Skip to main content
If your service sells regulated goods, handles PII, or needs to know who’s paying; AgentScore gives you identity verification for the agents and operators interacting with your API.
Want a step-by-step tutorial using Martin Estate’s wine commerce API as the worked example? See the Agentic Commerce Quickstart; it walks through the AgentScore Gate middleware pattern end-to-end.

How it works

  1. An agent requests a purchase or action from your service
  2. Your service calls AgentScore to verify the operator’s identity
  3. AgentScore returns allow or deny based on your compliance policy
  4. If denied, the operator can self-serve verify via a URL you provide
You define the policy. AgentScore enforces it.

Define your compliance policy

A policy specifies what identity checks the operator must pass:

Check identity at transaction time

When an agent sends a request to your service, extract the identity from the headers and call POST /v1/assess:
Or use AgentScore Gate middleware for automatic enforcement:

Per-product policy + soft mode (commerce SDK)

The single-gate setup above attaches one policy to a route. Multi-product merchants where each item has different compliance needs (regulated wine ⨉ free-to-everyone merch ⨉ high-value print that wants KYC as a fraud signal but won’t block the sale) want the policy per product, not per route. Both agentscore-commerce (Python) and @agent-score/commerce (Node) ship parallel helpers for this. Field names follow each language’s convention (snake_case in Python, camelCase in Node) but the shape is identical. Python (agentscore_commerce.identity.policy):
  • PolicyBlock: typed shape carrying enforcement (hard | soft | absent), require_kyc, require_sanctions_clear, min_age, allowed_jurisdictions, allowed_shipping_countries, allowed_shipping_states. Vendors usually source these from a database row (one column per field).
  • build_gate_from_policy(policy, *, api_key); translates a block into an AgentScoreGate. Returns None when the block has no enforcement set, signalling “no gate; identity_status=‘anonymous’”.
  • run_gate_with_enforcement(request, gate, *, enforcement); runs the gate. On hard denial it returns status="denied" with a denial_status and denial_body for the caller to propagate. On soft denial it swallows the 403 and returns status="unverified" so the order completes with a degraded identity stamp. On success: status="verified". No gate: status="anonymous".
Node (@agent-score/commerce/identity/policy):
  • PolicyBlock: same fields in camelCase (enforcement, requireKyc, requireSanctionsClear, minAge, allowedJurisdictions, allowedShippingCountries, allowedShippingStates).
  • buildGateFromPolicy(policy, { apiKey }): translates a block into the options object the per-framework agentscoreGate(...) accepts. The Node SDK builds gates per framework (Hono, Express, Fastify, Next.js, Web), so the policy module emits options rather than a constructed gate, mirroring python’s build_gate_from_policy verb pattern. Returns null when no enforcement.
  • runGateWithEnforcement(enforcement, runGate): wraps the per-framework middleware in the hard/soft enforcement runner. The vendor passes a runGate adapter that resolves to { ok: true } on accept or { ok: false, status, body } on deny; the runner returns a structured GateResult.
In both languages, also:
  • shipping{Country,State}Allowed(...): per-product shipping allowlists. Country list is hard-enforced regardless of identity strictness; state list only fires for US shipments (e.g. wine).
Three modes per product: Persist identity_status on each order row (verified | unverified | anonymous) so ops/analytics can distinguish soft passes from hard passes from anonymous sales. A typical multi-product setup mixes enforcement modes; e.g. a regulated wine SKU with enforcement="hard" (KYC + 21 + US-only state allowlist) alongside unregulated merch (tee, sticker pack) with no policy. Single-file runnable examples: per_product_policy_merchant.py (Python) and per-product-policy-merchant.ts (Node).

Handle unverified operators

When an operator isn’t verified, the assess response includes a verify_url. Return it to the agent so the operator can self-serve:
The agent should tell the operator: “Identity verification is required. Visit [verify_url] to get verified.” For a smoother flow, create a verification session before returning the deny. This lets the agent poll for the result instead of requiring the operator to copy-paste credentials:
After the operator verifies, the agent polls and receives an operator_token. It retries the request; this time assess returns allow. The user closes the AgentScore tab; the agent finishes the transaction in the background.

What’s checked

AgentScore Gate denial codes

When AgentScore Gate rejects a request before hitting /v1/assess, the 403 body uses one of the codes below. Every code carries a structured agent_instructions payload (JSON-encoded {action, steps, user_message}) so agents can recover deterministically from the response alone; no discovery-doc round trip required.

Wallet-mode response fields

When identity_mode: "wallet", 402 and 403 bodies also include these fields so agents know exactly which address must sign:

Fail-open behavior (opt-in)

By default AgentScore Gate fails closed: any AgentScore-side infrastructure failure (HTTP 429, 5xx, network timeout) returns 503 to the buyer. This is the correct posture for regulated commerce; better to outage than to ship to a sanctioned wallet because our API blipped. Some merchants (low-stakes commerce, high-uptime SLAs) prefer graceful degradation. Set failOpen: true (Node) / fail_open=True (Python) to opt in. When opted in AND the failure is infra-shape, the buyer passes through and the gate state carries a degraded flag merchants can log/alert on:
infraReason / infra_reason is one of: failOpen does NOT bypass compliance denials. sanctions_flagged, age_insufficient, jurisdiction_restricted, wallet_signer_mismatch, kyc_required and other real policy outcomes still return 403 regardless of the flag. failOpen only covers “we couldn’t reach AgentScore to ask,” never “AgentScore said no but we’ll allow anyway.” For Web Fetch / Next.js (createAgentScoreGate / withAgentScoreGate), the degraded + infraReason fields land directly on the GuardResult.allowed variant / handler’s gate parameter; no separate getter needed.

Recommendations by vertical

What sellers see

Sellers receive binary decisions; allow or deny. You never see the operator’s name, address, date of birth, or ID documents. The only data exposed:
  • Verification level (none / claimed / verified)
  • Whether each policy check passed or failed

Privacy

  • AgentScore does not store ID documents; they are processed by Stripe Identity and never leave Stripe
  • We store derived facts only: verification status, jurisdiction (country code), age bracket, sanctions status
  • If our database is breached, attackers see “operator X is verified, US, individual”; no identity data

Sandbox testing

Use test: true with reserved test addresses to simulate compliance scenarios:

Pricing

See pricing for plans, quotas, and which tier includes compliance gating.

Next steps

POST /v1/assess

Full assess endpoint reference.

Sessions

Create verification sessions for agent polling.

Credentials

Create and manage operator credentials.

AgentScore Passport

How operators verify their identity.