Identity verification gate with policy evaluation. Paid tier required.
Documentation Index
Fetch the complete documentation index at: https://docs.agentscore.sh/llms.txt
Use this file to discover all available pages before exploring further.
| Header | Required | Description |
|---|---|---|
X-API-Key | Yes | Your API key (paid or enterprise tier) |
Content-Type | Yes | application/json |
address (wallet) or operator_token (credential). At least one is required.
| Field | Type | Required | Description |
|---|---|---|---|
address | string | One of address/operator_token | Wallet address — EVM (0x... 40-hex) or Solana (base58, 32–44 chars). Network is auto-detected from the address format. |
operator_token | string | One of address/operator_token | Operator credential (opc_...) for non-wallet agents. Credential resolves to an account’s KYC status. |
chain | string | No | Chain to score. If omitted, scores the chain with the highest existing score. Defaults to base for unknown addresses. |
refresh | boolean | No | Force score recomputation even if cached |
policy | object | No | Policy rules for allow/deny decision |
policy.require_kyc | boolean | No | Require operator KYC verification |
policy.require_sanctions_clear | boolean | No | Require clean sanctions status |
policy.min_age | number | No | Minimum age bracket (18 or 21) |
policy.blocked_jurisdictions | string[] | No | ISO country codes to block (blocklist) |
policy.allowed_jurisdictions | string[] | No | ISO country codes to allow (allowlist — only these pass) |
resolve_signer | object | No | Server-side wallet-signer-match. When present, the API resolves resolve_signer.address to its operator and emits a signer_match block on the response — lets commerce gates collapse the legacy 2 follow-up assess calls into one round trip. |
resolve_signer.address | string | null | If resolve_signer set | Recovered payment-signer wallet. null indicates the rail carries no wallet signature (Stripe SPT, card) — produces signer_match.kind = "wallet_auth_requires_wallet_signing". |
resolve_signer.network | string | If resolve_signer set | Key-derivation family of the signer wallet. evm or solana. |
test | boolean | No | Enable sandbox/test mode with reserved addresses |
"test": true to get controlled responses without hitting the database, rate limits, or billing. Test calls are not logged to the production audit trail.
Test mode only works with these reserved addresses:
| Address | Behavior |
|---|---|
0x0000000000000000000000000000000000000001 | allow — verified individual, US, 21+ |
0x0000000000000000000000000000000000000002 | deny — kyc_required, includes verify_url |
0x0000000000000000000000000000000000000003 | deny — sanctions_flagged |
0x0000000000000000000000000000000000000004 | allow — verified individual, DE |
0x0000000000000000000000000000000000000005 | allow — verified individual, US, 18+ (denies on min_age: 21) |
0x0000000000000000000000000000000000000006 | allow — verified individual, IR (denies on blocked_jurisdictions: ["IR"]) |
0x0000000000000000000000000000000000000007 | allow — verified individual, BR (denies on allowed_jurisdictions: ["US"]) |
test: true with any other address returns a 400 error.
Test responses include "test": true in the response body. If you include a policy object, the test fixtures evaluate the policy rules against their built-in verification data and return realistic decision, decision_reasons, and policy_result fields.
GET /v1/reputation/:address.X-Wallet-Address (or address was supplied), the response includes:
| Field | Type | Description |
|---|---|---|
resolved_operator | string | Canonical operator wallet (the earliest claimed wallet, or the lexically-smallest active-captured wallet). All same-operator sibling wallets resolve to this address. |
linked_wallets | string[] | All same-operator sibling wallets, normalized per network — EVM addresses lowercased, Solana base58 preserved verbatim. Includes both wallets claimed via identity verification and wallets captured via POST /v1/credentials/wallets. May contain a mix of EVM and Solana addresses for multi-chain operators. Merchants doing wallet-signer-match checks should accept a payment signed by any address in this list, regardless of chain. |
signer_match | object | Returned only when the request supplied resolve_signer. Server-side wallet-signer-match verdict — see below. |
signer_match response (when resolve_signer was supplied)resolve_signer, the response carries a signer_match block describing whether the supplied signer wallet resolves to the same operator as the claimed address. Lets commerce gates skip the legacy 2 follow-up assess calls.
| Field | Type | Description |
|---|---|---|
signer_match.kind | string | pass (claimed and signer resolve to the same operator, or are byte-equal); wallet_signer_mismatch (operators differ); wallet_auth_requires_wallet_signing (request supplied resolve_signer.address: null — agent should switch to operator-token auth). |
signer_match.claimed_operator | string | null | Operator the claimed wallet resolves to. null if unlinked. |
signer_match.signer_operator | string | null | Operator the signer wallet resolves to. null if unlinked. |
signer_match.expected_signer | string | Echoed on wallet_signer_mismatch — the claimed wallet, normalized. |
signer_match.actual_signer | string | Echoed on wallet_signer_mismatch — the signer wallet, normalized. |
signer_match.linked_wallets | string[] | Same-operator linked wallets the agent could re-sign from to satisfy the claim. Mirrors the top-level linked_wallets deny-guard — omitted on deny verdicts. |
signer_match.agent_instructions | string | JSON-encoded {action, steps, user_message} envelope for SDK denial bodies. Spread verbatim into the gate’s 403 response. |
verify_url if the denial is resolvable through verification:
| Value | Meaning |
|---|---|
allow | All policy rules passed, or no policy was specified |
deny | One or more policy rules failed |
decision_reasons is an empty array.
explanation array is returned alongside policy_result whenever a policy is provided. Each element describes one rule evaluation:
| Field | Type | Description |
|---|---|---|
rule | string | The policy rule name (e.g., require_kyc) |
passed | boolean | Whether the rule passed |
required | string | The required value for the rule |
actual | string | The actual value found |
message | string | Human-readable description of the result |
how_to_remedy | string | null | Action to resolve a failure, or null if the denial is not fixable (e.g., age below minimum on a verified ID) or the rule passed |
| Reason | When | verify_url? |
|---|---|---|
kyc_required | Not verified | Yes |
kyc_pending | KYC in progress | No |
kyc_failed | KYC failed | Yes (can retry) |
sanctions_flagged | Sanctions match | No |
age_insufficient | Below min_age | No |
jurisdiction_restricted | Blocked country | No |
verify_url, the response contains a URL the agent’s operator can visit to complete or retry verification. This field is only present on compliance denials that are resolvable through verification.
For merchant-initiated flows where you need to create a verification session and poll for completion, see POST /v1/sessions.
require_sanctions_clear checks whether the operator has been flagged in sanctions screening, which happens during KYC verification. For operators who have not completed KYC, this check fails with kyc_required. Sanctions screening is performed automatically as part of the KYC process.policy field, the endpoint returns decision: "allow" with decision_reasons: ["no_policy_applied"]. This is useful for on-the-fly scoring without enforcement.
/v1/assess creates a minimal entry and triggers scoring as a side effect. The assess response is returned immediately based on identity + compliance state — GET /v1/reputation/:address is the endpoint that returns score data.
/v1/assess response (success and 429) carries account-level quota observability headers when the account has a per-period quota:
| Header | Description |
|---|---|
X-Quota-Limit | Total quota for the current period (numeric) |
X-Quota-Used | Current usage within the period (numeric) |
X-Quota-Reset | ISO-8601 timestamp when the period resets, or the literal never for unlimited / lifetime caps |
Response.headers. The Node and Python SDKs surface them on AssessResponse.quota (via assess() / aassess()) so consumers can monitor approach-to-cap proactively (warn at 80%, alert at 95%) before a 429. See @agent-score/sdk and agentscore-py READMEs for usage.
Accounts without a per-period quota (Enterprise / unlimited tiers) receive no X-Quota-* headers.
| Status | error.code | When | Retry posture |
|---|---|---|---|
400 | invalid_request | Malformed body, unknown address format, missing required field | Don’t retry — fix the request |
401 | invalid_api_key | Missing/invalid X-API-Key header | Don’t retry — fix the key |
429 | quota_exceeded | Account-level cap reached | Don’t retry — the cap won’t lift through retry alone. Body carries agent_instructions; commerce SDKs can opt in to fail-open on this code via failOpen / fail_open. |
5xx | api_error | Transient AgentScore infra failure | Retry with backoff per agent_instructions envelope (see errors). Commerce SDKs surface this via failOpen / fail_open opt-in. |
failOpen is enabled — see compliance-gating › Fail-open behavior.