Skip to main content
agentscore-commerce is the full merchant-side SDK for agentic commerce in Python. One install bundles identity gating, payment-protocol helpers, 402 challenge builders, discovery doc generators, and Stripe multichain support. Submodule imports keep dependencies focused.

Installation

Accept x402 payments through the Coinbase facilitator (mints per-endpoint CDP JWTs via cdp-sdk):
The [mppx] extra adds Tempo MPP + Stripe SPT helpers.

Build the x402 accepts entry for a 402 challenge

Returns a list of plain dicts ready for the 402 body’s accepts[]. extra.name is derived from the registered scheme metadata so the EIP-712 domain matches the on-chain USDC contract.

Submodules

Identity model

Two identity types: wallet (X-Wallet-Address) and operator-token (X-Operator-Token). Default checks operator-token first, then wallet. Address normalization is network-aware: EVM lowercased, Solana base58 preserved verbatim. DenialReason codes (missing_identity, identity_verification_required, token_expired, invalid_credential, wallet_signer_mismatch, wallet_auth_requires_wallet_signing, wallet_not_trusted, api_error, payment_required) each carry a structured agent_instructions JSON block describing concrete recovery actions. create_session_on_missing auto-mints a verification session for two paths: cold-start (no identity headers) AND wallet_not_trusted with fixable reasons (kyc_required / kyc_pending / kyc_failed). Both paths rewrite the denial to identity_verification_required before reaching on_denied, so merchants only handle one code. When the merchant omits create_session_on_missing from the gate config, Checkout auto-defaults it from gate.api_key + gate.base_url + gate.context + gate.merchant_name; merchants that need on_before_session side effects (e.g. pre-minting an order_id) supply their own config to override. build_verification_required_body(reason, message=?, agent_instructions=?, extra=?) collapses the per-merchant body-mapping boilerplate. The gate middleware extracts the payment signer pre-evaluate (extract_payment_signer(x402_header)) and passes signer={address, network} to /v1/assess; one round trip now carries the gate verdict AND the wallet-signer-match outcome AND the signer_sanctions OFAC SDN wallet-address verdict. Merchants read both back synchronously via get_signer_verdict(request) off the gate’s cache (no extra HTTP call). Wallet-OFAC SDN enforcement is unconditional whenever the signer is supplied; an SDN hit OR an unavailable wallet-sanctions lookup flips the gate decision to deny before the handler runs (fail-closed; OFAC strict-liability), without requiring policy.require_sanctions_clear to opt in. policy.require_sanctions_clear is the separate NAME-based screen on the operator’s KYC identity. capture_wallet is fire-and-forget; POSTs the signer to /v1/credentials/wallets so the operator’s cross-merchant credential↔wallet profile builds up over time.

Identity publishing (cross-vendor standards)

Two helpers compose AgentScore identity into the payload formats published to other agent-commerce ecosystems. Each returns an unsigned dataclass; your service signs + serves it however its key infrastructure works.
Note: ACP (Stripe + OpenAI Agentic Commerce Protocol) is a transactional checkout protocol. Not an identity-publishing surface. ACP merchants integrate through the existing build_402_body + build_payment_headers + Stripe SPT rail.

Signing UCP profiles (vendor extension; opt-in for trust-mode verifiers)

UCP §6 doesn’t mandate profile-body JWS signing; production UCP merchants commonly ship unsigned. AgentScore’s agentscore-profile+jws is a vendor extension layered on top of the unsigned UCP profile for trust-mode verifiers (regulated-commerce, AP2-aware) that opt into auditable cryptographic provenance. Vanilla UCP agents read the canonical body and ignore the signature field. agentscore-commerce ships four helpers that ride on the joserfc optional dep (pip install agentscore-commerce[ucp]):
verify_ucp_profile enforces the JWS protected header typ='agentscore-profile+jws' (vendor-namespaced; UCP §6 doesn’t define a profile-as-JWS typ), restricts alg to EdDSA/ES256, requires a kid, rejects duplicate kids, and compares canonical body bytes against the JWS payload. Failures raise UCPVerificationError with a discriminated code attribute. sign_ucp_profile rejects profiles containing float values: cross-language float canonicalization is not stable. Use decimal strings (e.g. "9.99") for monetary or fractional fields in extras. Persisting the private JWK. Mint once via generate_ucp_signing_key(), serialize via key.private_key.as_dict(private=True), store in your secret manager. On each container start, read the secret, OKPKey.import_key(jwk_dict) (or ECKey.import_key for ES256) to re-hydrate. KMS-backed flows require subclassing the joserfc Key to delegate the sign hook. Key rotation. Mint a new key with a new kid, add the public JWK to your JWKS endpoint alongside the old one, then sign new profiles with the new key. Drop the old JWK after your verifier-side cache TTL has elapsed. Inline JWK in the profile vs separate JWKS endpoint. UCP §6 mandates the separate /.well-known/jwks.json endpoint as the canonical trust source. The profile’s signing_keys[] is informational; verifiers MUST resolve the kid against the JWKS to prevent a swap-after-sign attack. Verifiers reconstruct the canonical body (everything except signature, keys sorted at every level), look up the kid in JWKS, and check the JWS. verify_ucp_profile(signed, jwks) does this for you. Both EdDSA (Ed25519) and ES256 are supported. EdDSA is the default and recommended. Profiles signed by Node verify in Python and vice versa: cross-language byte-identical canonicalization.

Quick start: full merchant via the Checkout orchestrator

Checkout is the canonical merchant surface in 2.0; one config object, hooks for the merchant-specific pieces, and the SDK handles 402 emit, identity gating, x402 verify+settle, mppx compose, $0 carve-out, identity_metadata auto-attach, and the per-framework adapter. Most merchants reach for Checkout first and only drop to lower-level helpers when they need custom flows (variable-cost streaming, multi-protocol composition).
Solana MPP requires a static recipient with a pre-funded token account. Point the Solana rail at a fixed wallet you control (as with SOLANA_RECIPIENT above) and pre-fund that wallet’s USDC associated token account (ATA) once. Per-order rotating Solana deposit addresses (for example Stripe-multichain minted addresses) do not settle on Solana MPP, because the settlement transaction does not create the recipient’s token account. Tempo and x402 (Base) settle fine to per-order recipients; only Solana needs the static, pre-funded wallet. When you mint per-order recipients via agentscore_commerce.stripe_multichain, pass static_recipients={"solana": "<wallet>"} so Solana is served from your fixed wallet, or leave Solana out of the rail set.
The 402 body Checkout emits auto-attaches identity_mode + required_signer + signer_constraint (and linked_wallets when the gate populated them) when an inbound X-Wallet-Address header is present; so agents self-correct at discovery instead of at the 403 retry.

Fail-open (opt-in)

By default AgentScore Gate fails closed on AgentScore-side infra failure (429 / 5xx / network timeout); buyer gets 503. Pass fail_open=True to opt in to graceful degradation, then read the per-request degraded state via get_gate_degraded_state(request):
get_gate_degraded_state is exported by every Python adapter (FastAPI, Flask, Django, AIOHTTP, Sanic, ASGI middleware) and reads the framework-appropriate request state. Signatures take a request argument on every adapter except Flask, which reads from g and takes no arguments (get_gate_degraded_state()). Compliance denials (sanctions, age, jurisdiction, signer-mismatch) still deny regardless of fail_open; see compliance-gating › Fail-open behavior.

Examples

The examples/ directory has runnable single-file FastAPI apps for each common merchant scenario: