Verifiable trust for the agent economy.
Portable W3C Verifiable Credentials for AI agents. Your agent receives a credential from the AgentMarque registry, presents it to services with selective disclosure and holder binding, and services verify both signatures.
pip install agentmarqueRequires Python 3.12+.
from agentmarque import AgentCredential, AgentMarqueVerifier, AgentHandshake
# 1. Load a credential (received from the AgentMarque registry)
credential = AgentCredential.from_json(stored_credential_json)
# 2. Present with selective disclosure + holder binding
presentation = credential.present(
holder_key=my_private_key,
verifier_nonce="nonce-from-hotel",
audience="did:web:hotel-api.com",
disclose=["verificationTier", "reputationScore", "organization"],
)
# 3. Verify (service side)
verifier = AgentMarqueVerifier(trusted_issuers=["did:web:api.agentmarque.com"])
result = verifier.verify(
presentation=presentation,
expected_nonce="nonce-from-hotel",
expected_audience="did:web:hotel-api.com",
min_tier=2,
min_reputation=60.0,
)
# result.valid, result.claims["reputationScore"], result.checks.holder_bound
# 4. Handshake (structured challenge/response)
challenge = AgentHandshake.create_challenge(audience="did:web:hotel-api.com")
response = AgentHandshake.respond(challenge, credential, holder_key=my_private_key)
hs_result = AgentHandshake.verify_response(response, challenge, verifier)Two keys, two signatures. The credential is signed by the issuer (AgentMarque). The presentation is signed by the holder (your agent). Verifiers check both:
- Issuer signature — is the credential from a trusted issuer?
- Holder binding (KB-JWT) — does the presenter control the key in the credential's
cnfclaim?
This prevents replay and impersonation. Without holder binding, a stolen credential is a bearer token. With it, the credential is worthless without the agent's private key.
- Portable — any W3C VC verifier can check an AgentMarque credential
- Selective disclosure — prove "tier 2, reputation 87+" without revealing your full identity
- Offline verification — no network calls required (except optional revocation check)
- No vendor lock-in — verifiers don't need our SDK
Agents store credentials as a JSON bundle containing both the W3C VC and the pre-signed SD-JWT. This is what to_json() / from_json() serialize:
{
"vc": {
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://agentmarque.com/ns/agent/v1"
],
"type": ["VerifiableCredential", "AgentMarqueCredential"],
"issuer": "did:web:api.agentmarque.com",
"validFrom": "2026-04-02T00:00:00Z",
"validUntil": "2026-07-01T00:00:00Z",
"credentialSubject": {
"id": "did:key:z6MkAgent...",
"type": "AIAgent",
"agentName": "translate-agent",
"organization": { "id": "https://acme.co", "name": "Acme Corp" },
"capabilities": ["translate", "detect_language"],
"verificationTier": 2,
"reputationScore": 87.5,
"settlement": { "methods": ["x402"], "x402_address": "0xabc..." }
},
"cnf": { "jwk": { "kty": "OKP", "crv": "Ed25519", "x": "..." } },
"proof": {
"type": "DataIntegrityProof",
"cryptosuite": "eddsa-jcs-2022",
"...": "..."
}
},
"sd_jwt": "<issuer-signed-jwt>~<disclosure1>~<disclosure2>~..."
}The vc field is the full W3C VC with Data Integrity proof. The sd_jwt field is the pre-signed SD-JWT with all disclosures — the agent selects which to reveal at presentation time.
AgentMarqueVerifier.verify() checks in order:
- Issuer signature on SD-JWT
- cnf claim present and well-formed
- Holder binding (KB-JWT signed by the holder's key, matching cnf)
- Nonce match
- Audience match
- Dates (nbf / exp)
- Revocation status (fail closed if unreachable)
- Policy (min tier, min reputation, required capabilities)
A separate verify_vc() method is available for checking raw VC dicts (issuer signature only — no holder proof).
For local development or running your own registry:
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from agentmarque.issuer import issue_credential
from agentmarque.crypto import public_key_to_did_key
issuer_key = Ed25519PrivateKey.generate()
agent_key = Ed25519PrivateKey.generate()
credential = issue_credential(
issuer_key=issuer_key,
subject_did=public_key_to_did_key(agent_key.public_key()),
subject_key=agent_key.public_key(),
agent_name="my-agent",
organization={"id": "https://acme.co", "name": "Acme Corp"},
capabilities=["translate"],
verification_tier=2,
reputation_score=87.5,
)
# Now use credential.present(holder_key=agent_key, ...) as normal- W3C Verifiable Credentials Data Model 2.0
- W3C Data Integrity (eddsa-jcs-2022)
- W3C BitstringStatusList
- IETF SD-JWT with Key Binding JWT
- did:key and did:web DID methods
- JSON Canonicalization Scheme (RFC 8785)
Full documentation at docs.agentmarque.com.
MIT