Skip to main content

Python SDK for Self Agent ID — proof-of-human verification for AI agents

Project description

selfxyz-agent-sdk

Python SDK for Self Agent ID — on-chain AI agent identity with proof-of-human verification.

Sign requests in Python, verify in TypeScript or Rust, or vice versa. The signing protocol is language-agnostic — all SDKs produce identical signatures.

Install

pip install selfxyz-agent-sdk

Agent Side — Sign Requests

from self_agent_sdk import SelfAgent

agent = SelfAgent(private_key="0x...", network="mainnet")

# Sign a request (returns dict of auth headers)
headers = agent.sign_request("POST", "https://api.example.com/data",
                             body='{"query": "test"}')

# Or use the built-in HTTP client
response = agent.fetch("https://api.example.com/data",
                       method="POST", body='{"query": "test"}')

# Check registration status
print(agent.is_registered())  # True/False
print(agent.get_info())       # AgentInfo(agent_id=5, is_verified=True, ...)

Credentials

# Fetch ZK-attested credentials (nationality, age, OFAC, etc.)
creds = agent.get_credentials()
# AgentCredentials(issuing_state="GBR", nationality="GBR", older_than=18, ofac=[True], ...)

strength = agent.get_verification_strength()
# 0 = unverified, 1 = basic, 2 = standard, 3 = enhanced

Service Side — Verify Requests

from self_agent_sdk import SelfAgentVerifier

verifier = SelfAgentVerifier()  # mainnet by default

result = verifier.verify(
    signature=request.headers["x-self-agent-signature"],
    timestamp=request.headers["x-self-agent-timestamp"],
    method=request.method,
    url=request.path,
    body=request.get_data(as_text=True),
)

if result.valid:
    print(f"Verified agent: {result.agent_address}")

VerifierBuilder

Chainable API for configuring verification requirements:

from self_agent_sdk import VerifierBuilder

verifier = (
    VerifierBuilder()
    .network("mainnet")
    .require_age(18)
    .require_ofac()
    .require_nationality("US", "GB", "DE")
    .require_self_provider()
    .sybil_limit(1)
    .rate_limit(per_minute=60, per_hour=1000)
    .replay_protection()
    .include_credentials()
    .max_age(300_000)     # 5 min timestamp window
    .cache_ttl(60_000)    # 1 min cache
    .build()
)

Static Factory

# From a flat config dict (useful for env-driven config)
verifier = SelfAgentVerifier.from_config({
    "network": "mainnet",
    "require_age": 18,
    "require_ofac": True,
    "sybil_limit": 1,
})

Flask Middleware

from flask import Flask, g, jsonify
from self_agent_sdk import SelfAgentVerifier
from self_agent_sdk.middleware.flask import require_agent

app = Flask(__name__)
verifier = SelfAgentVerifier()

@app.route("/api/data", methods=["POST"])
@require_agent(verifier)
def handle():
    print(g.agent.agent_address)
    return jsonify(ok=True)

FastAPI Dependency

from fastapi import FastAPI, Depends
from self_agent_sdk import SelfAgentVerifier
from self_agent_sdk.middleware.fastapi import AgentAuth
from self_agent_sdk.types import VerificationResult

app = FastAPI()
verifier = SelfAgentVerifier()
auth = AgentAuth(verifier)

@app.post("/api/data")
async def handle(agent: VerificationResult = Depends(auth)):
    print(agent.agent_address)
    return {"ok": True}

Proof Expiry & Refresh

Human proofs expire after maxProofAge (default: 365 days) or at passport document expiry, whichever is sooner. The expiry timestamp is set on-chain at registration.

# Check proof freshness
info = agent.get_info()
print(info.proof_expires_at)  # unix seconds, 0 if unregistered

# Check if expiring within 30 days
import time
THIRTY_DAYS = 30 * 24 * 60 * 60
if info.proof_expires_at > 0 and info.proof_expires_at - time.time() < THIRTY_DAYS:
    print("Proof expiring soon — prompt human to re-verify")

Verifier-side: The verifier returns reason="PROOF_EXPIRED" when an agent's proof has lapsed.

