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 Agent Commerce Quickstart — it walks through the 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:
{
  "require_kyc": true,
  "require_sanctions_clear": true,
  "min_age": 21,
  "allowed_jurisdictions": ["US"]
}
FieldTypeDescription
require_kycbooleanOperator must have completed identity verification
require_sanctions_clearbooleanOperator must not be on OFAC/sanctions lists
min_agenumberMinimum age (18 or 21)
blocked_jurisdictionsstring[]ISO country codes to block
allowed_jurisdictionsstring[]ISO country codes to allow (denies all others)

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:
import AgentScore from '@agent-score/sdk';

const agentscore = new AgentScore({ apiKey: process.env.AGENTSCORE_API_KEY });

const policy = {
  require_kyc: true,
  require_sanctions_clear: true,
  min_age: 21,
  allowed_jurisdictions: ['US'],
};

// In your request handler
const walletAddress = req.headers['x-wallet-address'];
const operatorToken = req.headers['x-operator-token'];

const result = walletAddress
  ? await agentscore.assess(walletAddress, { policy })
  : await agentscore.assess(null, { operatorToken, policy });

if (result.decision === 'deny') {
  return res.status(403).json({
    error: 'compliance_denied',
    reasons: result.decision_reasons,
    verify_url: result.verify_url,
  });
}

// Identity verified — proceed with transaction
Or use the gate middleware for automatic enforcement:
import { Hono } from 'hono';
import { agentscoreGate } from '@agent-score/gate/hono';

const app = new Hono();
app.use('*', agentscoreGate({
  apiKey: process.env.AGENTSCORE_API_KEY!,
  requireKyc: true,
  requireSanctionsClear: true,
  minAge: 21,
  allowedJurisdictions: ['US'],
}));

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:
{
  "decision": "deny",
  "decision_reasons": ["kyc_required"],
  "verify_url": "https://agentscore.sh/dashboard/verify?address=0x..."
}
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:
// No identity provided — create a verification session
const session = await agentscore.createSession({
  context: 'purchase',
  product_name: 'Premium API Access',
});

return res.status(403).json({
  error: 'identity_required',
  verify_url: session.verify_url,
  session_id: session.session_id,
  poll_secret: session.poll_secret,
  poll_url: session.poll_url,
  agent_instructions: {
    action: 'poll_for_credential',
    steps: [
      'Direct the user to visit verify_url',
      'Poll poll_url with X-Poll-Secret header every 5 seconds',
      'When status is "verified", extract operator_token from response',
      'Retry the original request with X-Operator-Token header',
    ],
  },
});
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

CheckWhat it verifies
require_kycGovernment-issued photo ID via Stripe Identity
require_sanctions_clearNot on OFAC, SDN, or PEP lists
min_ageAge bracket derived from ID (18+ or 21+)
blocked_jurisdictionsCountry from ID is not in blocked list
allowed_jurisdictionsCountry from ID is in allowed list

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
{
  "decision": "allow",
  "operator_verification": {
    "level": "kyc_verified",
    "operator_type": "individual"
  },
  "policy_result": {
    "all_passed": true,
    "checks": [
      { "rule": "require_kyc", "passed": true },
      { "rule": "require_sanctions_clear", "passed": true },
      { "rule": "min_age", "passed": true, "required": 21 },
      { "rule": "allowed_jurisdictions", "passed": true }
    ]
  }
}

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:
# Always allow (verified individual, US, 21+)
curl -X POST https://api.agentscore.sh/v1/assess \
  -H "X-API-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{"address": "0x0000000000000000000000000000000000000001", "test": true, "policy": {"require_kyc": true, "min_age": 21}}'

# Always deny (unverified)
curl -X POST https://api.agentscore.sh/v1/assess \
  -H "X-API-Key: your-api-key" \
  -d '{"address": "0x0000000000000000000000000000000000000002", "test": true, "policy": {"require_kyc": true}}'

# Sanctions flagged
curl -X POST https://api.agentscore.sh/v1/assess \
  -H "X-API-Key: your-api-key" \
  -d '{"address": "0x0000000000000000000000000000000000000003", "test": true, "policy": {"require_sanctions_clear": true}}'

# Verified entity (DE jurisdiction)
curl -X POST https://api.agentscore.sh/v1/assess \
  -H "X-API-Key: your-api-key" \
  -d '{"address": "0x0000000000000000000000000000000000000004", "test": true, "policy": {"require_kyc": true}}'

Pricing

Compliance gating is included in the Pro plan ($100/mo, 1,000 assess calls). See pricing.

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.