Skip to main content
@agent-score/commerce is the full merchant-side SDK for agentic commerce. One install bundles identity gating, payment-protocol helpers, 402 challenge builders, discovery doc generators, and Stripe multichain support. Subpath imports keep bundle size focused: identity-only consumers pay no cost for payment helpers, and vice versa.

Installation

Framework + integration packages are optional peer deps; install only what you use:

Subpaths

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. createSessionOnMissing 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 onDenied, so merchants only handle one code. When the merchant omits createSessionOnMissing from the gate config, Checkout auto-defaults it from gate.apiKey + gate.baseUrl + gate.context + gate.merchantName; every gated route gets the bootstrap UX out of the box; merchants that need per-request session context or onBeforeSession side effects (goods merchants pre-minting an order_id) supply their own config to override. buildVerificationRequiredBody(reason, opts?) collapses the per-merchant body-mapping boilerplate into one call (status: 403, body: buildVerificationRequiredBody(reason, { message, agentInstructions, extra })). The gate middleware extracts the payment signer pre-evaluate (extractPaymentSigner(req, x402Header) covers MPP did:pkh:eip155 + Solana did:pkh:solana + Solana TransferChecked authority fallback + x402 EIP-3009) 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 getSignerVerdict(ctx) (or the gate.getSignerVerdict() accessor on the wrapper adapters) 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. captureWallet 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 object; 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 build402Body + buildPaymentHeaders + 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. Sign + verify via the optional jose peer dep (install via bun add jose):
Verifiers reconstruct the canonical body (everything except signature, keys sorted at every level), look up the kid in JWKS, and check the JWS. verifyUCPProfile(signed, jwks) does this for you. It 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 throw UCPVerificationError with a discriminated code field. Both EdDSA (Ed25519) and ES256 are supported. EdDSA is the default and recommended. signUCPProfile rejects profiles containing non-integer Number values: cross-language float canonicalization is not stable, so use decimal strings (e.g. "9.99") for any monetary or fractional fields you put in extras. Persisting the private JWK. Mint once via generateUCPSigningKey(), export with jose.exportJWK(privateKey), store in your secret manager. On each container start, read the secret, jose.importJWK(jwk, alg) to re-hydrate. KMS-backed flows require an adapter that exposes a KeyLike jose can call; jose does not natively wrap KMS endpoints. See examples/signed-ucp-merchant.ts for the runtime-independent re-hydrate pattern. 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.

Quick start: full merchant via the Checkout orchestrator

Checkout is the canonical merchant surface in 2.0 for fixed-price one-shot endpoints; 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. For variable-cost pay-per-result endpoints (per-result search, per-token LLM, per-byte transcoding), reach for computeFirstCheckout; same config shape, but the probe leg runs the work, caches the result by content-hash of the request body, and emits a 402 with the EXACT computed price. The retry pays that exact amount and the merchant returns the cached body. Works on every exact-mode rail (x402-exact Base, tempo/charge, solana/charge, Stripe SPT) without upto / Permit2 / Settlement-Overrides. Tradeoff: the work runs on the unpaid probe leg, so mount rateLimitHono (@agent-score/commerce/middleware/hono) globally; it’s load-bearing.
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 @agent-score/commerce/stripe-multichain, pass staticRecipients: { 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. See the compute-first merchant example for the canonical variable-cost pattern via computeFirstCheckout.

Fail-open (opt-in)

By default AgentScore Gate fails closed on AgentScore-side infra failure (429 / 5xx / network timeout); buyer gets 503. Pass failOpen: true to opt in to graceful degradation, then read the per-request degraded state via getGateDegradedState(c):
getGateDegradedState is exported by every Node adapter (Hono, Express, Fastify). For withAgentScoreGate (Next.js / Web Fetch), the degraded + infraReason fields land on the gate object passed to your handler. Compliance denials (sanctions, age, jurisdiction, signer-mismatch) still deny regardless of failOpen; see compliance-gating › Fail-open behavior.

Examples

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