Refreshing: There is no in-place refresh. Deregister (burn NFT) → re-register (new passport scan, new agentId, fresh expiry):

agent.request_deregistration()  # human confirms via Self app
# ... after completion:
session = agent.request_registration(minimum_age=18, ofac=True)

A2A Agent Card

Publish machine-readable identity metadata for agent-to-agent discovery:

# Read the on-chain agent card
card = agent.get_agent_card()
# A2AAgentCard(name="My Agent", self_protocol=SelfProtocolExtension(...))

# Set or update the agent card (writes on-chain, returns tx hash)
tx_hash = agent.set_agent_card(
    name="My Agent",
    description="An AI assistant with verified identity",
    url="https://myagent.example.com",
    skills=[AgentSkill(name="search", description="Web search")],
)

# Generate a data URI for embedding
data_uri = agent.to_agent_card_data_uri()

Registration Helpers

Build the userDefinedData strings that Self Protocol expects during registration:

from self_agent_sdk import (
    get_registration_config_index,
    compute_registration_challenge_hash,
    sign_registration_challenge,
    build_simple_register_user_data_ascii,
    build_simple_deregister_user_data_ascii,
    build_advanced_register_user_data_ascii,
    build_advanced_deregister_user_data_ascii,
    build_wallet_free_register_user_data_ascii,
)

# Config index maps disclosure flags to one of 6 on-chain configs
get_registration_config_index({"minimumAge": 18, "ofac": True})  # 4

# Simple mode (self-custody) — human IS the agent
build_simple_register_user_data_ascii({"minimumAge": 18})   # "R1"
build_simple_deregister_user_data_ascii({"minimumAge": 18})  # "D1"

# Advanced mode (linked) — agent has own keypair
signed = sign_registration_challenge(
    private_key="0xagentPrivKey",
    human_identifier="0xhumanAddr",
    chain_id=11142220,
    registry_address="0x29d94...",
)

build_advanced_register_user_data_ascii(
    agent_address=signed.agent_address,
    signature_r=signed.r,
    signature_s=signed.s,
    signature_v=signed.v,
    disclosures={"minimumAge": 18, "ofac": True},
)  # "K4{addr}{r}{s}{v}"

# Deregistration
build_advanced_deregister_user_data_ascii("0xagent")  # "X0{addr}"

# Wallet-free mode — agent acts as guardian
build_wallet_free_register_user_data_ascii(
    agent_address="0xagent",
    signature_r=signed.r,
    signature_s=signed.s,
    signature_v=signed.v,
    guardian_address="0xguardian",
    disclosures={"minimumAge": 18},
)  # "W1{agent}{guardian}{r}{s}{v}"

REST Registration API

Programmatic registration without the CLI:

Set SELF_AGENT_API_BASE to override the default hosted API base.

from self_agent_sdk import SelfAgent

# Start a registration session
session = SelfAgent.request_registration(
    mode="linked",
    network="mainnet",
    disclosures={"minimumAge": 18, "ofac": True},
    agent_name="My Agent",
)

print(session.deep_link)            # URL for the human to open
print(session.human_instructions)   # Steps for the human

# Wait for completion (polls on-chain)
result = session.wait_for_completion(timeout_ms=300_000)
print(result.agent_id)        # On-chain agent ID
print(result.agent_address)   # Agent's address

# Export the generated private key
private_key = session.export_key()

# Deregister
dereg_session = agent.request_deregistration()
dereg_session.wait_for_completion()

CLI

Interactive registration via the command line:

# Register an agent (linked mode)
self-agent register init --mode linked --human-address 0x... --network testnet
self-agent register open --session .self/session.json
self-agent register wait --session .self/session.json

# Deregister
self-agent deregister init --mode linked --human-address 0x... --agent-address 0x... --network testnet
self-agent deregister open --session .self/session.json
self-agent deregister wait --session .self/session.json

# Export private key (requires --unsafe flag)
self-agent register export --session .self/session.json --unsafe --print-private-key

Registration modes:

Mode Description userDefinedData
self-custody Human address = agent address R{cfg}
linked Agent has own keypair, signed challenge K{cfg}{addr}{r}{s}{v}
wallet-free Agent as guardian, no human wallet needed W{cfg}{addr}{guardian}{r}{s}{v}
ed25519 Ed25519 wallet-free agent W{cfg}{addr}{guardian}{r}{s}{v}
ed25519-linked Ed25519 agent linked to human wallet K{cfg}{addr}{r}{s}{v}
smartwallet ZeroDev Kernel + passkeys Smart wallet template

Configuration

# Testnet
agent = SelfAgent(private_key="0x...", network="testnet")
verifier = SelfAgentVerifier(network="testnet")

# Custom overrides
verifier = SelfAgentVerifier(
    registry_address="0x...",      # Custom registry
    rpc_url="https://...",         # Custom RPC
    max_agents_per_human=5,        # Sybil cap (0 = disabled)
    require_self_provider=True,    # Verify proof provider (default)
    include_credentials=True,      # Fetch ZK-attested credentials
)

Security Chain

The verifier implements an 11-step security chain:

  1. Timestamp freshness — reject stale requests (default: 5 min window)
  2. Signature recovery — derive agent address from ECDSA signature
  3. Agent key derivationzeroPad(address, 32) for on-chain lookup
  4. On-chain verificationisVerifiedAgent(agentKey) confirms human backing
  5. Provider check — ensures proof came from Self Protocol, not a third party
  6. Sybil resistance — limits agents per human (default: 1)
  7. Replay protection — reject duplicate (signature, timestamp) pairs
  8. Credential validation — verify ZK-attested credentials if configured
  9. Age verification — enforce minimum age from passport proof
  10. OFAC screening — verify agent passed sanctions screening
  11. Rate limiting — per-agent request throttling

Cross-Language Compatibility

This SDK is 100% compatible with the TypeScript SDK (@selfxyz/agent-sdk) and Rust SDK (self-agent-sdk). All three produce byte-identical signatures and userDefinedData payloads for the same inputs. Test vectors generated from TypeScript are verified byte-for-byte in the Python test suite.

Run Tests

From python-sdk/:

./scripts/test.sh

Manual setup (equivalent):

python3 -m venv .venv
. .venv/bin/activate
pip install -e ".[test]"
pytest -q

Networks

Network Registry Chain ID
Mainnet (Celo) 0xaC3DF9ABf80d0F5c020C06B04Cced27763355944 42220
Testnet (Celo Sepolia) 0x043DaCac8b0771DD5b444bCC88f2f8BBDBEdd379 11142220

License

Business Source License 1.1 (BUSL-1.1). See ../LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

selfxyz_agent_sdk-0.2.1.tar.gz (57.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

selfxyz_agent_sdk-0.2.1-py3-none-any.whl (51.0 kB view details)

Uploaded Python 3

File details

Details for the file selfxyz_agent_sdk-0.2.1.tar.gz.

File metadata

  • Download URL: selfxyz_agent_sdk-0.2.1.tar.gz
  • Upload date:
  • Size: 57.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for selfxyz_agent_sdk-0.2.1.tar.gz
Algorithm Hash digest
SHA256 b07d656d55fa465dc6bd5531cfe5efd6ea5564b3d68b679bd6b0f374d14dbb94
MD5 f7a2d24dfe34731ce393f59a96f74840
BLAKE2b-256 785b22b347fcc2957c8f6accfa48e36c76522e4e4bf619b8537d555da605c83f

See more details on using hashes here.

File details

Details for the file selfxyz_agent_sdk-0.2.1-py3-none-any.whl.

File metadata

File hashes

Hashes for selfxyz_agent_sdk-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 08bebcfe8dd1b3bf5483da76b86b3d47fe9cafcd2d633aadf7eff6e6573f0310
MD5 a504d25b73ebcdf2e74702b6d4ab4096
BLAKE2b-256 3bd7f8b8b1ccf33e69178dba11d1653127dc7d870b6b3ec2c52f5d7ee069b6b1

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page