Official Python SDK for Tether.name - AI agent identity verification
Project description
Tether.name Python SDK
Official Python SDK for Tether.name โ cryptographic identity verification for AI agents.
Tether lets AI agents prove their identity using RSA-2048 digital signatures, providing a secure, verifiable way to establish trust in AI-to-AI and AI-to-human interactions.
๐ Quick Start
Installation
pip install tether-name
Basic Usage
from tether_name import TetherClient
# Initialize with your credentials
client = TetherClient(
credential_id="your-credential-id",
private_key_path="/path/to/your/private-key.der"
)
# Verify your agent's identity
result = client.verify()
if result.verified:
print(f"โ
Verified as: {result.agent_name}")
print(f"๐ง Email: {result.email}")
print(f"๐ Verification URL: {result.verify_url}")
else:
print(f"โ Verification failed: {result.error}")
Agent Management
One line to start managing agents programmatically:
from tether_name import TetherClient
client = TetherClient(api_key="sk-tether-name-...")
# Create, list, and delete agents
agent = client.create_agent("my-bot")
agents = client.list_agents()
client.delete_agent(agent.id)
๐ How Tether Works
Tether.name provides cryptographic identity verification for AI agents through a simple 3-step process:
- Register: Create an agent identity at tether.name and get your credential ID and RSA-2048 private key
- Sign: Your agent signs a cryptographic challenge using its private key
- Verify: The signature proves your agent's identity to others
This creates unforgeable digital identity that anyone can verify.
๐ง Configuration
Authentication
The SDK supports two authentication modes:
API Key โ for agent management (create, list, delete):
client = TetherClient(api_key="sk-tether-name-...")
Private Key โ for identity verification (sign, verify):
client = TetherClient(
credential_id="your-credential-id",
private_key_path="/path/to/key.der"
)
Both โ for full access:
client = TetherClient(
api_key="sk-tether-name-...",
credential_id="your-credential-id",
private_key_path="/path/to/key.der"
)
Environment Variables
Set these environment variables to avoid hardcoding credentials:
export TETHER_API_KEY="sk-tether-name-..."
export TETHER_CREDENTIAL_ID="your-credential-id"
export TETHER_PRIVATE_KEY_PATH="/path/to/your/key.der"
Then initialize without parameters:
client = TetherClient() # Uses environment variables
Key Formats
The SDK supports multiple private key formats:
# From file path (PEM or DER)
client = TetherClient(
credential_id="...",
private_key_path="/path/to/key.der"
)
# From PEM string
client = TetherClient(
credential_id="...",
private_key_pem="-----BEGIN PRIVATE KEY-----\n..."
)
# From DER bytes
with open("key.der", "rb") as f:
key_bytes = f.read()
client = TetherClient(
credential_id="...",
private_key_der=key_bytes
)
๐ API Reference
TetherClient
Main client for Tether.name API interactions.
Constructor
TetherClient(
credential_id: Optional[str] = None,
private_key_path: Optional[Union[str, Path]] = None,
private_key_pem: Optional[Union[str, bytes]] = None,
private_key_der: Optional[bytes] = None,
timeout: float = 30.0,
api_key: Optional[str] = None
)
| Parameter | Env var | Description |
|---|---|---|
api_key |
TETHER_API_KEY |
API key for agent management operations |
credential_id |
TETHER_CREDENTIAL_ID |
Credential ID for identity verification |
private_key_path |
TETHER_PRIVATE_KEY_PATH |
Path to RSA-2048 private key (PEM or DER) |
private_key_pem |
โ | PEM-encoded private key string |
private_key_der |
โ | DER-encoded private key bytes |
When api_key is set, credential_id and private key parameters become optional (only needed for verify/sign operations).
Methods
verify() -> VerificationResult
Perform complete identity verification in one call.
result = client.verify()
print(result.verified) # bool: True if verified
print(result.agent_name) # str: Your agent's display name
print(result.verify_url) # str: Public verification URL
print(result.email) # str: Registered email address
request_challenge() -> str
Request a cryptographic challenge from Tether.
challenge = client.request_challenge()
print(challenge) # "550e8400-e29b-41d4-a716-446655440000"
sign(challenge: str) -> str
Sign a challenge with your private key.
challenge = client.request_challenge()
signature = client.sign(challenge)
print(signature) # URL-safe base64 signature (no padding)
submit_proof(challenge: str, proof: str) -> VerificationResult
Submit signed challenge for verification.
challenge = client.request_challenge()
signature = client.sign(challenge)
result = client.submit_proof(challenge, signature)
create_agent(agent_name: str, description: str = "") -> Agent
Create a new agent. Requires API key authentication.
agent = client.create_agent("my-bot", description="My automated agent")
print(agent.id) # Agent ID
print(agent.agent_name) # "my-bot"
print(agent.registration_token) # Token for agent registration
list_agents() -> list[Agent]
List all agents. Requires API key authentication.
agents = client.list_agents()
for agent in agents:
print(f"{agent.agent_name} (created {agent.created_at})")
delete_agent(agent_id: str) -> bool
Delete an agent. Requires API key authentication.
client.delete_agent("agent-id-here")
Agent
Agent object returned by management operations.
@dataclass
class Agent:
id: str # Unique agent ID
agent_name: str # Agent display name
description: str # Agent description
created_at: int # Creation time (epoch ms)
registration_token: str = "" # Token for agent registration
last_verified_at: int = 0 # Last verification time (epoch ms)
VerificationResult
Result object returned by verification operations.
@dataclass
class VerificationResult:
verified: bool # True if verification succeeded
agent_name: Optional[str] = None # Agent's display name
verify_url: Optional[str] = None # Public verification URL
email: Optional[str] = None # Registered email
registered_since: Optional[datetime] = None # Registration date
error: Optional[str] = None # Error message if failed
challenge: Optional[str] = None # Original challenge
๐ Step-by-Step Example
For more control, you can break down the verification process:
from tether_name import TetherClient, TetherAPIError, TetherVerificationError
try:
client = TetherClient(
credential_id="your-credential-id",
private_key_path="/path/to/key.der"
)
# Step 1: Request a challenge
print("๐ก Requesting challenge...")
challenge = client.request_challenge()
print(f"๐ข Challenge: {challenge}")
# Step 2: Sign the challenge
print("โ๏ธ Signing challenge...")
signature = client.sign(challenge)
print(f"๐ Signature: {signature[:32]}...")
# Step 3: Submit proof
print("๐ค Submitting proof...")
result = client.submit_proof(challenge, signature)
if result.verified:
print(f"โ
Successfully verified as {result.agent_name}")
print(f"๐ Share this verification: {result.verify_url}")
else:
print(f"โ Verification failed: {result.error}")
except TetherAPIError as e:
print(f"๐ API Error: {e.message}")
if e.status_code:
print(f"๐ Status: {e.status_code}")
except TetherVerificationError as e:
print(f"๐ Verification Error: {e.message}")
finally:
client.close() # Clean up HTTP connections
๐งช Testing
The SDK includes comprehensive unit tests that don't hit the live API:
# Install development dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Run with coverage
pytest --cov=tether_name
๐ Context Manager Support
Use TetherClient as a context manager for automatic cleanup:
with TetherClient(credential_id="...", private_key_path="...") as client:
result = client.verify()
print(f"Verified: {result.verified}")
# HTTP client automatically closed
๐ก๏ธ Security Notes
- Private Key Security: Never commit private keys to version control or share them publicly
- API Key Security: API keys are hashed before storage. The
sk-tether-name-prefix enables leak detection. Revoke compromised keys immediately - Key Format: Tether requires RSA-2048 keys. Other key sizes will be rejected
- Challenge Uniqueness: Each verification uses a unique challenge to prevent replay attacks
- Signature Algorithm: Uses SHA256withRSA (PKCS#1 v1.5 padding) as specified by Tether
๐ Error Handling
The SDK provides specific exception types for different error conditions:
from tether_name import (
TetherError, # Base exception
TetherAPIError, # API request failures
TetherVerificationError, # Verification failures
TetherKeyError, # Private key issues
)
try:
result = client.verify()
except TetherAPIError as e:
# Handle API connectivity or server errors
print(f"API Error {e.status_code}: {e.message}")
except TetherVerificationError as e:
# Handle verification failures (invalid signature, etc.)
print(f"Verification failed: {e.message}")
except TetherKeyError as e:
# Handle private key loading or format errors
print(f"Key error: {e.message}")
except TetherError as e:
# Handle any other Tether-related errors
print(f"Tether error: {e.message}")
๐ Requirements
- Python: 3.8+
- Dependencies:
httpx>=0.20.0,cryptography>=3.4.0 - Key Format: RSA-2048 private key (PEM or DER)
๐ฆ Publishing
Published to PyPI automatically via GitHub Actions when a release is created (uses trusted publishing).
Version checklist
Update the version in:
pyproject.tomlโversionsrc/tether_name/__init__.pyโ__version__
Steps
- Update version numbers above (they must match)
- Commit and push to
main - Create a GitHub release with a matching tag (e.g.
v1.0.0) - CI builds and publishes to PyPI automatically
Manual publish (if needed)
pip install build twine
python -m build
twine upload dist/*
๐ License
MIT License - see LICENSE file for details.
๐ค Contributing
Contributions welcome! Please see the GitHub repository for details.
๐ Links
- ๐ Tether.name: https://tether.name
- ๐ฆ PyPI Package: https://pypi.org/project/tether-name/
- ๐ป Source Code: https://github.com/tether-name/tether-name-python
- ๐ API Documentation: https://docs.tether.name
- โ Support: jawnnypoo@gmail.com
Ready to get started? Register your AI agent at tether.name and start building with cryptographic identity verification! ๐
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tether_name-1.0.5.tar.gz.
File metadata
- Download URL: tether_name-1.0.5.tar.gz
- Upload date:
- Size: 13.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1f813c337a1a47853f2c7cdc9757ce42288d7c1f276095aab7a072e7b8f41a4d
|
|
| MD5 |
3ea55bcd201390210a205951307f310d
|
|
| BLAKE2b-256 |
2fb0cf8413d13b4897b38f4e2011da38149614b80459f2e2f31685d6d136059d
|
Provenance
The following attestation bundles were made for tether_name-1.0.5.tar.gz:
Publisher:
publish.yml on tether-name/tether-name-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tether_name-1.0.5.tar.gz -
Subject digest:
1f813c337a1a47853f2c7cdc9757ce42288d7c1f276095aab7a072e7b8f41a4d - Sigstore transparency entry: 1004776272
- Sigstore integration time:
-
Permalink:
tether-name/tether-name-python@042f5a8eb0f111eccb693f5322115f945edf9b74 -
Branch / Tag:
refs/tags/v1.0.5 - Owner: https://github.com/tether-name
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@042f5a8eb0f111eccb693f5322115f945edf9b74 -
Trigger Event:
push
-
Statement type:
File details
Details for the file tether_name-1.0.5-py3-none-any.whl.
File metadata
- Download URL: tether_name-1.0.5-py3-none-any.whl
- Upload date:
- Size: 12.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f0573ef1ff4647993a8de605852e17e39c225e31bb72c85c1177ed5232375ca0
|
|
| MD5 |
f65c08d62fe1068670924ede3579fa08
|
|
| BLAKE2b-256 |
f42a35741849763864f0fe28aa2621ccdfca0e631c4c4e70cb6f13d36ae8ab9b
|
Provenance
The following attestation bundles were made for tether_name-1.0.5-py3-none-any.whl:
Publisher:
publish.yml on tether-name/tether-name-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tether_name-1.0.5-py3-none-any.whl -
Subject digest:
f0573ef1ff4647993a8de605852e17e39c225e31bb72c85c1177ed5232375ca0 - Sigstore transparency entry: 1004776273
- Sigstore integration time:
-
Permalink:
tether-name/tether-name-python@042f5a8eb0f111eccb693f5322115f945edf9b74 -
Branch / Tag:
refs/tags/v1.0.5 - Owner: https://github.com/tether-name
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@042f5a8eb0f111eccb693f5322115f945edf9b74 -
Trigger Event:
push
-
Statement type: