{
  "openapi": "3.1.0",
  "info": {
    "title": "InsumerAPI",
    "version": "1.0",
    "description": "InsumerAPI is the API for wallet auth — the primitive: read on-chain state, evaluate against caller-supplied conditions, return ECDSA-signed booleans across 37 chains. Conditions in, signed attestations out. Provable and private — no shared secrets, no identity-first claims, no static credentials. Never exposes wallet balances. Every result is signed and checkable offline against the published keys, and on EVM chains an optional Merkle proof lets the verifier check the balance against the block header without trusting the API. What a signed result shows: a signed result is InsumerAPI's statement that it read chain state and evaluated the stated conditions. It does not show who controls the wallet or who the person is, and it describes state at its anchor, valid until expiresAt. With a Merkle proof the value can be checked against the chain itself; without one, the result is as reliable as InsumerAPI, its upstream data sources, and its signing keys. A failed read is refused, never signed. Full list of limits: \"What a signed result shows, and what it does not\" in https://insumermodel.com/llms-full.txt. InsumerAPI is the programmatic interface for The Insumer Model — used by developers, AI agents, and platforms alike. One endpoint checks token balances, NFT ownership, EAS attestations, Farcaster identity, arbitrary boolean view calls, dimensionless ratio rules (balance vs a transaction amount, or share of supply), account code (plain key, EIP-7702 delegation or contract at the wallet address, any EVM chain), and agent standing on Base (ERC-8004 registration, ERC-7710 delegation validity) across 37 blockchains, returns ECDSA P-256 signed booleans, and never exposes wallet balances. The primitive is five operations: POST /v1/attest, POST /v1/trust, POST /v1/trust/batch, GET /v1/jwks, and GET /v1/compliance/templates (tags Wallet Auth and Trust Fact Profiles). The other 41 operations are applications built on it (merchant discounts and codes, point-of-sale recognition, ACP/UCP formats for agent commerce, the public directory) and the plumbing around it (keys, credits, billing, health). Supports up to 10 conditions per request, each with its own chainId. Optional Merkle storage proofs (EIP-1186) for trustless verification. Pre-configured compliance templates for Coinbase Verifications (KYC, country, Coinbase One) on Base. Not a points program. Not a reputation network. Not an identity system. Not a DeFi protocol. Not a payments processor. Not an oracle network. Used by AsterPay KYA (ERC-8183 agent trust scoring) and Revettr (counterparty risk for x402). 5 agent SDKs: MCP server (npx -y mcp-server-insumer), LangChain (pip install langchain-insumer), LlamaIndex (pip install llama-index-tools-insumer), ElizaOS (@insumermodel/plugin-eliza), OpenAI GPT (GPT Store). 2 framework adapters: WDK protocol module (@insumermodel/wdk-protocol-wallet-auth) for Tether's Wallet Development Kit; mppx condition-gate (@insumermodel/mppx-condition-gate) for Machine Payments Protocol routes (first listed entry on Tempo's extensions page). Attestations independently verifiable with insumer-verify (npm install insumer-verify, or pip install insumer-verify for Python; same checks, same published test vectors; source https://github.com/insumerapi/insumer-verify). Full guide: https://insumermodel.com/ai-agent-verification-api/ Visual endpoint map: https://insumermodel.com/workbench/\n",
    "contact": {
      "email": "support@insumermodel.com",
      "url": "https://insumermodel.com/developers/"
    },
    "termsOfService": "https://insumermodel.com/terms-of-service/",
    "license": {
      "name": "Proprietary"
    }
  },
  "servers": [
    {
      "url": "https://api.insumermodel.com",
      "description": "Production"
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "x-auth-note": "Default authentication is the X-API-Key header. Five endpoints — POST /v1/attest, POST /v1/trust, POST /v1/trust/batch, GET /v1/credits, and POST /v1/credits/buy — also accept wallet-signed auth via an Authorization: Wallet header (SIWE envelope) from a wallet that holds an Insumer Access pass. All other endpoints require X-API-Key. POST /v1/attest, POST /v1/trust, and POST /v1/trust/batch additionally accept x402 pay-per-call: a request with NO credential headers on those three receives a 402 quote (see each operation's 402 response and x-payment-info) rather than a 401. A credential-less GET or HEAD to one of those three paths receives the same 402 quote (the quote's resource.method still says POST; paid handling stays POST-only). Everywhere else, and whenever a credential is present but invalid, the response is 401 with {ok: false, error: {code: 401, message: 'Invalid or missing API key.'}}. One exception: a request presenting an Authorization: Wallet header to any endpoint outside that five-endpoint wallet-auth allowlist returns 501, stating that wallet-pass auth is scoped to those endpoints only.",
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "API key in format: insr_live_ followed by 40 hex characters"
      },
      "WalletAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "Authorization",
        "description": "Wallet-signed authentication. Accepted on: POST /v1/attest, POST /v1/trust, POST /v1/trust/batch, GET /v1/credits, and POST /v1/credits/buy. Other endpoints return 501 for this scheme. Header value: `Wallet <base64(JSON({message, signature}))>` where `message` is a SIWE (EIP-4361) string with `Domain: api.insumermodel.com` and `signature` is an EIP-191 personal_sign over `message`. The signing wallet must (1) match the wallet registered to the API key (the sender wallet from POST /v1/keys/buy) and (2) hold the Insumer Access pass (soulbound ERC-721 on Base, collection 0x3E2a408cc6eceba04FF9d04A5B8B05aBa8DD50ce). Nonce is single-use; `Issued At` must be within the last 5 minutes. Wallet auth authenticates the caller only. Every wallet evaluated by /v1/attest, /v1/trust, or /v1/trust/batch comes from the request body, is independent of the signer, and is not required to match it. A relying party that needs the verdict bound to the presenting wallet verifies that wallet's own signature first, then attests the recovered address (the pattern `@skyemeta/access` implements). Drop-in middleware available as `@skyemeta/access` on npm.\n"
      }
    },
    "responses": {
      "RateLimited": {
        "description": "Rate limit exceeded. API-key requests count against the key's daily limit; every authenticated response carries X-RateLimit-Limit and X-RateLimit-Remaining headers, and a 429 additionally carries Retry-After (seconds until the window resets).\n",
        "headers": {
          "X-RateLimit-Limit": {
            "schema": {
              "type": "string"
            },
            "description": "The key's daily request limit."
          },
          "X-RateLimit-Remaining": {
            "schema": {
              "type": "string"
            },
            "description": "Requests remaining in the current daily window."
          },
          "Retry-After": {
            "schema": {
              "type": "string"
            },
            "description": "Seconds until the rate-limit window resets."
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "ServerError": {
        "description": "Unexpected server error. Safe to retry; no credits are charged on a 500. Router endpoints return the standard error envelope; standalone endpoints (the ones whose 200 is a flat object) return a flat {\"error\": \"...\"} object.\n",
        "content": {
          "application/json": {
            "schema": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              ]
            }
          }
        }
      }
    },
    "schemas": {
      "ChainId": {
        "oneOf": [
          {
            "type": "integer",
            "enum": [
              1,
              56,
              8453,
              43114,
              137,
              42161,
              10,
              88888,
              1868,
              98866,
              146,
              100,
              5000,
              534352,
              59144,
              324,
              81457,
              167000,
              2020,
              42220,
              88,
              204,
              480,
              130,
              57073,
              1329,
              80094,
              33139,
              50,
              4663,
              5042
            ]
          },
          {
            "type": "string",
            "enum": [
              "solana",
              "xrpl",
              "bitcoin",
              "tron",
              "stellar",
              "sui"
            ]
          }
        ],
        "description": "EVM chain ID (integer), or one of \"solana\", \"xrpl\", \"bitcoin\", \"tron\", \"stellar\", \"sui\" (string). Supported chains: Ethereum (1), BNB Chain (56), Base (8453), Avalanche (43114), Polygon (137), Arbitrum (42161), Optimism (10), Chiliz (88888), Soneium (1868), Plume (98866), Sonic (146), Gnosis (100), Mantle (5000), Scroll (534352), Linea (59144), zkSync Era (324), Blast (81457), Taiko (167000), Ronin (2020), Celo (42220), Viction (88), opBNB (204), World Chain (480), Unichain (130), Ink (57073), Sei (1329), Berachain (80094), ApeChain (33139), XDC Network (50), Robinhood Chain (4663), Arc (5042), Solana (\"solana\"), XRP Ledger (\"xrpl\"), Bitcoin (\"bitcoin\"), Tron (\"tron\"), Stellar (\"stellar\"), Sui (\"sui\"). Bitcoin only supports token_balance with contractAddress \"native\". Tron, Stellar, and Sui support token_balance only. Moonbeam (1284) and Moonriver (1285) were retired on 2026-09-20 after both networks stopped producing blocks. GLMR and MOVR now live on Base (chainId 8453) as ERC-20s and are read with an ordinary token_balance condition; a request naming either retired chain returns 400.\n"
      },
      "OnboardingChainId": {
        "oneOf": [
          {
            "type": "integer",
            "enum": [
              1,
              56,
              8453,
              43114,
              137,
              42161,
              10,
              88888,
              1868,
              98866,
              146,
              100,
              5000,
              534352,
              59144,
              324,
              81457,
              167000,
              2020,
              42220,
              88,
              204,
              480,
              130,
              57073,
              1329,
              80094,
              33139,
              50,
              4663,
              5042
            ]
          },
          {
            "type": "string",
            "enum": [
              "solana",
              "xrpl"
            ]
          }
        ],
        "description": "Chains supported for merchant token/NFT configuration: all 31 EVM chains (same integer IDs as ChainId) plus Solana (\"solana\") and XRP Ledger (\"xrpl\"). Bitcoin, Tron, Stellar, and Sui are not available for merchant registry configuration, though they remain queryable via /v1/attest and /v1/trust.\n"
      },
      "PaymentChainId": {
        "oneOf": [
          {
            "type": "integer",
            "enum": [
              1,
              8453,
              137,
              42161,
              10,
              56,
              43114
            ]
          },
          {
            "type": "string",
            "enum": [
              "solana",
              "bitcoin",
              "tron"
            ]
          }
        ],
        "description": "Chains supported for crypto payments. EVM chains and Solana accept USDC and USDT. Bitcoin accepts BTC (converted to USD at market rate, requires 1 confirmation). Tron accepts USDT-TRC20."
      },
      "UsdcChainId": {
        "$ref": "#/components/schemas/PaymentChainId"
      },
      "SuccessEnvelope": {
        "type": "object",
        "required": [
          "ok",
          "data",
          "meta"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          },
          "data": {
            "type": "object"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        }
      },
      "ErrorEnvelope": {
        "type": "object",
        "required": [
          "ok",
          "error",
          "meta"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": false
          },
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "integer"
              },
              "message": {
                "type": "string"
              }
            }
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        }
      },
      "X402Quote": {
        "type": "object",
        "description": "x402 pay-per-call quote body, returned with HTTP 402 to credential-less callers on the pay-per-call endpoints (POST /v1/attest, POST /v1/trust, POST /v1/trust/batch). The same payload, base64-encoded, also rides in the payment-required response header. This is NOT the standard error envelope: there is no ok or meta field, and error is a plain string.\n",
        "required": [
          "x402Version",
          "error",
          "resource",
          "accepts"
        ],
        "properties": {
          "x402Version": {
            "type": "integer",
            "description": "x402 protocol version of this quote."
          },
          "error": {
            "type": "string",
            "description": "Why the request was not processed as a paid call, as a plain string (e.g. \"PAYMENT-SIGNATURE (or X-PAYMENT) header is required\", or the reason a submitted payment was rejected)."
          },
          "resource": {
            "type": "object",
            "description": "Resource envelope describing the payable endpoint: url, method, description, mimeType, serviceName, tags, iconUrl."
          },
          "accepts": {
            "type": "array",
            "description": "Payment requirements the caller may satisfy: one entry per settlement network — Base (eip155:8453, first), Polygon (eip155:137), Arbitrum (eip155:42161), Solana (solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp), Arc (eip155:5042, last) — each carrying scheme, network (CAIP-2), amount (atomic USDC units, identical across entries), asset, payTo, maxTimeoutSeconds, and extra (the USDC EIP-712 domain fields on EVM entries, which differ by network: name \"USD Coin\" on Base, Polygon and Arbitrum, \"USDC\" on Arc, so sign under the quoted values; the facilitator's feePayer on the Solana entry). The quote is priced for the exact submitted body, so the advertised amount is the price of this request.",
            "items": {
              "type": "object"
            }
          },
          "extensions": {
            "type": "object",
            "description": "Discovery metadata for catalog crawlers."
          }
        }
      },
      "RpcFailureEnvelope": {
        "type": "object",
        "description": "Returned when one or more upstream data sources are unavailable after retries. No attestation is signed, no JWT issued, and no credits are charged. This is a retryable error — the caller should retry the same request after a short delay (e.g. 2-5 seconds). Do NOT treat this as a verification failure. Most refusals clear on retry. A few repeat until the wallet or the source changes: a wallet holding more than one read can page through, or a kind of asset the answering source cannot observe. If the same request is refused again with the same failedConditions, stop retrying and treat the result as unavailable, never as pass: false.\n",
        "required": [
          "ok",
          "error",
          "meta"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": false
          },
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "rpc_failure"
                ]
              },
              "message": {
                "type": "string",
                "example": "Unable to verify all conditions — data source unavailable after retries"
              },
              "failedConditions": {
                "type": "array",
                "description": "Which reads failed, each with the operation and the chain it was scoped to.",
                "items": {
                  "type": "object",
                  "properties": {
                    "source": {
                      "type": "string",
                      "description": "Generic operation label for the failed read. One of: balance_read, token_metadata_read, supply_read, attestation_read, identity_read, agent_registry_read, signature_check, delegation_read, view_call, chain_head_read, chain_read (the catch-all)."
                    },
                    "chainId": {
                      "oneOf": [
                        {
                          "type": "integer"
                        },
                        {
                          "type": "string"
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "Chain the failed read was scoped to. Integer for EVM chains, string for non-EVM chains, null when the failing read was not chain-scoped."
                    },
                    "message": {
                      "type": "string",
                      "description": "A short phrase naming what failed, for example \"Timeout\", \"transport error\", \"data source unreachable\" or \"malformed response from the data source\". It names no data source."
                    }
                  }
                }
              }
            }
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        }
      },
      "Meta": {
        "type": "object",
        "properties": {
          "version": {
            "type": "string",
            "example": "1.0"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Condition": {
        "type": "object",
        "required": [
          "type"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "token_balance",
              "nft_ownership",
              "eas_attestation",
              "farcaster_id",
              "evm_view_call",
              "ratio_to_amount",
              "ratio_to_supply",
              "erc8004_agent",
              "erc7710_delegation",
              "account_code"
            ]
          },
          "expect": {
            "type": "string",
            "enum": [
              "none",
              "eip7702",
              "contract"
            ],
            "description": "Required for account_code. The code state the wallet address itself must be in at the anchored block: \"none\" (no code: a plain key account), \"eip7702\" (the EIP-7702 delegation designator: a key that has delegated execution to a contract), or \"contract\" (any other code: a smart-contract wallet, a protocol, a token). The three are exclusive on a chain. The result is the boolean met; the code and the delegation target are never returned. EVM chains only (a non-EVM chainId is a 400). 1 credit. Proof mode returns an EIP-1186 account proof whose codeHash field is the proven value (subject \"account_code\").",
            "example": "eip7702"
          },
          "delegate": {
            "type": "string",
            "description": "Optional, account_code with expect \"eip7702\" only (a 400 with any other expect). An EVM address: the condition is met iff the wallet's designator points at this address. A caller who cares which contract names it here and still receives only yes or no; when supplied it is echoed inside the signed evaluatedCondition so the hash binds the question asked.",
            "example": "0x5a7fc11397e9a8ad41bf10bf13f22b0a63f96f6d"
          },
          "contractAddress": {
            "type": "string",
            "description": "Token or NFT contract address (required for token_balance, nft_ownership, ratio_to_amount, ratio_to_supply, and evm_view_call; use \"native\" for the chain's native asset on token_balance and ratio_to_amount; nft_ownership requires the NFT contract, ratio_to_supply an ERC-20 contract and evm_view_call a real contract, and \"native\" on any of those three is a 400. To ask whether a wallet holds the native coin, use token_balance with \"native\"). For Solana: \"native\" for SOL, or the mint address (base58, 32 to 44 characters); anything else is a 400. For XRPL: use \"native\" for XRP, or the issuer r-address for trust line tokens and NFTs; the base58 checksum is verified, so a mistyped issuer is a 400. For Tron: \"native\" for TRX, or a TRC-20 contract address (starts with T; the checksum is verified, so a mistyped address is a 400). For Stellar: \"native\" for XLM, or the asset issuer's G-address (StrKey, 56 chars; the checksum is verified, so a mistyped issuer is a 400). For Bitcoin: must be \"native\". For Sui: must be a coin type (address::module::Name, optionally with type parameters); the short form (0x2::sui::SUI) and the 64-hex long form of an address name the same coin, and anything that is not a coin type is a 400. On two chains the native asset is ALSO exposed as an ERC-20 at a mirror contract, so \"native\" and that address are one balance read two ways: Celo 42220 (0x471EcE3750Da237f93B8E339c536989b8978a438) and Arc 5042 (USDC predeploy 0x3600000000000000000000000000000000000000, which is Arc's gas asset). TWO token_balance conditions requiring BOTH in one call count the same holding twice, so that pair is refused with a 400 naming both condition indexes before any credit is charged — use one or the other. The guard covers token_balance pairs only; a ratio_to_amount rule is not summed against a token_balance threshold, so that combination is redundant rather than refused."
          },
          "selector": {
            "type": "string",
            "description": "Required for evm_view_call. The canonical signature of a view function returning bool, in the form \"functionName(address)\" (e.g. \"hasAccess(address)\"). v1 supports single-address-argument view functions only; the 4-byte selector is derived from this signature. EVM chains only."
          },
          "chainId": {
            "$ref": "#/components/schemas/ChainId"
          },
          "threshold": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "string"
              }
            ],
            "description": "Minimum balance required (token_balance type), in token/display units — e.g. \"100\" for 100 USDC or \"0.001\" for 0.001 ETH, NOT base units/wei. The token's own decimals are read from the chain (a decimals value in the request is a cross-check, never an override) and the raw balance is scaled before comparison, so a base-unit threshold such as \"1000000\" for 1 USDC is a valid request for one million USDC and simply returns met: false. v1 keys take a JSON number (e.g. 100). v2 keys — which is every newly created key — require a decimal STRING (e.g. \"100\"); a JSON number is rejected with 400. v2 carries the threshold as an exact canonical decimal so an agent can specify full-precision thresholds that a JSON float would silently round. Must be > 0 (use \"0.000001\" / 0.000001 for prove-any-balance). A decimal string is at most 400 characters."
          },
          "multiple": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "string"
              }
            ],
            "description": "Required for ratio_to_amount. The collateralization multiple — the condition is met iff balance >= multiple * amount (e.g. 10 for \"hold >= 10x the transaction amount\"). v1 keys take a JSON number; v2 keys — every newly created key — require a decimal STRING (e.g. \"10\") and reject a JSON number with 400. Must be > 0. A decimal string is at most 400 characters."
          },
          "amount": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "string"
              }
            ],
            "description": "Required for ratio_to_amount. The per-request reference amount (e.g. the transaction size the agent intends to make), in token/display units — e.g. 100 for 100 USDC, NOT base units/wei. v1: JSON number; v2: decimal STRING (e.g. \"100\"). Must be > 0. An amount with more decimal places than the token has is a 400. ratio_to_amount is supported on EVM chains only. A decimal string is at most 400 characters."
          },
          "minFraction": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "string"
              }
            ],
            "description": "Required for ratio_to_supply. The required share of the token's on-chain total supply, as a fraction in (0, 1] — e.g. 0.005 for 0.5% of supply. The condition is met iff balance / totalSupply() >= minFraction. v1: JSON number; v2: decimal STRING (e.g. \"0.005\"). Use for project/governance tokens where share-of-supply is meaningful (not stablecoins). Supported on EVM chains, ERC-20 contracts only. A decimal string is at most 400 characters."
          },
          "decimals": {
            "oneOf": [
              {
                "type": "integer",
                "minimum": 0,
                "maximum": 100
              },
              {
                "type": "string",
                "pattern": "^(0{0,2}[0-9]|0?[1-9][0-9]|100)$"
              }
            ],
            "description": "Optional, for token_balance and ratio_to_amount. The token's own decimals are always read from the chain: decimals() on EVM and Tron at the anchored block, the coin metadata on Sui; native coins are fixed by definition. A scale is never taken from the request and never assumed. When sent, decimals is a cross-check. It must be an integer from 0 to 100 (a JSON number, or its digits as a string); anything else is a 400. If it equals the token's own value nothing changes; if it differs the API returns 400 and the message names the token's own value. A token that states no decimals on chain: a zero balance is signed as met: false (zero is zero at any scale); any other balance is a 400 on every key, because no scale exists for the threshold to be read at and none is ever taken from the request. If the token's decimals cannot be read (an upstream failure) the API returns the documented 503 rpc_failure, never a 400. Why: a threshold is in display units, so the verdict depends on the scale, and the relying party must be able to trust that the scale is the token's own."
          },
          "currency": {
            "type": "string",
            "description": "XRPL currency code (required for XRPL trust line tokens, ignored for other chains). One of: a 3-character standard code (e.g. \"USD\"; letters, digits and ?!@#$%^&*<>(){}[]| only), a token name of 1 to 20 printable ASCII characters (e.g. \"RLUSD\", hex-encoded to a 40-character code), or a 40-character hex currency code. Anything else, including a non-string, is a 400. Currency codes are case-sensitive on the XRP Ledger: send the code exactly as the issuer created it. `USD` and `usd` are different currencies, and a token name is encoded in the letter case sent. `XRP` is the native coin, not a trust line currency: on a trust line condition it is a 400, as are its 40-character hex spellings. To check XRP, use contractAddress \"native\". The 40-character hex spelling of a 3-character code is that code, and is returned in the 3-character form. The code is carried inside the signed evaluatedCondition, so it can only ever be well-formed Unicode.",
            "example": "RLUSD"
          },
          "assetCode": {
            "type": "string",
            "description": "Stellar trustline asset code (e.g. \"USDC\"): 1 to 12 characters from a-z, A-Z, 0-9. Required for Stellar trustline token_balance conditions (contractAddress is the G-issuer); not used for native XLM. Anything outside that alphabet, or a non-string, is a 400. The code is carried inside the signed evaluatedCondition, so it can only ever be well-formed Unicode.",
            "example": "USDC"
          },
          "taxon": {
            "type": "integer",
            "description": "XRPL NFToken taxon filter (optional, for XRPL conditions): an integer from 0 to 4294967295, as a JSON number or its digits as a string; anything else (a fraction, a negative, text) is a 400, and so is null on nft_ownership. On nft_ownership it filters NFTs by issuer + taxon; on any XRPL condition a supplied taxon is carried into the signed evaluatedCondition as a JSON number."
          },
          "label": {
            "type": "string",
            "maxLength": 100,
            "description": "Human-readable label for this condition. It is carried inside the signed result. A longer label is cut to 100 UTF-16 code units rather than rejected, and the cut never splits a surrogate pair: the signed label is always well-formed Unicode (an unpaired surrogate is replaced with U+FFFD), so the signed bytes can be rebuilt in any language."
          },
          "schemaId": {
            "type": "string",
            "description": "EAS schema ID (bytes32 hex string). Required for eas_attestation unless template is provided.",
            "example": "0xf8b05c79f090979bf4a80270aba232dff11a10d9ca55c4f88de95317970f0de9"
          },
          "attester": {
            "type": "string",
            "description": "Expected attester address (optional, for eas_attestation). If provided, the attestation's attester must match this address (case-insensitive). Recipient is not a request-side field — it auto-binds to the wallet being verified, and the attestation's recipient field must equal that wallet for the condition to pass."
          },
          "indexer": {
            "type": "string",
            "description": "EAS indexer contract address (0x + 40 hex chars; format-validated when present: a malformed value returns 400, as does a malformed attester). Required for raw (non-template) eas_attestation conditions: a raw condition without it returns 400, because without an indexer there is no way to resolve an attestation UID and nothing could be evaluated. Templates supply their own. The API resolves the attestation UID by calling `getAttestationUid(address recipient, bytes32 schema) returns (bytes32)` (selector 0xab2717dd) on this contract, then fetches and verifies the resolved attestation against the EAS contract on the target chain. Custom EAS issuers must deploy or co-list in such an indexer; see /developers/compliance/#custom-eas-issuers."
          },
          "template": {
            "type": "string",
            "enum": [
              "coinbase_verified_account",
              "coinbase_verified_country",
              "coinbase_one",
              "gitcoin_passport_score",
              "gitcoin_passport_active"
            ],
            "description": "Pre-configured compliance template name. Use instead of raw schemaId/attester/indexer — the template fills in all three. See GET /v1/compliance/templates for available templates."
          },
          "agentId": {
            "type": "string",
            "description": "Required for erc8004_agent (generally available on any API key, and on x402 pay-per-call with no key). The ERC-8004 agent ID as a uint256 decimal string. Must be supplied by the caller — the deployed Identity Registry has no wallet-to-agentId reverse lookup. The condition is met iff the attested wallet owns the agent NFT (ownerOf) or is the registry's on-chain signature-verified agentWallet binding (getAgentWallet). Registry: ERC-8004 Identity Registry 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432 on Base; chainId 8453 only. tokenURI JSON is never trusted. Note the honest semantics: ERC-8004 registration is permissionless NFT minting — the signed statement is exactly \"registered in registry R at agentId N, owned by / bound to this wallet\" and implies no vetting, no reputation, no endorsement. Merkle proofs are not available for this type.",
            "example": "123"
          },
          "delegationManager": {
            "type": "string",
            "description": "Required for erc7710_delegation (generally available on any API key, and on x402 pay-per-call with no key). The DelegationManager contract address the delegation was signed against. Must be one of the three recognized MetaMask Delegation Framework managers on Base (framework versions 1.0.0 / 1.1.0 / 1.3.0; current default 0xdb9B1e94B5b69Df7e401DDbedE43491141047dB3). chainId 8453 only. Max 3 erc7710_delegation conditions per request. Merkle proofs ARE available for this type: with proof: \"merkle\" the result carries an EIP-1186 storage proof of the revocation slot (subject \"delegation_revocation\"), for managers whose storage layout has been verified on-chain — currently the v1.3.0 manager 0xdb9B1e94B5b69Df7e401DDbedE43491141047dB3 on Base. Other recognized managers return proof.available: false with a reason naming the unverified layout, because an inferred slot would produce a proof of the wrong location that still verifies against the block header.",
            "example": "0xdb9B1e94B5b69Df7e401DDbedE43491141047dB3"
          },
          "expectedDelegator": {
            "type": "string",
            "description": "Required for erc7710_delegation. The principal address the caller asserts authorized this agent. The condition fails unless the delegation's declared delegator matches this address — without it a self-delegation would read as authority, so there is no structural-only mode."
          },
          "delegation": {
            "type": "object",
            "description": "Required for erc7710_delegation. The signed ERC-7710 delegation to evaluate. The condition is met iff ALL of: the attested wallet is the delegate; the declared delegator is expectedDelegator; the EIP-712 signature verifies (EOA recovery, or ERC-1271 for contract principals); the delegation is not revoked on-chain as of the anchored block; every caveat uses a recognized enforcer (an unknown enforcer fails the condition, no override); and any time-window caveat is currently satisfied. Recognized caveat enforcers (5 kinds): timestamp (time window — evaluated now), erc20_transfer_amount, native_transfer_amount, allowed_targets, limited_calls. Recognition is per manager: native_transfer_amount is recognized on the 1.1.0 and 1.3.0 managers only, not on 1.0.0 (a 1.0.0 delegation carrying it fails as an unknown enforcer). The last four are REPORTED as declared limits — on-chain redemption enforces them; the attestation states what the principal signed, it does not simulate enforcement. Keep the two apart: `met` is the verdict — the boolean listed above, and nothing more. `declaredLimits` is NOT an input to that boolean; it is a signed DECODE of the caveat terms the caller itself submitted, riding alongside the verdict inside the signed results — on true and false verdicts alike, once the signature and revocation checks pass. Each decoded entry carries the exact `terms` hex it was decoded from, so the decode is a checkable claim rather than an assertion: re-run the enforcer contract's public getTermsInfo byte layout against `terms` and compare, and recompute `delegationHash` (in evaluatedCondition — the EIP-712 struct hash committing to every caveat's enforcer and terms) from the delegation object you hold. Set the top-level `declaredLimits` request modifier to \"omit\" to leave the decode out of the signed results entirely. Attestations containing a delegation condition expire in 5 minutes (not the standard 30) — revocation is one transaction away, so the verdict window stays tight; the verdict states \"not revoked as of block N\".",
            "required": [
              "delegator",
              "delegate",
              "authority",
              "caveats",
              "salt",
              "signature"
            ],
            "properties": {
              "delegator": {
                "type": "string",
                "description": "Principal address that signed the delegation. Must equal expectedDelegator."
              },
              "delegate": {
                "type": "string",
                "description": "Agent wallet the delegation authorizes. Must equal the attested wallet."
              },
              "authority": {
                "type": "string",
                "description": "Root authority only (0xffff…ffff, 32 bytes of 0xff). Delegation chains are unsupported in v1.",
                "example": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
              },
              "caveats": {
                "type": "array",
                "maxItems": 16,
                "description": "Caveats the principal signed (max 16). Every enforcer must be recognized or the condition fails.",
                "items": {
                  "type": "object",
                  "required": [
                    "enforcer",
                    "terms"
                  ],
                  "properties": {
                    "enforcer": {
                      "type": "string",
                      "description": "Caveat enforcer contract address"
                    },
                    "terms": {
                      "type": "string",
                      "description": "ABI-encoded caveat terms (hex)"
                    }
                  }
                }
              },
              "salt": {
                "type": "string",
                "description": "Delegation salt (decimal string)",
                "example": "42"
              },
              "signature": {
                "type": "string",
                "description": "EIP-712 signature over the delegation (hex). EOA recovery, or ERC-1271 for smart-contract principals."
              }
            }
          }
        }
      },
      "EvaluatedCondition": {
        "type": "object",
        "description": "The exact condition logic that was evaluated, included for tamper-evidence. Callers can recompute conditionHash from this object to verify integrity.",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "token_balance",
              "nft_ownership",
              "eas_attestation",
              "farcaster_id",
              "evm_view_call",
              "ratio_to_amount",
              "ratio_to_supply",
              "erc8004_agent",
              "erc7710_delegation",
              "account_code"
            ]
          },
          "chainId": {
            "$ref": "#/components/schemas/ChainId"
          },
          "expect": {
            "type": "string",
            "enum": [
              "none",
              "eip7702",
              "contract"
            ],
            "description": "The code state the condition asked for (present only for account_code conditions). With operator code_state the result is met iff the code at the wallet address at blockNumber is in this state; nothing read from the chain is echoed here."
          },
          "contractAddress": {
            "type": "string",
            "description": "Contract address that was queried (token_balance, nft_ownership, ratio_to_amount, and ratio_to_supply). For XRPL: \"native\" or issuer r-address. For evm_view_call: the contract whose view function was called."
          },
          "operator": {
            "type": "string",
            "enum": [
              "gte",
              "gt",
              "valid",
              "decoder",
              "registered",
              "view_call_true",
              "gte_fraction",
              "owner_or_bound_wallet",
              "authorized_by_principal",
              "code_state"
            ],
            "description": "Comparison operator used: gte (>=) for token_balance and ratio_to_amount, gte_fraction (balance/totalSupply >=) for ratio_to_supply, gt (>) for nft_ownership, valid for eas_attestation, decoder for Gitcoin Passport, registered for farcaster_id, view_call_true for evm_view_call, owner_or_bound_wallet for erc8004_agent, authorized_by_principal for erc7710_delegation, code_state for account_code (the code at the wallet address is in the state named by expect)"
          },
          "selector": {
            "type": "string",
            "description": "The view function signature that was called (present only for evm_view_call conditions)"
          },
          "threshold": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "string"
              }
            ],
            "description": "Threshold value used in comparison (human-readable units for token_balance, 0 for nft_ownership). For ratio_to_amount this is the authoritative derived value (= multiple * amount) that balance was compared against. Not present for eas_attestation or ratio_to_supply. v1 keys return a JSON number; v2 keys — every newly created key — return a canonical decimal string (nft_ownership stays the number 0 on both)."
          },
          "multiple": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "string"
              }
            ],
            "description": "Collateralization multiple (present only for ratio_to_amount). Echoed for provenance; threshold (= multiple * amount) is the authoritative comparison value. v1: JSON number; v2: canonical decimal string."
          },
          "amount": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "string"
              }
            ],
            "description": "Reference amount in token/display units (present only for ratio_to_amount). Echoed for provenance; the operative comparison is balance >= threshold. v1: JSON number; v2: canonical decimal string."
          },
          "minFraction": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "string"
              }
            ],
            "description": "Required share of total supply as a fraction in (0, 1] (present only for ratio_to_supply). The condition (balance / totalSupply >= minFraction) is fully described by this plus contractAddress/chainId; the totalSupply read and computed fraction are returned on the result object (siblings of evaluatedCondition), not here, so conditionHash stays a pure rule fingerprint. v1: JSON number; v2: canonical decimal string."
          },
          "decimals": {
            "type": "integer",
            "nullable": true,
            "description": "Token decimals (present only for token_balance and ratio_to_amount conditions). v1 attest responses only. On the 31 EVM chains it is the token's own decimals, as read from the chain. On the other chain families it repeats the value sent in the request, or is null when none was sent. Trust profiles always return a non-null value. v2 attest omits this field entirely: the canonical decimal threshold is self-describing."
          },
          "currency": {
            "type": "string",
            "description": "XRPL currency code the condition was evaluated against: a 3-character code, or the 40-character hex form of a token name or hex code. Present when a currency was sent on an XRPL condition; a trust line condition always carries it."
          },
          "assetCode": {
            "type": "string",
            "description": "Stellar trustline asset code. Present only for Stellar trustline token_balance conditions."
          },
          "taxon": {
            "type": "integer",
            "description": "XRPL NFToken taxon filter. Present when a taxon was sent on an XRPL condition."
          },
          "schemaId": {
            "type": "string",
            "description": "EAS schema ID (present only for eas_attestation conditions)"
          },
          "attester": {
            "type": "string",
            "description": "Expected attester address (present only for eas_attestation conditions when attester was specified)"
          },
          "decoder": {
            "type": "string",
            "description": "Decoder contract address (present only for decoder-based eas_attestation conditions like Gitcoin Passport)"
          },
          "decoderMethod": {
            "type": "string",
            "enum": [
              "isHuman",
              "getScore"
            ],
            "description": "The decoder method that decided the verdict (present only for decoder-based eas_attestation conditions). isHuman: met when the Passport decoder reports the wallet as human (score of at least 20; template gitcoin_passport_score). getScore: met when the score is above zero (template gitcoin_passport_active). Signed, so a verifier can tell the two templates apart; match it as well as decoder."
          },
          "registry": {
            "type": "string",
            "description": "ERC-8004 Identity Registry contract address that was queried, in lower case as signed (present only for erc8004_agent conditions)",
            "example": "0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"
          },
          "agentId": {
            "type": "string",
            "description": "Agent ID evaluated, uint256 decimal string (present only for erc8004_agent conditions)"
          },
          "wallet": {
            "type": "string",
            "description": "The attested wallet the condition was evaluated against (present only for erc8004_agent and erc7710_delegation conditions)"
          },
          "delegationManager": {
            "type": "string",
            "description": "DelegationManager contract address the delegation was verified against (present only for erc7710_delegation conditions)"
          },
          "domainVersion": {
            "type": "string",
            "description": "EIP-712 domain version used for signature verification (present only for erc7710_delegation conditions)"
          },
          "frameworkVersion": {
            "type": "string",
            "description": "MetaMask Delegation Framework version of the recognized manager: 1.0.0, 1.1.0, or 1.3.0 (present only for erc7710_delegation conditions)"
          },
          "delegationHash": {
            "type": "string",
            "description": "Hash of the evaluated delegation (present only for erc7710_delegation conditions)"
          },
          "delegator": {
            "type": "string",
            "description": "Declared delegator (principal) from the delegation (present only for erc7710_delegation conditions)"
          },
          "delegate": {
            "type": "string",
            "description": "On erc7710_delegation: the declared delegate (agent wallet) from the delegation. On account_code: the address the caller named, present only when one was supplied; met then also requires the wallet's EIP-7702 designator to point at it. Absent on every other type."
          },
          "authority": {
            "type": "string",
            "description": "Always \"root\" — delegation chains are unsupported in v1 (present only for erc7710_delegation conditions)"
          },
          "expectedDelegator": {
            "type": "string",
            "description": "The principal the caller asserted (present only for erc7710_delegation conditions)"
          },
          "signatureType": {
            "type": "string",
            "enum": [
              "eoa",
              "erc1271",
              "none"
            ],
            "description": "How the delegation signature verified (present only for erc7710_delegation conditions). \"eoa\" means an EOA principal signed the delegation; \"erc1271\" means a smart-contract principal asserts the delegation is valid — that is a different claim, and both appear distinctly in the signed bytes."
          },
          "caveatCoverage": {
            "type": "string",
            "enum": [
              "full",
              "partial"
            ],
            "description": "Whether every caveat was evaluated/decoded (present only for erc7710_delegation conditions)"
          },
          "caveatCount": {
            "type": "string",
            "description": "Number of caveats in the delegation, as a decimal string inside the signed bytes (present only for erc7710_delegation conditions)"
          },
          "unevaluatedCaveats": {
            "type": "string",
            "description": "Number of caveats reported as declared limits rather than evaluated, as a decimal string inside the signed bytes (present only for erc7710_delegation conditions)"
          }
        }
      },
      "AttestationResult": {
        "type": "object",
        "properties": {
          "condition": {
            "type": "integer",
            "description": "Index of the condition in the request array"
          },
          "label": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "token_balance",
              "nft_ownership",
              "eas_attestation",
              "farcaster_id",
              "evm_view_call",
              "ratio_to_amount",
              "ratio_to_supply",
              "erc8004_agent",
              "erc7710_delegation",
              "account_code"
            ]
          },
          "chainId": {
            "$ref": "#/components/schemas/ChainId"
          },
          "met": {
            "type": "boolean"
          },
          "evaluatedCondition": {
            "$ref": "#/components/schemas/EvaluatedCondition"
          },
          "conditionHash": {
            "type": "string",
            "description": "SHA-256 hash of the canonical (sorted-key) JSON of evaluatedCondition, prefixed with 0x. Callers can recompute this to verify the condition was not tampered with.",
            "example": "0x3a7f1b2c..."
          },
          "totalSupply": {
            "type": "string",
            "description": "Raw on-chain totalSupply() read at blockNumber (integer as a string), present only for ratio_to_supply. A reproducibility reference: re-read totalSupply at blockNumber to confirm. Inside the signed results payload but outside conditionHash.",
            "example": "52448506631611846"
          },
          "fraction": {
            "type": "number",
            "description": "Computed balance / totalSupply at blockNumber (present only for ratio_to_supply, and only on v1 keys; v2 responses omit this field so no float enters the canonical signed bytes). Display/transparency value; verifiers should re-derive met from the raw on-chain reads rather than this float. Can exceed 1.0 for pathological tokens where balanceOf > totalSupply.",
            "example": 5.93479e-10
          },
          "agentExists": {
            "type": "boolean",
            "description": "Whether the agent NFT exists in the Identity Registry (present only for erc8004_agent conditions)"
          },
          "matchedVia": {
            "type": "string",
            "enum": [
              "owner",
              "agent_wallet",
              "none"
            ],
            "description": "How the attested wallet matched the agent: \"owner\" (holds the agent NFT via ownerOf), \"agent_wallet\" (the registry's on-chain signature-verified agentWallet binding via getAgentWallet), or \"none\". Present only for erc8004_agent conditions. The registry clears the agentWallet binding automatically when the agent NFT transfers — a block-anchored verdict reflects binding truth at that block."
          },
          "declaredLimits": {
            "type": "array",
            "description": "Decoded caveat limits the principal signed, with decimal-string amounts in base units (present only for erc7710_delegation conditions, and only when the request did not set declaredLimits: \"omit\"). These are REPORTED as declared — on-chain redemption enforces them; the attestation states what the principal signed, it does not simulate enforcement. Not part of the met verdict: this is a signed decode of caveat terms the caller itself submitted, a sibling of evaluatedCondition — inside the signed results payload but outside conditionHash. The decode is independently verifiable: each entry carries the exact terms hex it came from, so re-run the enforcer contract's public getTermsInfo byte layout against terms and compare to the decoded values. No external lookup is needed, since the caller supplied those bytes in its own request. Present on both true and false verdicts: the decode is computed once the signature and revocation checks pass, so a delegation failing on unknown_caveat_enforcer (recognized subset only, with unrecognizedEnforcers naming the rest) or outside_time_window still carries it. Failures at or before the signature and revocation checks carry no decode.",
            "items": {
              "type": "object",
              "properties": {
                "kind": {
                  "type": "string",
                  "enum": [
                    "timestamp",
                    "erc20_transfer_amount",
                    "native_transfer_amount",
                    "allowed_targets",
                    "limited_calls"
                  ],
                  "description": "Which recognized caveat enforcer this entry decodes. Field set per kind: timestamp → timestampAfter, timestampBefore; erc20_transfer_amount → token, maxAmount; native_transfer_amount → maxAmount; allowed_targets → targets (array); limited_calls → maxCalls."
                },
                "enforcer": {
                  "type": "string",
                  "description": "Caveat enforcer contract address the entry was decoded for",
                  "example": "0xf100b0819427117ecf76ed94b358b1a5b5c6d2fc"
                },
                "terms": {
                  "type": "string",
                  "description": "The exact hex bytes this entry was decoded from — the caveat terms as submitted in the request. Re-run the enforcer's public getTermsInfo byte layout against this value to check the decode yourself. The signed evaluatedCondition also carries delegationHash, the EIP-712 struct hash committing to every caveat's enforcer and terms, so a verifier can recompute that hash from the delegation object it holds and confirm it matches.",
                  "example": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913000000000000000000000000000000000000000000000000000000003b9aca00"
                },
                "token": {
                  "type": "string",
                  "description": "Token contract the limit applies to (erc20_transfer_amount only)"
                },
                "maxAmount": {
                  "type": "string",
                  "description": "Ceiling as a decimal string in base units (erc20_transfer_amount, native_transfer_amount)",
                  "example": "1000000000"
                },
                "targets": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Addresses the delegation may call (allowed_targets only)"
                },
                "maxCalls": {
                  "type": "string",
                  "description": "Maximum number of redemptions, decimal string (limited_calls only)"
                },
                "timestampAfter": {
                  "type": "string",
                  "description": "Start of the signed time window, decimal string (timestamp only)"
                },
                "timestampBefore": {
                  "type": "string",
                  "description": "End of the signed time window, decimal string (timestamp only)"
                }
              }
            }
          },
          "declaredLimitsOmitted": {
            "type": "boolean",
            "description": "Present and true when the request set declaredLimits: \"omit\" (erc7710_delegation conditions only). The decoded limits were left out so a forwarded attestation does not carry the principal's spending ceiling. met, delegationHash, and conditionHash are byte-identical to the include case, so the attestation still commits to exactly which delegation was checked."
          },
          "unrecognizedEnforcers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Enforcer addresses that were not recognized, when the condition fails on unknown caveats (present only for erc7710_delegation conditions)"
          },
          "failReason": {
            "type": "string",
            "enum": [
              "delegate_mismatch",
              "principal_mismatch",
              "invalid_signature",
              "delegator_not_deployed",
              "revoked",
              "unknown_caveat_enforcer",
              "outside_time_window"
            ],
            "description": "Why the delegation condition failed (present only for failing erc7710_delegation conditions)"
          },
          "blockNumber": {
            "type": "string",
            "description": "Hex block number at which the condition was evaluated. Present on all 31 EVM chains. Every other chain family carries its own anchor instead: slot (Solana), ledgerIndex (XRPL, Stellar), blockHeight (Bitcoin, Tron), checkpointSequence (Sui). The API refuses to sign any attestation whose anchor could not be captured or whose chain state could not be read, returning 503 instead: a failed read is never reported as met: false.",
            "example": "0x12f4a80"
          },
          "blockTimestamp": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 timestamp of the block at which the condition was evaluated. Present on all 31 EVM chains and co-required with blockNumber.",
            "example": "2026-02-26T12:34:56.000Z"
          },
          "ledgerIndex": {
            "type": "integer",
            "description": "Validated ledger index the result is anchored to. Present only for XRPL and Stellar conditions. On XRPL every read behind the result is pinned to this one validated ledger, so it names the state that was read. On Stellar it is the latest ledger, captured alongside the read: a freshness anchor.",
            "example": 102575456
          },
          "ledgerHash": {
            "type": "string",
            "description": "Hash of the ledger named by ledgerIndex. Present only for XRPL and Stellar conditions.",
            "example": "BB9023D447285923C36E3DF18EF0FC37A5A6A1113527FB5F6FCE3139AAD72388"
          },
          "trustLineState": {
            "type": "object",
            "description": "Trust line state flags for XRPL trust line token conditions. Present only for non-native XRPL token_balance conditions.",
            "properties": {
              "frozen": {
                "type": "boolean",
                "description": "Whether the trust line is frozen: a freeze set on the line by either side, or an issuer that has frozen everything it issued. A frozen line means the balance is not spendable."
              }
            }
          },
          "slot": {
            "type": "integer",
            "description": "Solana slot the result is anchored to. Present only for Solana conditions. It is a floor: the wallet state was observed at this slot or later (across a paged read it is the lowest slot any page reported). Verifiers can reproduce the read by querying wallet state at this slot or later.",
            "example": 338472915
          },
          "blockHeight": {
            "type": "integer",
            "description": "Chain tip block height at the time of wallet state observation. Present only for Bitcoin and Tron conditions. Evidence-of-freshness anchor: the height binds the observation to a recent tip rather than to a specific block's state (Bitcoin's UTXO model does not permit reproducible balance-at-block queries).",
            "example": 946083
          },
          "blockHash": {
            "type": "string",
            "description": "Chain tip block hash at the time of wallet state observation (64-character lowercase hex on Bitcoin). Present only for Bitcoin and Tron conditions. Co-reported with blockHeight.",
            "example": "000000000000000000003c5ff410ed3c66b3cb803c2aac90b5b6600b20ba91e5"
          },
          "checkpointSequence": {
            "type": "integer",
            "description": "Sui checkpoint sequence number, captured alongside the read. A freshness anchor: it binds the observation to a recent checkpoint rather than naming the exact state that was read. Present only for Sui conditions."
          },
          "proof": {
            "description": "Present only when proof: \"merkle\" is requested",
            "oneOf": [
              {
                "$ref": "#/components/schemas/MerkleProof"
              },
              {
                "$ref": "#/components/schemas/MerkleProofUnavailable"
              }
            ]
          }
        }
      },
      "MerkleProof": {
        "type": "object",
        "description": "EIP-1186 Merkle proof for trustless verification against block headers. Four kinds of proof exist today (three carry a subject; the ERC-20 balance-slot proof carries none): a token_balance or ratio_to_amount condition against an ERC-20 proves the balance slot (no subject field; a ratio_to_amount proof proves the same slot a token_balance proof does); the same condition with contractAddress \"native\" proves the account itself (subject: \"account_balance\"): a native balance is a field of the account rather than a mapping entry, so it carries an ACCOUNT proof with no storageProof, mappingSlot or storageKey, and its balance field is the value evaluated; an account_code condition proves the same account record with codeHash as the evaluated field (subject: \"account_code\"); and an erc7710_delegation condition proves the revocation slot (subject: \"delegation_revocation\").",
        "properties": {
          "available": {
            "type": "boolean",
            "const": true
          },
          "type": {
            "type": "string",
            "const": "merkle"
          },
          "balance": {
            "type": "string",
            "description": "Hex-quantity native balance proven by the account branch. Present on subjects \"account_balance\" and \"account_code\" (the record has four fields and a verifier rebuilds all of them). On \"account_balance\" it equals the value the condition was evaluated against at blockNumber, and is served only when the two agree."
          },
          "nonce": {
            "type": "string",
            "description": "Hex-quantity account nonce from the same branch. Present on subjects \"account_balance\" and \"account_code\"."
          },
          "codeHash": {
            "type": "string",
            "description": "Account code hash from the same branch. Present on subjects \"account_balance\" and \"account_code\". On \"account_code\" it is the evaluated field: keccak256 of empty code (0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470) means no code, keccak256 of 0xef0100 followed by the 20-byte target means an EIP-7702 delegation to that target, anything else means contract code; an account absent from the state trie may report it as all zeros, which also means no code. Served only when it agrees with the code the condition was evaluated against."
          },
          "subject": {
            "type": "string",
            "enum": [
              "account_balance",
              "account_code",
              "delegation_revocation"
            ],
            "description": "What the proof is about. Three values today. \"account_balance\" on a token_balance or ratio_to_amount condition whose contractAddress is \"native\": the proof is the account's own branch of the state trie and its balance field is the value evaluated. \"account_code\" on an account_code condition: the same account branch, with codeHash as the value evaluated. \"delegation_revocation\" on an erc7710_delegation condition: the proof covers disabledDelegations[delegationHash] in the DelegationManager's storage. All are against the anchored block's state root. An ERC-20 balance-slot proof carries no subject field, so the field's ABSENCE is what identifies that variant; do not read a missing subject as a delegation proof, or a present one as anything other than the three values above."
          },
          "blockNumber": {
            "type": "string",
            "description": "Hex block number at which the proof was generated",
            "example": "0x12a05f200"
          },
          "contractAddress": {
            "type": "string",
            "description": "The contract whose storage was proven. Present on erc7710_delegation proofs, where it is the DelegationManager the proof is against."
          },
          "mappingSlot": {
            "type": "integer",
            "description": "Storage slot of the proven mapping: the ERC-20 balanceOf mapping for a token_balance or ratio_to_amount proof (both prove the same balance slot), or the disabledDelegations mapping for an erc7710_delegation proof. Never inferred — for delegation proofs the layout is verified on-chain first, and managers without a verified layout return no proof at all."
          },
          "storageKey": {
            "type": "string",
            "description": "keccak256(abi.encode(key, uint256(mappingSlot))) storage key. The key is the wallet address for a token_balance or ratio_to_amount proof, or delegationHash for an erc7710_delegation proof. A verifier SHOULD recompute it from the delegationHash carried in the signed evaluatedCondition and confirm it matches the returned value — that recomputation is what binds the proof to this specific delegation, since a proof of some other slot would still verify against the block header."
          },
          "accountProof": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Merkle proof nodes from state root to account"
          },
          "storageProof": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "key": {
                  "type": "string"
                },
                "value": {
                  "type": "string",
                  "description": "The proven slot value (hex). For a token_balance proof, the raw token balance before decimal division. For an erc7710_delegation proof, 1 means the delegation was revoked and 0 means it was not — and a proven 0 is a positive proof that no revocation exists, not merely a claim that none was found."
                },
                "proof": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              }
            },
            "description": "Merkle proof nodes from storage root to the proven slot"
          },
          "storageHash": {
            "type": "string",
            "description": "Storage root hash of the contract account"
          }
        }
      },
      "MerkleProofUnavailable": {
        "type": "object",
        "description": "Returned when Merkle proof is not available for a condition",
        "properties": {
          "type": {
            "type": "string",
            "const": "merkle",
            "description": "Optional on this variant: some unavailable results (e.g. slot-discovery failures) omit the type field and carry only available and reason."
          },
          "available": {
            "type": "boolean",
            "const": false
          },
          "transient": {
            "type": "boolean",
            "description": "Present when the proof was not produced because of the read rather than a property of the condition. true means a read did not complete and the same request may succeed later. false means the outcome is settled: see unsupportedChain. Absent when the condition itself cannot carry a proof (EAS, Farcaster, erc8004_agent, a zero ERC-20 balance whose storage slot has not yet been discovered, or an unverified DelegationManager). A zero native balance is always provable: its account proof has no storage slot to discover.\n"
          },
          "unsupportedChain": {
            "type": "boolean",
            "description": "Present and true when the chain does not support Merkle storage proofs, so no proof can be produced there and retrying will not change the outcome. Applies to ZKsync Era (324), Sei (1329), Viction (88) and XDC Network (50). The attestation itself is signed and block-anchored as usual, and the proof premium is not charged.\n"
          },
          "reason": {
            "type": "string",
            "description": "Why the proof is unavailable (e.g. a chain that does not support Merkle storage proofs, Solana, nft_ownership, erc8004_agent, a zero ERC-20 balance whose storage slot has not yet been discovered, or an erc7710_delegation whose DelegationManager storage layout has not been verified on-chain)"
          }
        }
      },
      "TrustCheck": {
        "type": "object",
        "properties": {
          "label": {
            "type": "string",
            "description": "Human-readable label (e.g. 'USDC on Ethereum')"
          },
          "chainId": {
            "$ref": "#/components/schemas/ChainId"
          },
          "met": {
            "type": "boolean",
            "description": "Whether the presence check passed: a token balance above zero, an NFT held, or, in the account dimension, contract code or an EIP-7702 delegation present at the wallet address"
          },
          "evaluatedCondition": {
            "$ref": "#/components/schemas/EvaluatedCondition"
          },
          "conditionHash": {
            "type": "string",
            "description": "SHA-256 of canonical evaluatedCondition JSON, 0x-prefixed"
          },
          "evaluated": {
            "type": "boolean",
            "description": "Present, and false, only on a check that could not be evaluated because the wallet its chain needs was not supplied (Solana, XRPL, Bitcoin, Tron, Stellar, Sui entries in the curated set). Such a check stays in the signed profile with met false, carries no anchor, and is counted in notEvaluatedCount rather than passCount or failCount. Absent on every evaluated check.",
            "example": false
          },
          "reason": {
            "type": "string",
            "enum": [
              "wallet_not_provided"
            ],
            "description": "Why the check was not evaluated. Present only with evaluated: false."
          },
          "requires": {
            "type": "string",
            "enum": [
              "solanaWallet",
              "xrplWallet",
              "bitcoinWallet",
              "tronWallet",
              "stellarWallet",
              "suiWallet"
            ],
            "description": "The request parameter that would let this check be evaluated. Present only with evaluated: false."
          },
          "blockNumber": {
            "type": "string",
            "description": "Hex block number at which the check was evaluated. Present on all 31 EVM chains; Solana checks use slot, XRPL checks use ledgerIndex."
          },
          "blockTimestamp": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 timestamp of the block at which the check was evaluated. Present on all 31 EVM chains."
          },
          "ledgerIndex": {
            "type": "integer",
            "description": "Validated ledger index (XRPL and Stellar checks)"
          },
          "ledgerHash": {
            "type": "string",
            "description": "Validated ledger hash (XRPL and Stellar checks)"
          },
          "trustLineState": {
            "type": "object",
            "description": "Trust line state flags (XRPL trust line tokens only). Frozen lines fail attestation.",
            "properties": {
              "frozen": {
                "type": "boolean"
              }
            }
          },
          "slot": {
            "type": "integer",
            "description": "Solana slot the result is anchored to. Present only for Solana conditions. It is a floor: the wallet state was observed at this slot or later (across a paged read it is the lowest slot any page reported). Verifiers can reproduce the read by querying wallet state at this slot or later.",
            "example": 338472915
          },
          "blockHeight": {
            "type": "integer",
            "description": "Chain tip block height at the time of wallet state observation. Present only for Bitcoin and Tron checks. Evidence-of-freshness anchor: the height binds the observation to a recent tip rather than to a specific block's state (Bitcoin's UTXO model does not permit reproducible balance-at-block queries).",
            "example": 946083
          },
          "blockHash": {
            "type": "string",
            "description": "Chain tip block hash at the time of wallet state observation (64-character lowercase hex on Bitcoin). Present only for Bitcoin and Tron checks. Co-reported with blockHeight.",
            "example": "000000000000000000003c5ff410ed3c66b3cb803c2aac90b5b6600b20ba91e5"
          },
          "checkpointSequence": {
            "type": "integer",
            "description": "Sui checkpoint sequence number, captured alongside the read. A freshness anchor: it binds the observation to a recent checkpoint rather than naming the exact state that was read. Present only for Sui checks."
          },
          "proof": {
            "description": "EIP-1186 Merkle storage proof anchored to the block header, enabling trustless verification without re-querying the chain. Present only when proof: 'merkle' is requested.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/MerkleProof"
              },
              {
                "$ref": "#/components/schemas/MerkleProofUnavailable"
              }
            ]
          }
        }
      },
      "TrustDimension": {
        "type": "object",
        "properties": {
          "checks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TrustCheck"
            }
          },
          "passCount": {
            "type": "integer",
            "description": "Number of checks where met is true"
          },
          "failCount": {
            "type": "integer",
            "description": "Number of evaluated checks where met is false"
          },
          "notEvaluatedCount": {
            "type": "integer",
            "description": "Number of checks carrying evaluated: false (wallet for that chain not supplied). passCount + failCount + notEvaluatedCount = total."
          },
          "total": {
            "type": "integer",
            "description": "Total checks in this dimension"
          }
        }
      },
      "Attestation": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Format: ATST- followed by 16 uppercase hex characters",
            "example": "ATST-A7C3E1B2D4F56789"
          },
          "pass": {
            "type": "boolean",
            "description": "true only when ALL conditions are met"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AttestationResult"
            }
          },
          "passCount": {
            "type": "integer"
          },
          "failCount": {
            "type": "integer"
          },
          "attestedAt": {
            "type": "string",
            "format": "date-time"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time",
            "description": "Attestation expires after 30 minutes. Attestations containing an erc7710_delegation condition expire after 5 minutes instead (see POST /v1/attest)."
          }
        }
      },
      "Tier": {
        "type": "object",
        "required": [
          "name",
          "threshold",
          "discount"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 30
          },
          "threshold": {
            "type": "number",
            "exclusiveMinimum": 0
          },
          "discount": {
            "type": "integer",
            "minimum": 1,
            "maximum": 50,
            "description": "Discount percentage: a whole number from 1 to 50, as a JSON number or its digits as a string. A value with a fraction (10.5) is a 400; \"10.0\" is accepted as 10."
          }
        }
      },
      "TokenConfig": {
        "type": "object",
        "required": [
          "symbol",
          "chainId",
          "contractAddress",
          "decimals",
          "tiers"
        ],
        "properties": {
          "symbol": {
            "type": "string",
            "maxLength": 10
          },
          "name": {
            "type": "string",
            "maxLength": 100,
            "description": "Optional display name shown in the public directory listing (without it the entry shows a bare symbol)."
          },
          "logo": {
            "type": "string",
            "maxLength": 500,
            "description": "Optional logo URL shown in the public directory listing."
          },
          "chainId": {
            "$ref": "#/components/schemas/OnboardingChainId"
          },
          "contractAddress": {
            "type": "string",
            "description": "Token address, validated per chain: 0x + 40 hex on EVM chains, or \"native\" for the chain's own coin (ETH on Ethereum or Base, POL on Polygon); on Solana \"native\" for SOL or the mint address (base58, 32 to 44 characters); on XRPL \"native\" for XRP or the issuer r-address, whose base58 checksum is verified. Anything else is a 400."
          },
          "decimals": {
            "type": "integer",
            "minimum": 0,
            "maximum": 18,
            "description": "Token decimals. Required; a missing or non-numeric value is rejected with 400. When a discount is evaluated the token's decimals are read from the chain; this stored value is not used."
          },
          "currency": {
            "type": "string",
            "description": "XRPL trust line currency code (e.g. \"USD\", \"RLUSD\"). Required for XRPL trust line tokens. Enter the currency code exactly as the issuer created it. Codes are case-sensitive, and the code is stored as entered. It is validated by the same rule as the `currency` of an attest condition: a 3-character standard code, a token name of 1 to 20 printable ASCII characters, or a 40-character hex code; anything else is a 400, and so is `XRP`, which is the native coin (use contractAddress \"native\")."
          },
          "tiers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Tier"
            },
            "minItems": 1,
            "maxItems": 4
          },
          "alsoOn": {
            "type": "array",
            "maxItems": 9,
            "description": "Optional. The same token on other networks, each as { chainId, contractAddress }: EVM chains and Solana, not the XRP Ledger and not a chain's native coin. The discount check and the verification (verify, ACP, UCP) read every network listed plus the token's own, add the balances exactly, and award the token's tier once, so the token appears once in the breakdown and uses one of the 8 token slots. The store decides which deployments count as the same token; each network's balance is read in that token's own decimals there. A read that fails on any listed network refuses the whole check (503 rpc_failure), never a total from the networks that answered. Leave it out and only chainId and contractAddress are read, as before. A network listed twice, or already listed by another token, is a 400. Not available on an XRP Ledger token.",
            "items": {
              "type": "object",
              "required": [
                "chainId",
                "contractAddress"
              ],
              "properties": {
                "chainId": {
                  "$ref": "#/components/schemas/OnboardingChainId"
                },
                "contractAddress": {
                  "type": "string",
                  "description": "0x + 40 hex on EVM chains, or the mint address on Solana."
                }
              }
            }
          },
          "enabled": {
            "type": "boolean",
            "default": true,
            "description": "Read on ownToken only. `false` switches the own token off (the same as sending ownToken as null), and the other fields are then not required. `true`, or leaving it out, saves the token switched on. Any other value is a 400; text such as \"true\" or \"false\" is not a boolean."
          }
        }
      },
      "NftConfig": {
        "type": "object",
        "required": [
          "name",
          "contractAddress",
          "chainId"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 50
          },
          "contractAddress": {
            "type": "string",
            "description": "Collection contract address, validated per chain: 0x + 40 hex on EVM chains; a mint address on Solana (base58, 32 to 44 characters; \"native\" is refused); the issuer r-address on XRPL, whose base58 checksum is verified. A malformed address returns 400."
          },
          "chainId": {
            "$ref": "#/components/schemas/OnboardingChainId"
          },
          "taxon": {
            "type": "integer",
            "description": "XRPL NFToken taxon filter. Optional, for filtering NFTs by collection under the same issuer. An integer from 0 to 4294967295; anything else is a 400. The XRPL issuer address is checksum-verified, so a mistyped issuer is a 400."
          },
          "benefitType": {
            "type": "string",
            "enum": [
              "discount",
              "recognition"
            ],
            "default": "discount",
            "description": "What holding the collection grants. \"discount\" applies the configured percentage; \"recognition\" only marks the pass as recognized (door access) and carries no discount."
          },
          "discount": {
            "type": "integer",
            "minimum": 1,
            "maximum": 50,
            "description": "Discount percentage: a whole number from 1 to 50, as a JSON number or its digits as a string. A value with a fraction (10.5) is a 400; \"10.0\" is accepted as 10. Required only when benefitType is \"discount\" (the default); ignored for \"recognition\"."
          },
          "enabled": {
            "type": "boolean",
            "default": true,
            "description": "Merchant's on/off toggle for this collection. Absent means enabled; only an explicit false disables it. A value that is not a boolean is a 400."
          }
        }
      },
      "MerchantSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "companyName": {
            "type": "string"
          },
          "website": {
            "type": "string"
          },
          "location": {
            "type": "string"
          },
          "verified": {
            "type": "boolean"
          },
          "tokens": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "symbol": {
                  "type": "string"
                },
                "maxDiscount": {
                  "type": "integer"
                }
              }
            }
          },
          "nftCollections": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "discount": {
                  "type": "integer"
                }
              }
            }
          },
          "discountMode": {
            "type": "string",
            "enum": [
              "highest",
              "stack",
              "capped"
            ]
          },
          "discountCap": {
            "type": "integer"
          },
          "walletTerms": {
            "$ref": "#/components/schemas/WalletTerms"
          }
        }
      },
      "MerchantDetail": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "companyName": {
            "type": "string"
          },
          "website": {
            "type": "string"
          },
          "location": {
            "type": "string"
          },
          "verified": {
            "type": "boolean"
          },
          "verifiedDomain": {
            "type": "string"
          },
          "discountMode": {
            "type": "string",
            "enum": [
              "highest",
              "stack",
              "capped"
            ],
            "description": "The merchant's stored discount mode, returned as configured."
          },
          "discountCap": {
            "type": "integer"
          },
          "tokens": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "ownToken": {
            "type": "object",
            "nullable": true
          },
          "partnerTokens": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "nftCollections": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "acceptsUsdc": {
            "type": "boolean"
          },
          "walletTerms": {
            "$ref": "#/components/schemas/WalletTerms"
          }
        }
      },
      "WalletProof": {
        "type": "object",
        "description": "Optional proof that the caller controls the EVM wallet named in `wallet`: an EIP-4361 (Sign-In with Ethereum) message signed by that wallet (EIP-191; smart-contract wallets are not accepted yet). The message must use domain `api.insumermodel.com` or the merchant's own website (a wallet asked to sign in the store's page expects the page's own site), the wallet as its address, URI `https://api.insumermodel.com/v1/merchants/{merchantId}`, an Issued At within the last 5 minutes, and a nonce not used before. A proven wallet gets the full discount its holdings earn (under the store's tiers and cap), without the daily limit for unproven wallets. A proof object without a string `message` and `signature` is a 400; a proof that does not verify is a 401, never a quiet fallback to the unproven terms. Neither uses a credit. Send it with `wallet` only: a request with a proof and `solanaWallet` or `xrplWallet` is a 400.\n",
        "required": [
          "message",
          "signature"
        ],
        "properties": {
          "message": {
            "type": "string",
            "description": "The EIP-4361 message, exactly as signed."
          },
          "signature": {
            "type": "string",
            "description": "The wallet's signature over the message (0x hex)."
          }
        }
      },
      "WalletTerms": {
        "type": "object",
        "description": "What this store gives a wallet with and without proof of control, so an agent can decide before calling whether to sign. A proven wallet gets the full discount its holdings earn (under the store's tiers and cap), without the daily limit for unproven wallets.\n",
        "properties": {
          "proofAccepted": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Wallet types whose proof is accepted. Currently [\"evm\"]."
          },
          "proven": {
            "type": "object",
            "properties": {
              "maxDiscountsPerWalletPerDay": {
                "type": "null",
                "description": "Always null: no daily limit for a proven wallet."
              }
            }
          },
          "unproven": {
            "type": "object",
            "properties": {
              "maxDiscount": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "At most this percent without proof; 0 = no discount; null = the same as proven."
              },
              "maxDiscountsPerWalletPerDay": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "Discount codes per unproven wallet per UTC day; null = no limit."
              }
            }
          }
        }
      },
      "DiscountBreakdown": {
        "type": "object",
        "properties": {
          "symbol": {
            "type": "string"
          },
          "tier": {
            "type": "string"
          },
          "discount": {
            "type": "integer"
          },
          "chain": {
            "type": "string",
            "description": "Chain name (present only in GET /v1/discount/check responses, omitted in /v1/verify, /v1/acp/discount, /v1/ucp/discount). A token configured with alsoOn and held on more than one of its networks lists them, comma-separated (\"Ethereum, Arbitrum\")."
          }
        }
      },
      "ComplianceTemplate": {
        "type": "object",
        "properties": {
          "provider": {
            "type": "string",
            "description": "KYC provider name",
            "example": "Coinbase"
          },
          "description": {
            "type": "string",
            "description": "Human-readable description of what this template verifies",
            "example": "Verified account (KYC completed)"
          },
          "chainId": {
            "type": "integer",
            "description": "EVM chain where the attestation lives",
            "example": 8453
          },
          "chainName": {
            "type": "string",
            "description": "Human-readable chain name",
            "example": "Base"
          }
        }
      }
    }
  },
  "paths": {
    "/v1/jwks": {
      "get": {
        "operationId": "getJwks",
        "summary": "Get JWKS (public key set)",
        "description": "Returns the JSON Web Key Set containing InsumerAPI's two public signing keys. Use this to verify attestation and trust-profile signatures without hardcoding a key. Five entries are published. Three `kid` labels point at the SAME ECDSA P-256 key: `insumer-attest-v1` (v1 attest, v1 trust, and all commerce discount responses regardless of key generation), `insumer-attest-v2` (v2 attest), `insumer-trust-v2` (v2 trust). They are followed by two RFC 9964 `AKP` entries for the ML-DSA-65 post-quantum signature key, `insumer-attest-pq1` and `insumer-trust-pq1`, appended after the EC entries. Resolve the key by the `kid` (or `pqKid`) on the response you are verifying, never by position; an unknown kid is unverifiable, not refuted. The `kid` also tells you which verification rules to apply (see the `sig` notes on /v1/attest). Keys are never removed: a rotated key stays in this set permanently under its original `kid`, so attestations kept as records remain verifiable. No authentication required. Cached for 24 hours.\n",
        "tags": [
          "Wallet Auth"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "JWKS document",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "example": "public, max-age=86400"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "keys": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "kty": {
                            "type": "string",
                            "description": "EC on the three classical entries; AKP (RFC 9964) on the two post-quantum entries",
                            "example": "EC"
                          },
                          "crv": {
                            "type": "string",
                            "example": "P-256"
                          },
                          "x": {
                            "type": "string",
                            "description": "Base64url-encoded x coordinate"
                          },
                          "y": {
                            "type": "string",
                            "description": "Base64url-encoded y coordinate"
                          },
                          "use": {
                            "type": "string",
                            "example": "sig"
                          },
                          "alg": {
                            "type": "string",
                            "description": "ES256 on the EC entries; ML-DSA-65 (FIPS 204) on the AKP entries",
                            "example": "ES256"
                          },
                          "pub": {
                            "type": "string",
                            "description": "Base64url ML-DSA-65 public key; present only on the AKP entries (which carry no crv, x or y)"
                          },
                          "kid": {
                            "type": "string",
                            "description": "One of: insumer-attest-v1, insumer-attest-v2, insumer-trust-v2 (all the same EC key; post-quantum AKP entries, kid insumer-attest-pq1 / insumer-trust-pq1, are appended after them).",
                            "example": "insumer-attest-v1"
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "keys": [
                    {
                      "kty": "EC",
                      "crv": "P-256",
                      "x": "...",
                      "y": "...",
                      "use": "sig",
                      "alg": "ES256",
                      "kid": "insumer-attest-v1"
                    },
                    {
                      "kty": "EC",
                      "crv": "P-256",
                      "x": "...",
                      "y": "...",
                      "use": "sig",
                      "alg": "ES256",
                      "kid": "insumer-attest-v2"
                    },
                    {
                      "kty": "EC",
                      "crv": "P-256",
                      "x": "...",
                      "y": "...",
                      "use": "sig",
                      "alg": "ES256",
                      "kid": "insumer-trust-v2"
                    },
                    {
                      "kty": "AKP",
                      "alg": "ML-DSA-65",
                      "pub": "...",
                      "use": "sig",
                      "kid": "insumer-attest-pq1"
                    },
                    {
                      "kty": "AKP",
                      "alg": "ML-DSA-65",
                      "pub": "...",
                      "use": "sig",
                      "kid": "insumer-trust-pq1"
                    }
                  ]
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/compliance/templates": {
      "get": {
        "operationId": "listComplianceTemplates",
        "summary": "List compliance templates",
        "description": "Returns pre-configured compliance templates for common KYC/identity providers. Templates abstract away raw EAS schema IDs and attester addresses. Use a template name in POST /v1/attest conditions instead of specifying schemaId, attester, and indexer manually. No authentication required.\n",
        "tags": [
          "Wallet Auth"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Template catalog",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "example": "public, max-age=3600"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "templates": {
                          "type": "object",
                          "additionalProperties": {
                            "$ref": "#/components/schemas/ComplianceTemplate"
                          }
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "data": {
                    "templates": {
                      "coinbase_verified_account": {
                        "provider": "Coinbase",
                        "description": "Coinbase Verified Account",
                        "chainId": 8453,
                        "chainName": "Base"
                      },
                      "coinbase_verified_country": {
                        "provider": "Coinbase",
                        "description": "Coinbase Verified Country",
                        "chainId": 8453,
                        "chainName": "Base"
                      },
                      "coinbase_one": {
                        "provider": "Coinbase",
                        "description": "Coinbase One Member",
                        "chainId": 8453,
                        "chainName": "Base"
                      },
                      "gitcoin_passport_score": {
                        "provider": "Gitcoin",
                        "description": "Gitcoin Passport Score (≥20)",
                        "chainId": 10,
                        "chainName": "Optimism"
                      },
                      "gitcoin_passport_active": {
                        "provider": "Gitcoin",
                        "description": "Gitcoin Passport Active",
                        "chainId": 10,
                        "chainName": "Optimism"
                      }
                    }
                  },
                  "meta": {
                    "version": "1.0",
                    "timestamp": "2026-02-27T12:00:00.000Z"
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/attest": {
      "post": {
        "operationId": "createAttestation",
        "x-payment-info": {
          "price": {
            "mode": "dynamic",
            "currency": "USD",
            "min": "0.05",
            "max": "0.10"
          },
          "protocols": [
            {
              "x402": {}
            }
          ]
        },
        "summary": "Create on-chain verification",
        "description": "Verify 1-10 on-chain conditions: token balances, NFT ownership, EAS attestations, Farcaster identity, arbitrary boolean view calls (evm_view_call), the dimensionless ratio rules (ratio_to_amount, ratio_to_supply), account code (account_code: is the wallet a plain key, an EIP-7702-delegated key, or a contract, optionally delegated to a named address), and agent standing (erc8004_agent, erc7710_delegation). Returns ECDSA-signed booleans, never raw balances or code. 1 credit standard, 2 with proof=\"merkle\". EAS: use a compliance template or raw schemaId. Agent conditions, generally available on any API key: erc8004_agent (is this wallet a registered ERC-8004 agent — owner of or bound to agentId N in the Identity Registry on Base) and erc7710_delegation (is this signed ERC-7710 delegation from principal P to this agent wallet currently valid, and what limits does it declare). Both are Base (8453) only and cost 1 credit. erc8004_agent does not support Merkle proofs. erc7710_delegation does: proof=\"merkle\" returns an EIP-1186 storage proof of the revocation slot (subject \"delegation_revocation\", 2 credits), on DelegationManagers whose storage layout has been verified on-chain — currently the v1.3.0 manager on Base. Both are also reachable with no API key at all via x402 pay-per-call: call with no credential headers, take the 402 quote, pay the quoted amount in USDC on Base, Polygon, Arbitrum, Arc, or Solana, and retry with the PAYMENT-SIGNATURE header — $0.05 at the standard per-call rate. Account code, generally available on any API key and on x402: account_code (what code sits at the wallet address itself at the anchored block: expect \"none\", \"eip7702\" or \"contract\", and with \"eip7702\" an optional delegate the designator must point at). Any EVM chain, 1 credit, answered as met only; the code and the delegation target are never returned. A trust profile reports the same two facts (contract code present, EIP-7702 delegation present) per chain in its account dimension without naming a target; this condition is where a caller asks about a named one. Attestations containing an erc7710_delegation condition expire in 5 minutes (not the standard 30) — revocation is one transaction away, so the verdict window stays tight. On a delegation, met is the verdict; declaredLimits is a separate signed decode of the caveat terms the caller submitted, each entry carrying the raw terms hex so the decode can be checked independently. Send declaredLimits: \"omit\" to leave that decode out of a forwarded attestation. Authentication: this endpoint accepts EITHER the X-API-Key header OR the Authorization: Wallet header (SIWE envelope from a wallet that holds the Insumer Access pass).\n",
        "tags": [
          "Wallet Auth"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "WalletAuth": []
          }
        ],
        "parameters": [
          {
            "name": "proof",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "merkle"
              ]
            },
            "description": "Query-string alternative to the body proof field: ?proof=merkle enables proof mode on this endpoint too (body or query, either works; the body field takes precedence when both are present). This endpoint only; POST /v1/trust and POST /v1/trust/batch read proof from the body alone."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "conditions"
                ],
                "properties": {
                  "wallet": {
                    "type": "string",
                    "description": "EVM wallet address (0x...)"
                  },
                  "solanaWallet": {
                    "type": "string",
                    "description": "Solana wallet address (base58, 32-44 chars). Required if any condition uses chainId \"solana\"."
                  },
                  "xrplWallet": {
                    "type": "string",
                    "description": "XRPL wallet address (classic r-address). The base58 checksum is verified; an address that fails it returns 400 rather than a signed not-met result.",
                    "example": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"
                  },
                  "bitcoinWallet": {
                    "type": "string",
                    "description": "Bitcoin address (P2PKH, P2SH, bech32, or Taproot). Required if any condition uses chainId \"bitcoin\".",
                    "example": "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq"
                  },
                  "tronWallet": {
                    "type": "string",
                    "description": "Tron address (T-prefix, base58, 34 chars). Required if any condition uses chainId \"tron\". Tron supports TRC-20 (e.g. USDT) and native TRX via contractAddress \"native\".",
                    "example": "TWdcgk9NLsxKr3z3UELq3vCgsx9wU2cFhB"
                  },
                  "stellarWallet": {
                    "type": "string",
                    "description": "Stellar address (G-prefix StrKey, 56 chars; the checksum is verified). Required if any condition uses chainId \"stellar\". Stellar checks measure classic-account balances (trustlines + native XLM); Soroban contract-held balances are out of scope. Trustline conditions require both contractAddress (G-issuer) and assetCode.",
                    "example": "GB3ZDBVMNFADCPKRVDSTTPW7QQTWD7EAQQ3DCKG74MEALLWYGMPIP6M2"
                  },
                  "suiWallet": {
                    "type": "string",
                    "description": "Sui address (0x + 64 hex chars, 32-byte). Required if any condition uses chainId \"sui\". Coin type goes in contractAddress (e.g., \"0x2::sui::SUI\" for native, or \"<package>::<module>::<TYPE>\" for any other coin). Response envelope surfaces checkpointSequence as the temporal anchor.",
                    "example": "0x0000000000000000000000000000000000000000000000000000000000000005"
                  },
                  "proof": {
                    "type": "string",
                    "enum": [
                      "merkle"
                    ],
                    "description": "Set to \"merkle\" to include EIP-1186 Merkle storage proofs in results. Proofs are attempted for token_balance and ratio_to_amount conditions on all 31 EVM chains (a ratio_to_amount proof proves the same ERC-20 balance slot), and returned for erc7710_delegation conditions on DelegationManagers whose storage layout has been verified on-chain (currently the v1.3.0 manager on Base). A delegation proof carries subject: \"delegation_revocation\" and proves the value of disabledDelegations[delegationHash] against the anchored block's state root — so \"not revoked as of block N\" becomes checkable rather than taken on the API's word. Where a chain cannot serve a proof, or the token's storage slot cannot be discovered (a zero ERC-20 balance whose slot is not yet known, or a non-standard storage layout), the result carries proof.available: false with a reason instead. In practice 27 of the 31 EVM chains serve proofs today; ZKsync Era (324), Sei (1329), Viction (88) and XDC Network (50) do not. Always unavailable: nft_ownership, eas_attestation, farcaster_id, ratio_to_supply, and erc8004_agent conditions; conditions on Solana, XRPL, Bitcoin, Tron, Stellar, and Sui; and delegations against a manager whose layout has not been verified (an inferred slot would yield a proof of the wrong location that still verifies against the header, which is worse than no proof). Costs 2 credits instead of 1; whenever no proof is delivered the premium is refunded and the request costs 1, whatever the reason: a read that did not complete, a chain or token that cannot carry a proof, or a condition type that has none. A condition with contractAddress \"native\" carries an ACCOUNT proof (subject \"account_balance\") instead of a storage proof. An account_code condition carries an account proof too (subject \"account_code\"): its codeHash field is the proven value, which a verifier compares with the hash the expected state implies (keccak256 of empty code for \"none\", keccak256 of 0xef0100 followed by the delegate the verifier supplies for \"eip7702\", anything else for \"contract\"); an account absent from the state trie may report codeHash as all zeros, which also means no code. Note: in proof mode the account record's fields (balance, nonce, storageHash, codeHash) reach the caller; on a token_balance condition that is the raw on-chain balance (standard mode never returns it).\n"
                  },
                  "format": {
                    "type": "string",
                    "enum": [
                      "jwt"
                    ],
                    "description": "Set to \"jwt\" to include a Wallet Auth by InsumerAPI token (ES256-signed JWT) in the response. The JWT contains the attestation data as standard claims (iss, sub, jti, iat, exp) plus pass, results, conditionHash, blockNumber, and blockTimestamp. sub is the wallet a condition in the request evaluated. A wallet field that no condition reads is ignored and never named. When conditions span chain families, sub names the first evaluated family in the order EVM, Solana, XRPL, Bitcoin, Tron, Stellar, Sui; the other families' wallets are evaluated but not named by sub. format \"jwt\" needs at least one condition that evaluates a wallet. The exp claim matches the attestation's expiresAt: iat + 1800 (30 minutes), or iat + 300 (5 minutes) when the request contains an erc7710_delegation condition, so a JWT never outlives the attestation it carries. Verifiable by any standard JWT library using the JWKS at https://insumermodel.com/.well-known/jwks.json. No additional cost.\n"
                  },
                  "declaredLimits": {
                    "type": "string",
                    "enum": [
                      "include",
                      "omit"
                    ],
                    "default": "include",
                    "description": "Controls whether decoded caveat limits ride along with erc7710_delegation results. Default (field absent, or \"include\"): declaredLimits are returned inside the signed results, and therefore also travel inside the portable JWT when format: \"jwt\" is used. Set to \"omit\" and the decoded limits are left out; the result carries declaredLimitsOmitted: true instead. Use \"omit\" when the attestation will be FORWARDED to third parties and the principal's spending ceiling should not travel with it — a delegation attestation in JWT form is portable, so by default the declared limits reach anyone it is passed to. That is usually what you want (a relying party needs the limits to act), but not always. The caller loses nothing by omitting: it submitted the caveats and already holds them. Critically, met, delegationHash, and conditionHash are byte-identical either way — a forwarded token still commits to exactly which delegation was checked, and a holder can verify a limit shown to them out-of-band without ever learning one from the token. No effect on any other condition type. No additional cost.\n"
                  },
                  "conditions": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/Condition"
                    },
                    "minItems": 1,
                    "maxItems": 10
                  }
                }
              },
              "examples": {
                "standard": {
                  "summary": "Standard attestation (boolean only)",
                  "value": {
                    "wallet": "0x1234567890abcdef1234567890abcdef12345678",
                    "conditions": [
                      {
                        "type": "token_balance",
                        "contractAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
                        "chainId": 1,
                        "threshold": "1000",
                        "label": "USDC >= 1000"
                      },
                      {
                        "type": "nft_ownership",
                        "contractAddress": "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D",
                        "chainId": 1,
                        "label": "Bored Ape holder"
                      }
                    ]
                  }
                },
                "eas_template": {
                  "summary": "EAS attestation via compliance template",
                  "value": {
                    "wallet": "0x1234567890abcdef1234567890abcdef12345678",
                    "conditions": [
                      {
                        "type": "eas_attestation",
                        "template": "coinbase_verified_account",
                        "label": "Coinbase KYC verified"
                      }
                    ]
                  }
                },
                "eas_raw": {
                  "summary": "EAS attestation with raw schema ID",
                  "value": {
                    "wallet": "0x1234567890abcdef1234567890abcdef12345678",
                    "conditions": [
                      {
                        "type": "eas_attestation",
                        "schemaId": "0xf8b05c79f090979bf4a80270aba232dff11a10d9ca55c4f88de95317970f0de9",
                        "attester": "0x357458739F90461b99789350868CD7CF330Dd7EE",
                        "indexer": "0x2c7eE1E5f416dfF40054c27A62f7B357C4E8619C",
                        "chainId": 8453,
                        "label": "Coinbase Verified Account"
                      }
                    ]
                  }
                },
                "xrpl": {
                  "summary": "XRPL attestation (XRP + RLUSD + USDC)",
                  "value": {
                    "xrplWallet": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
                    "conditions": [
                      {
                        "type": "token_balance",
                        "contractAddress": "native",
                        "chainId": "xrpl",
                        "threshold": "100",
                        "label": "XRP >= 100"
                      },
                      {
                        "type": "token_balance",
                        "contractAddress": "rMxCKbEDwqr76QuheSUMdEGf4B9xJ8m5De",
                        "chainId": "xrpl",
                        "currency": "RLUSD",
                        "threshold": "50",
                        "label": "RLUSD >= 50"
                      },
                      {
                        "type": "token_balance",
                        "contractAddress": "rGm7WCVp9gb4jZHWTEtGUr4dd74z2XuWhE",
                        "chainId": "xrpl",
                        "currency": "USDC",
                        "threshold": "100",
                        "label": "USDC on XRPL >= 100"
                      }
                    ]
                  }
                },
                "erc8004_agent": {
                  "summary": "ERC-8004 agent registration",
                  "value": {
                    "wallet": "0x1234567890abcdef1234567890abcdef12345678",
                    "conditions": [
                      {
                        "type": "erc8004_agent",
                        "chainId": 8453,
                        "agentId": "123",
                        "label": "Registered agent"
                      }
                    ]
                  }
                },
                "erc7710_delegation": {
                  "summary": "ERC-7710 delegation validity",
                  "value": {
                    "wallet": "0xAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAa",
                    "conditions": [
                      {
                        "type": "erc7710_delegation",
                        "chainId": 8453,
                        "delegationManager": "0xdb9B1e94B5b69Df7e401DDbedE43491141047dB3",
                        "expectedDelegator": "0xBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBb",
                        "delegation": {
                          "delegator": "0xBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBb",
                          "delegate": "0xAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAa",
                          "authority": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
                          "caveats": [
                            {
                              "enforcer": "0xCcCcCcCcCcCcCcCcCcCcCcCcCcCcCcCcCcCcCcCc",
                              "terms": "0x00000000000000000000000000000000000000000000000000000000000f4240"
                            }
                          ],
                          "salt": "42",
                          "signature": "0x1b2c3d4e5f60"
                        },
                        "label": "Authorized by principal"
                      }
                    ]
                  }
                },
                "declared_limits_omit": {
                  "summary": "Delegation attestation with declared limits omitted (for forwarding)",
                  "description": "Shows the request shape only. declaredLimits appears in results only when the delegation itself validates (signature and revocation checks pass), so this placeholder delegation would yield a signed met: false with no decode to omit; a real signed delegation is needed to see declaredLimitsOmitted: true.",
                  "value": {
                    "wallet": "0xAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAa",
                    "format": "jwt",
                    "declaredLimits": "omit",
                    "conditions": [
                      {
                        "type": "erc7710_delegation",
                        "chainId": 8453,
                        "delegationManager": "0xdb9B1e94B5b69Df7e401DDbedE43491141047dB3",
                        "expectedDelegator": "0xBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBb",
                        "delegation": {
                          "delegator": "0xBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBb",
                          "delegate": "0xAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAa",
                          "authority": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
                          "caveats": [
                            {
                              "enforcer": "0xf100b0819427117ecf76ed94b358b1a5b5c6d2fc",
                              "terms": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913000000000000000000000000000000000000000000000000000000003b9aca00"
                            }
                          ],
                          "salt": "42",
                          "signature": "0x1b2c3d4e5f60"
                        },
                        "label": "Authorized by principal"
                      }
                    ]
                  }
                },
                "account_code": {
                  "summary": "Account code state (EIP-7702 delegation on Base)",
                  "description": "Is this address a key that delegated execution under EIP-7702? vitalik.eth carries the designator on Base, so this returns met: true. expect \"none\" asks for a plain key and \"contract\" for any other code; add delegate (an address) to require that the designator points at it. The response says only yes or no: the code and the delegation target are never returned.",
                  "value": {
                    "wallet": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
                    "conditions": [
                      {
                        "type": "account_code",
                        "chainId": 8453,
                        "expect": "eip7702",
                        "label": "Delegated key on Base"
                      }
                    ]
                  }
                },
                "jwt_format": {
                  "summary": "Attestation with Wallet Auth token",
                  "value": {
                    "wallet": "0x1234567890abcdef1234567890abcdef12345678",
                    "format": "jwt",
                    "conditions": [
                      {
                        "type": "token_balance",
                        "contractAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
                        "chainId": 1,
                        "threshold": "1000",
                        "label": "USDC >= 1000"
                      }
                    ]
                  }
                },
                "merkle_proof": {
                  "summary": "Attestation with Merkle storage proofs",
                  "value": {
                    "wallet": "0x1234567890abcdef1234567890abcdef12345678",
                    "proof": "merkle",
                    "conditions": [
                      {
                        "type": "token_balance",
                        "contractAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
                        "chainId": 1,
                        "threshold": "1000",
                        "label": "USDC >= 1000"
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verification created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "attestation": {
                          "$ref": "#/components/schemas/Attestation"
                        },
                        "sig": {
                          "type": "string",
                          "description": "ECDSA P-256 signature (base64, P1363). Branch on `kid` to reconstruct the signed bytes: `insumer-attest-v1` → ES256 over JSON.stringify({id, pass, results, attestedAt}); `insumer-attest-v2` → ES256 over the domain-separated, canonical preimage \"insumer.attestation.v2\\n\" + recursive sorted-key canonical JSON of {v:2, id, pass, results, attestedAt} (keys sorted at every level, no whitespace: this is the RFC 8785 / JCS canonical form, so any RFC 8785 serializer reproduces the bytes; all quantities are decimal strings and the only JSON numbers are bounded small integers, so the bytes never depend on a language's floating-point formatting), where the v2 `results[].evaluatedCondition.threshold` is a canonical decimal string and carries no `decimals` field. v1 stays byte-frozen. Verify with `npm install insumer-verify` or `pip install insumer-verify`.\n"
                        },
                        "kid": {
                          "type": "string",
                          "description": "Which key + scheme signed this response. insumer-attest-v1 (v1 attest) or insumer-attest-v2 (v2 attest). Resolve the public key from GET /v1/jwks or https://insumermodel.com/.well-known/jwks.json (all EC kids share one key; post-quantum AKP entries are appended after them)."
                        },
                        "pqSig": {
                          "type": "string",
                          "description": "OPTIONAL post-quantum signature: base64 ML-DSA-65 (FIPS 204) over the post-quantum domain tag plus the exact classical preimage this response's kid selects. A kid a verifier does not recognise selects no preimage, so the post-quantum signature is then unverifiable, never refuted, and no other era's preimage may be substituted for it. Additive; sig and kid are unchanged. See the state attestation spec, Section 12 Check 6."
                        },
                        "pqKid": {
                          "type": "string",
                          "description": "OPTIONAL post-quantum key identifier (insumer-attest-pq1 or insumer-trust-pq1), resolved in the JWKS as an RFC 9964 AKP / ML-DSA-65 key.",
                          "example": "insumer-attest-pq1"
                        },
                        "jwt": {
                          "type": "string",
                          "description": "Wallet Auth by InsumerAPI token — ES256 JWT (only present when format: \"jwt\" is requested). Verifiable with any standard JWT library using the JWKS endpoint."
                        },
                        "pqJwt": {
                          "type": "string",
                          "description": "OPTIONAL sibling of `jwt` when format is `jwt`: a compact JWS with alg ML-DSA-65 (RFC 9964), signed under the post-quantum key insumer-attest-pq1. Additive; `jwt` is unchanged. Verifier contract: after verifying the JWS over its own header.payload bytes, confirm that its payload and the ES256 `jwt` payload carry the identical claim set: the same member names, and for every member a deeply equal JSON value (objects compared without regard to member order, arrays in order, numbers by value). Any difference, whether a changed value, a missing member or an extra member on either side, makes the post-quantum signature `refuted`. Compare PARSED JSON, never bytes: byte-identical payload segments satisfy this trivially, but a verifier MUST NOT require byte identity, since two serializers may order members differently. Checking only `jti`, `exp` and `pass` is not sufficient: it leaves `results` and `conditionHash` unbound. See the state attestation spec, Section 12 Check 6, and test vectors 24 and 25 (the refused cases).\n"
                        }
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "creditsRemaining": {
                          "type": [
                            "integer",
                            "null"
                          ],
                          "description": "Credits left on the key after this call. null on x402-paid calls (creditsCharged is 0 there; the call was paid at the transport layer, not from stored credits)."
                        },
                        "creditsCharged": {
                          "type": "integer",
                          "description": "1 for standard, 2 for proof: merkle. 0 on x402-paid calls."
                        },
                        "version": {
                          "type": "string"
                        },
                        "timestamp": {
                          "type": "string",
                          "format": "date-time"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error. Beyond the usual per-field checks, one case is easy to hit by writing a reasonable-looking rule: on a chain whose native asset is also an ERC-20 at a mirror contract (Celo, Arc — see contractAddress), two token_balance conditions requiring both \"native\" and that address read one balance twice, and are refused naming both condition indexes before any credit is charged. Scale and coin type are checked too: a decimals value that differs from the token's own (the message names the token's own value), a decimals value that is not an integer from 0 to 100, a ratio_to_amount amount with more decimal places than the token has, a non-zero balance of a token that states no usable decimals on chain, and a Sui contractAddress that is not a coin type are each a 400. A token whose decimals cannot be read is the 503 rpc_failure instead, never a 400.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "402": {
            "description": "Payment required. For API-key callers: insufficient verification credits (standard error envelope). For credential-less callers this is the x402 pay-per-call quote (X402Quote body): the v2 payment payload is in the JSON body and, base64-encoded, in the payment-required response header. Pay the quoted amount in USDC on any listed network (Base, Polygon, Arbitrum, Arc, or Solana) and retry with the PAYMENT-SIGNATURE header (X-PAYMENT is still accepted).",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ErrorEnvelope"
                    },
                    {
                      "$ref": "#/components/schemas/X402Quote"
                    }
                  ]
                }
              }
            }
          },
          "413": {
            "description": "Body exceeds the pay-per-call size cap. Returned on x402-paid requests whose JSON body is larger than the cap; API-key and wallet-auth calls are not subject to it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "description": "Data source unavailable after retries (RpcFailureEnvelope; no attestation signed, no credits charged, retryable after a short delay). Wallet-auth and x402-paid calls can also return 503 as a standard error envelope for transient service conditions (for example the wallet-auth nonce store or payment verification being temporarily unavailable); those are equally retryable. On an Arc (eip155:5042) pay-per-call payment, a 503 can also mean the settlement was submitted but had not confirmed by the server's deadline, or the payment facilitator did not answer. That payment is UNRESOLVED, not refused: the transfer may still land. Retry the exact same request (same body) with the SAME payment header; it resolves to the same payment and cannot charge twice. Do not sign a new authorization. If the payment ultimately failed, the retry returns 402 with a fresh quote and nothing was charged.\n",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/RpcFailureEnvelope"
                    },
                    {
                      "$ref": "#/components/schemas/ErrorEnvelope"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/v1/trust": {
      "post": {
        "operationId": "walletTrust",
        "x-payment-info": {
          "price": {
            "mode": "dynamic",
            "currency": "USD",
            "min": "0.15",
            "max": "0.30"
          },
          "protocols": [
            {
              "x402": {}
            }
          ]
        },
        "summary": "Wallet trust fact profile",
        "description": "ECDSA-signed wallet trust profile: 155 base checks across 27 chains in 10 dimensions (stablecoins, governance, nfts, staking, institutional_stablecoins, tokenized_treasuries, stablecoin_deposits, wrapped_bitcoin, names, account), plus optional solana (14 checks), xrpl (RLUSD, USDC, OUSG), bitcoin (native BTC) and tron (USDT, USD1, WBTC) dimensions: up to 176 checks across 29 chains in 14 dimensions. Every row is a presence check (token balance above zero, NFT held, or, in the account dimension, contract code or an EIP-7702 delegation present at the wallet address on Ethereum, Base, Arbitrum, Optimism and Polygon). Returns per-check booleans and overall summary. Dimensions come back in a fixed order (the published table's), the same for every wallet. conditionSetVersion \"2026-10-08\" names the check list that was run; readers may log it. Signature verification must not reject a result solely because the condition-set version is unfamiliar; an application may still require a particular set for its own policy. 3 credits standard, 6 with proof=\"merkle\". Authentication: this endpoint accepts EITHER the X-API-Key header OR the Authorization: Wallet header (SIWE envelope from a wallet that holds the Insumer Access pass).\n",
        "tags": [
          "Trust Fact Profiles"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "WalletAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "wallet"
                ],
                "properties": {
                  "wallet": {
                    "type": "string",
                    "pattern": "^0x[a-fA-F0-9]{40}$",
                    "description": "EVM wallet address to profile (required)",
                    "example": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
                  },
                  "solanaWallet": {
                    "type": "string",
                    "description": "Optional Solana wallet address (base58). If provided, adds the 14-check solana dimension (USDC, OUSD, PYUSD, USDG, USD1, USDS, EURC, BUIDL, USDY, cbBTC, WBTC, tBTC, jitoSOL, mSOL) and evaluates the two Solana entries in institutional_stablecoins."
                  },
                  "xrplWallet": {
                    "type": "string",
                    "description": "Optional XRPL wallet address (classic r-address). If provided, adds the xrpl dimension (RLUSD, USDC, OUSG) and evaluates the EURCV on XRPL entry in institutional_stablecoins. The base58 checksum is verified; an address that fails it returns 400."
                  },
                  "bitcoinWallet": {
                    "type": "string",
                    "description": "Optional Bitcoin address. If provided, adds the bitcoin dimension (native BTC presence check)."
                  },
                  "tronWallet": {
                    "type": "string",
                    "description": "Optional Tron address (T-prefix, 34 chars). If provided, adds the tron dimension (USDT, USD1, WBTC on Tron)."
                  },
                  "stellarWallet": {
                    "type": "string",
                    "description": "Optional Stellar address (G-prefix, 56 chars; the checksum is verified, and a malformed address is a 400, never silently skipped). If provided, USDC and BENJI on Stellar are evaluated in the institutional_stablecoins dimension. Classic-account balances only — Soroban contracts out of scope."
                  },
                  "suiWallet": {
                    "type": "string",
                    "description": "Optional Sui address (0x + 64 hex chars). If provided, USDC on Sui (institutional_stablecoins) and USDY on Sui (tokenized_treasuries) are evaluated."
                  },
                  "proof": {
                    "type": "string",
                    "enum": [
                      "merkle"
                    ],
                    "description": "Set to 'merkle' for EIP-1186 storage proofs. EVM token rows carry a storage proof when the token's balance slot can be discovered; rows whose balance is computed rather than stored (Aave aTokens, BUIDL) and tokens with non-standard storage layouts are declined with a stated reason; NFT, non-EVM and account rows are declined (account rows with a reason pointing at /v1/attest); a check that was not evaluated carries no proof key at all; the premium is refunded whenever no proof is delivered. 6 credits."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Trust fact profile generated",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "trust": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string",
                              "description": "Trust profile ID (format: TRST-XXXXX)",
                              "example": "TRST-A1B2C"
                            },
                            "wallet": {
                              "type": "string"
                            },
                            "conditionSetVersion": {
                              "type": "string",
                              "description": "Dated identifier of the curated check list that was run (currently 2026-10-08). The same value on every key version, v1 and v2 alike; inside the signed payload; bumped whenever a row is added or removed. Readers may log it. Signature verification must not reject a result solely because the condition-set version is unfamiliar. An application may still require a particular set for its own policy. The kid, not this field, selects the signing preimage.",
                              "example": "2026-10-08"
                            },
                            "dimensions": {
                              "type": "object",
                              "description": "Checks organized by dimension. The dimension keys come in a fixed order: the ten base dimensions in the order listed here, then any of solana, xrpl, bitcoin and tron that were switched on, in that order; the same order for every wallet. Readers may still look dimensions up by name. The order of checks inside a dimension is stable and matches the published table. Ten base dimensions are always present; solana, xrpl, bitcoin and tron appear only when their wallet parameter is supplied.",
                              "properties": {
                                "stablecoins": {
                                  "$ref": "#/components/schemas/TrustDimension"
                                },
                                "governance": {
                                  "$ref": "#/components/schemas/TrustDimension"
                                },
                                "nfts": {
                                  "$ref": "#/components/schemas/TrustDimension"
                                },
                                "staking": {
                                  "$ref": "#/components/schemas/TrustDimension"
                                },
                                "institutional_stablecoins": {
                                  "description": "Always present in the base profile with all 8 checks (EURCV and USDCV on Ethereum and Solana; EURCV on XRPL; USDC and BENJI on Stellar; USDC on Sui). The Solana, XRPL, Stellar and Sui entries are evaluated only when the matching wallet parameter is supplied; otherwise they carry evaluated: false and are counted in notEvaluatedCount.",
                                  "$ref": "#/components/schemas/TrustDimension"
                                },
                                "tokenized_treasuries": {
                                  "description": "Always present: 16 checks. BUIDL on Ethereum, Arbitrum, Avalanche, BNB Chain, Optimism and Polygon plus BUIDL-I on Ethereum; USDY on Ethereum, Arbitrum, BNB Chain, Sei and Sui; USYC on Ethereum and BNB Chain; OUSG and USTB on Ethereum. USDY on Sui is evaluated only when suiWallet is supplied. BUIDL rows have no storage proof (computed balance) and are declined with available: false in proof mode.",
                                  "$ref": "#/components/schemas/TrustDimension"
                                },
                                "stablecoin_deposits": {
                                  "description": "Always present: 39 checks. Aave v3 aUSDC and aUSDT receipts across 13 chains (23 rows), sUSDS on Ethereum, Arbitrum, Base and Optimism, sDAI on Ethereum and Gnosis, and 10 listed Morpho USDC vaults on Ethereum and Base. Aave aToken rows have no storage proof (computed balance) and are declined with available: false in proof mode.",
                                  "$ref": "#/components/schemas/TrustDimension"
                                },
                                "wrapped_bitcoin": {
                                  "description": "Always present: 12 checks. WBTC on Ethereum, Arbitrum, Optimism, Polygon and Avalanche; cbBTC on Ethereum, Base, Arbitrum and Robinhood Chain; tBTC on Ethereum, Arbitrum and Base.",
                                  "$ref": "#/components/schemas/TrustDimension"
                                },
                                "names": {
                                  "description": "Always present: 2 checks. ENS .eth names on Ethereum and Basenames on Base, each an NFT-held presence check.",
                                  "$ref": "#/components/schemas/TrustDimension"
                                },
                                "account": {
                                  "description": "Always present: 10 checks, two per chain on Ethereum, Base, Arbitrum, Optimism and Polygon: \"Contract code on X\" (met when bytecode other than the EIP-7702 designator sits at the wallet address: a smart-contract wallet, a protocol, a token) and \"EIP-7702 delegation on X\" (met when the address carries the designator: a key that delegated execution). The two are exclusive on a chain; an ordinary key reads false on both. Each row's evaluatedCondition is {type: account_code, chainId, expect, operator: code_state}, the same shape as the /v1/attest condition, so its conditionHash equals that condition's. Which contract is never named; ask /v1/attest with account_code and delegate for that. In proof mode these rows carry available: false with a reason pointing at /v1/attest.",
                                  "$ref": "#/components/schemas/TrustDimension"
                                },
                                "solana": {
                                  "description": "Present only when solanaWallet is provided",
                                  "$ref": "#/components/schemas/TrustDimension"
                                },
                                "xrpl": {
                                  "description": "Present only when xrplWallet is provided",
                                  "$ref": "#/components/schemas/TrustDimension"
                                },
                                "bitcoin": {
                                  "description": "Present only when bitcoinWallet is provided",
                                  "$ref": "#/components/schemas/TrustDimension"
                                },
                                "tron": {
                                  "description": "Present only when tronWallet is provided",
                                  "$ref": "#/components/schemas/TrustDimension"
                                }
                              }
                            },
                            "summary": {
                              "type": "object",
                              "properties": {
                                "totalChecks": {
                                  "type": "integer"
                                },
                                "totalPassed": {
                                  "type": "integer"
                                },
                                "totalFailed": {
                                  "type": "integer"
                                },
                                "totalNotEvaluated": {
                                  "type": "integer",
                                  "description": "Checks across all dimensions that carry evaluated: false. totalPassed + totalFailed + totalNotEvaluated = totalChecks."
                                },
                                "dimensionsWithActivity": {
                                  "type": "integer"
                                },
                                "dimensionsChecked": {
                                  "type": "integer"
                                }
                              }
                            },
                            "profiledAt": {
                              "type": "string",
                              "format": "date-time"
                            },
                            "expiresAt": {
                              "type": "string",
                              "format": "date-time"
                            }
                          }
                        },
                        "sig": {
                          "type": "string",
                          "description": "ECDSA P-256 signature over the trust object (base64 P1363)"
                        },
                        "kid": {
                          "type": "string",
                          "description": "Which key + scheme signed this response. insumer-attest-v1 (v1 trust) or insumer-trust-v2 (v2 trust). Resolve the public key from GET /v1/jwks or https://insumermodel.com/.well-known/jwks.json (all EC kids share one key; post-quantum AKP entries are appended after them)."
                        },
                        "pqSig": {
                          "type": "string",
                          "description": "OPTIONAL post-quantum signature: base64 ML-DSA-65 (FIPS 204) over the post-quantum domain tag plus the exact classical preimage this response's kid selects. A kid a verifier does not recognise selects no preimage, so the post-quantum signature is then unverifiable, never refuted, and no other era's preimage may be substituted for it. Additive; sig and kid are unchanged. See the state attestation spec, Section 12 Check 6."
                        },
                        "pqKid": {
                          "type": "string",
                          "description": "OPTIONAL post-quantum key identifier (insumer-attest-pq1 or insumer-trust-pq1), resolved in the JWKS as an RFC 9964 AKP / ML-DSA-65 key.",
                          "example": "insumer-trust-pq1"
                        }
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "creditsRemaining": {
                          "type": [
                            "integer",
                            "null"
                          ],
                          "description": "Credits left on the key after this call. null on x402-paid calls (creditsCharged is 0 there; the call was paid at the transport layer, not from stored credits)."
                        },
                        "creditsCharged": {
                          "type": "integer",
                          "description": "3 for standard, 6 for proof: merkle. 0 on x402-paid calls."
                        },
                        "version": {
                          "type": "string"
                        },
                        "timestamp": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "data": {
                    "trust": {
                      "id": "TRST-81224",
                      "wallet": "0x1601843c5E9bC251A3272907010AFa41Fa18347E",
                      "conditionSetVersion": "2026-10-08",
                      "dimensions": {
                        "stablecoins": {
                          "checks": [
                            {
                              "label": "USDC on Ethereum",
                              "chainId": 1,
                              "met": false,
                              "evaluatedCondition": {
                                "type": "token_balance",
                                "chainId": 1,
                                "contractAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
                                "operator": "gt",
                                "threshold": 0,
                                "decimals": 6
                              },
                              "conditionHash": "0x27254c13e7bfb9e96dc90f7c54a7d2b05a5647fd38a00b2dc1bff58a236bbebf",
                              "blockNumber": "0x18eea5a",
                              "blockTimestamp": "2026-10-07T21:52:59.000Z"
                            },
                            {
                              "label": "USDC on Base",
                              "chainId": 8453,
                              "met": true,
                              "evaluatedCondition": {
                                "type": "token_balance",
                                "chainId": 8453,
                                "contractAddress": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
                                "operator": "gt",
                                "threshold": 0,
                                "decimals": 6
                              },
                              "conditionHash": "0x39c2094ef29fa7ea94e2db2ba02734ff06db035f47b1245fddd18be9e0e2d2f3",
                              "blockNumber": "0x31e312e",
                              "blockTimestamp": "2026-10-07T21:53:03.000Z"
                            }
                          ],
                          "passCount": 6,
                          "failCount": 46,
                          "notEvaluatedCount": 0,
                          "total": 52
                        },
                        "governance": {
                          "checks": [],
                          "passCount": 0,
                          "failCount": 8,
                          "notEvaluatedCount": 0,
                          "total": 8
                        },
                        "nfts": {
                          "checks": [],
                          "passCount": 0,
                          "failCount": 3,
                          "notEvaluatedCount": 0,
                          "total": 3
                        },
                        "staking": {
                          "checks": [],
                          "passCount": 0,
                          "failCount": 5,
                          "notEvaluatedCount": 0,
                          "total": 5
                        },
                        "institutional_stablecoins": {
                          "checks": [
                            {
                              "label": "EURCV on Ethereum",
                              "chainId": 1,
                              "met": false,
                              "evaluatedCondition": {
                                "type": "token_balance",
                                "chainId": 1,
                                "contractAddress": "0x5f7827fdeb7c20b443265fc2f40845b715385ff2",
                                "operator": "gt",
                                "threshold": 0,
                                "decimals": 18
                              },
                              "conditionHash": "0x0686a9c43f56bd396a0182761ec161f8a8ff8e431fdfd696665cd9d9de3de26d",
                              "blockNumber": "0x18eea5a",
                              "blockTimestamp": "2026-10-07T21:52:59.000Z"
                            }
                          ],
                          "passCount": 0,
                          "failCount": 2,
                          "notEvaluatedCount": 6,
                          "total": 8
                        },
                        "tokenized_treasuries": {
                          "checks": [],
                          "passCount": 0,
                          "failCount": 15,
                          "notEvaluatedCount": 1,
                          "total": 16
                        },
                        "stablecoin_deposits": {
                          "checks": [],
                          "passCount": 5,
                          "failCount": 34,
                          "notEvaluatedCount": 0,
                          "total": 39
                        },
                        "wrapped_bitcoin": {
                          "checks": [],
                          "passCount": 0,
                          "failCount": 12,
                          "notEvaluatedCount": 0,
                          "total": 12
                        },
                        "names": {
                          "checks": [],
                          "passCount": 0,
                          "failCount": 2,
                          "notEvaluatedCount": 0,
                          "total": 2
                        },
                        "account": {
                          "checks": [
                            {
                              "label": "Contract code on Ethereum",
                              "chainId": 1,
                              "met": true,
                              "evaluatedCondition": {
                                "type": "account_code",
                                "chainId": 1,
                                "expect": "contract",
                                "operator": "code_state"
                              },
                              "conditionHash": "0xfd7b6aa42eb012184fa54d9d5d99c6ab18481e0ce33ec0ec0e9d28d37b54ccbc",
                              "blockNumber": "0x18eea5a",
                              "blockTimestamp": "2026-10-07T21:52:59.000Z"
                            },
                            {
                              "label": "EIP-7702 delegation on Ethereum",
                              "chainId": 1,
                              "met": false,
                              "evaluatedCondition": {
                                "type": "account_code",
                                "chainId": 1,
                                "expect": "eip7702",
                                "operator": "code_state"
                              },
                              "conditionHash": "0xdef6fadcef95f59f4621fa2bf788e6be0ffc0492dba22038999b8cd757adf18b",
                              "blockNumber": "0x18eea5a",
                              "blockTimestamp": "2026-10-07T21:52:59.000Z"
                            }
                          ],
                          "passCount": 5,
                          "failCount": 5,
                          "notEvaluatedCount": 0,
                          "total": 10
                        }
                      },
                      "summary": {
                        "totalChecks": 155,
                        "totalPassed": 16,
                        "totalFailed": 132,
                        "totalNotEvaluated": 7,
                        "dimensionsWithActivity": 3,
                        "dimensionsChecked": 10
                      },
                      "profiledAt": "2026-10-07T21:53:04.795Z",
                      "expiresAt": "2026-10-07T22:23:04.795Z"
                    },
                    "sig": "<88-char base64, P1363 r||s>",
                    "kid": "insumer-trust-v2",
                    "pqSig": "<base64 ML-DSA-65 signature>",
                    "pqKid": "insumer-trust-pq1"
                  },
                  "meta": {
                    "creditsRemaining": 997,
                    "creditsCharged": 3,
                    "version": "1.0",
                    "timestamp": "2026-10-07T21:53:05.439Z"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request (missing wallet)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "402": {
            "description": "Payment required. For API-key callers: insufficient verification credits (standard error envelope). For credential-less callers this is the x402 pay-per-call quote (X402Quote body): the v2 payment payload is in the JSON body and, base64-encoded, in the payment-required response header. Pay the quoted amount in USDC on any listed network (Base, Polygon, Arbitrum, Arc, or Solana) and retry with the PAYMENT-SIGNATURE header (X-PAYMENT is still accepted).",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ErrorEnvelope"
                    },
                    {
                      "$ref": "#/components/schemas/X402Quote"
                    }
                  ]
                }
              }
            }
          },
          "413": {
            "description": "Body exceeds the pay-per-call size cap. Returned on x402-paid requests whose JSON body is larger than the cap; API-key and wallet-auth calls are not subject to it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "description": "Data source unavailable after retries (RpcFailureEnvelope; no trust profile signed, no credits charged, retryable after a short delay). Wallet-auth and x402-paid calls can also return 503 as a standard error envelope for transient service conditions (for example the wallet-auth nonce store or payment verification being temporarily unavailable); those are equally retryable. On an Arc (eip155:5042) pay-per-call payment, a 503 can also mean the settlement was submitted but had not confirmed by the server's deadline, or the payment facilitator did not answer. That payment is UNRESOLVED, not refused: the transfer may still land. Retry the exact same request (same body) with the SAME payment header; it resolves to the same payment and cannot charge twice. Do not sign a new authorization. If the payment ultimately failed, the retry returns 402 with a fresh quote and nothing was charged.\n",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/RpcFailureEnvelope"
                    },
                    {
                      "$ref": "#/components/schemas/ErrorEnvelope"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/v1/trust/batch": {
      "post": {
        "operationId": "batchWalletTrust",
        "x-payment-info": {
          "price": {
            "mode": "dynamic",
            "currency": "USD",
            "min": "0.15",
            "max": "3.00"
          },
          "protocols": [
            {
              "x402": {}
            }
          ]
        },
        "summary": "Batch wallet trust profiles",
        "description": "Batch trust profiles for up to 10 wallets in one request. Each wallet gets an independent ECDSA-signed profile. Partial success supported. 3 credits/wallet standard, 6 with proof=\"merkle\". Authentication: this endpoint accepts EITHER the X-API-Key header OR the Authorization: Wallet header (SIWE envelope from a wallet that holds the Insumer Access pass).\n",
        "tags": [
          "Trust Fact Profiles"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "WalletAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "wallets"
                ],
                "properties": {
                  "wallets": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 10,
                    "description": "1-10 wallet entries to profile",
                    "items": {
                      "type": "object",
                      "required": [
                        "wallet"
                      ],
                      "properties": {
                        "wallet": {
                          "type": "string",
                          "pattern": "^0x[a-fA-F0-9]{40}$",
                          "description": "EVM wallet address (required)"
                        },
                        "solanaWallet": {
                          "type": "string",
                          "description": "Solana wallet address (base58). Adds the 14-check solana dimension for this wallet and evaluates its Solana institutional_stablecoins entries."
                        },
                        "xrplWallet": {
                          "type": "string",
                          "description": "XRPL wallet address (classic r-address). Adds the xrpl dimension (RLUSD, USDC, OUSG) for this wallet and evaluates its EURCV on XRPL entry. The base58 checksum is verified; an address that fails it returns 400."
                        },
                        "bitcoinWallet": {
                          "type": "string",
                          "description": "Bitcoin address. Adds the bitcoin dimension (native BTC presence check) for this wallet."
                        },
                        "tronWallet": {
                          "type": "string",
                          "description": "Tron address (T-prefix, 34 chars). Adds the tron dimension (USDT, USD1, WBTC) for this wallet."
                        },
                        "stellarWallet": {
                          "type": "string",
                          "description": "Stellar address (G-prefix, 56 chars). Evaluates the Stellar entries (USDC, BENJI) under institutional_stablecoins for this wallet; the checksum is verified and a malformed address is a 400, never silently skipped."
                        },
                        "suiWallet": {
                          "type": "string",
                          "description": "Sui address (0x + 64 hex chars). Evaluates USDC on Sui (institutional_stablecoins) and USDY on Sui (tokenized_treasuries) for this wallet."
                        }
                      }
                    }
                  },
                  "proof": {
                    "type": "string",
                    "enum": [
                      "merkle"
                    ],
                    "description": "Set to 'merkle' for EIP-1186 storage proofs on all wallets. Same coverage as the single endpoint: EVM token rows carry a storage proof when the token's balance slot can be discovered; rows whose balance is computed rather than stored (Aave aTokens, BUIDL) and tokens with non-standard storage layouts are declined with a stated reason; NFT, non-EVM and account rows are declined (account rows with a reason pointing at /v1/attest); a check that was not evaluated carries no proof key at all; the premium is refunded whenever no proof is delivered. 6 credits/wallet."
                  }
                }
              },
              "example": {
                "wallets": [
                  {
                    "wallet": "0x1601843c5E9bC251A3272907010AFa41Fa18347E",
                    "solanaWallet": "DXK4yMpigbTSqv33nJk1tJucXB4E3rDmTXn3yZmiFAXt"
                  },
                  {
                    "wallet": "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb"
                  },
                  {
                    "wallet": "0xB561B1e79E448bC3A7aC4Dc377EeECBc99505f60"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Batch trust profiles (may include partial failures)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "results": {
                          "type": "array",
                          "description": "One entry per wallet — either a trust profile or an error",
                          "items": {
                            "oneOf": [
                              {
                                "type": "object",
                                "properties": {
                                  "trust": {
                                    "type": "object",
                                    "description": "Full trust profile (same schema as POST /v1/trust)",
                                    "properties": {
                                      "id": {
                                        "type": "string"
                                      },
                                      "wallet": {
                                        "type": "string"
                                      },
                                      "conditionSetVersion": {
                                        "type": "string"
                                      },
                                      "dimensions": {
                                        "type": "object"
                                      },
                                      "summary": {
                                        "type": "object"
                                      },
                                      "profiledAt": {
                                        "type": "string"
                                      },
                                      "expiresAt": {
                                        "type": "string"
                                      }
                                    }
                                  },
                                  "sig": {
                                    "type": "string",
                                    "description": "ECDSA P-256 signature over this wallet's trust object"
                                  },
                                  "kid": {
                                    "type": "string",
                                    "description": "insumer-trust-v2 (v2 keys) or insumer-attest-v1 (v1 keys); selects the key and the preimage exactly as on POST /v1/trust"
                                  },
                                  "pqSig": {
                                    "type": "string",
                                    "description": "OPTIONAL post-quantum signature over this wallet's trust preimage: base64 ML-DSA-65 (FIPS 204) over the post-quantum domain tag plus the exact classical preimage this entry's kid selects. A kid a verifier does not recognise selects no preimage, so the post-quantum signature is then unverifiable, never refuted, and no other era's preimage may be substituted for it. Additive; sig and kid are unchanged. See the state attestation spec, Section 12 Check 6."
                                  },
                                  "pqKid": {
                                    "type": "string",
                                    "description": "OPTIONAL post-quantum key identifier (insumer-trust-pq1), resolved in the JWKS as an RFC 9964 AKP / ML-DSA-65 key.",
                                    "example": "insumer-trust-pq1"
                                  }
                                }
                              },
                              {
                                "type": "object",
                                "properties": {
                                  "error": {
                                    "type": "object",
                                    "properties": {
                                      "wallet": {
                                        "type": "string"
                                      },
                                      "message": {
                                        "type": "string"
                                      }
                                    }
                                  }
                                }
                              }
                            ]
                          }
                        },
                        "summary": {
                          "type": "object",
                          "properties": {
                            "requested": {
                              "type": "integer"
                            },
                            "succeeded": {
                              "type": "integer"
                            },
                            "failed": {
                              "type": "integer"
                            }
                          }
                        }
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "creditsCharged": {
                          "type": "integer",
                          "description": "Total credits charged (successCount × creditsPerWallet). 0 on x402-paid calls."
                        },
                        "creditsRemaining": {
                          "type": [
                            "integer",
                            "null"
                          ],
                          "description": "Credits left on the key after this call. null on x402-paid calls (creditsCharged is 0 there; the call was paid at the transport layer, not from stored credits)."
                        },
                        "version": {
                          "type": "string"
                        },
                        "timestamp": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "data": {
                    "results": [
                      {
                        "trust": {
                          "id": "TRST-74167",
                          "wallet": "0x1601843c5E9bC251A3272907010AFa41Fa18347E",
                          "conditionSetVersion": "2026-10-08",
                          "dimensions": {
                            "stablecoins": {
                              "checks": [],
                              "passCount": 6,
                              "failCount": 46,
                              "notEvaluatedCount": 0,
                              "total": 52
                            },
                            "governance": {
                              "checks": [],
                              "passCount": 0,
                              "failCount": 8,
                              "notEvaluatedCount": 0,
                              "total": 8
                            },
                            "nfts": {
                              "checks": [],
                              "passCount": 0,
                              "failCount": 3,
                              "notEvaluatedCount": 0,
                              "total": 3
                            },
                            "staking": {
                              "checks": [],
                              "passCount": 0,
                              "failCount": 5,
                              "notEvaluatedCount": 0,
                              "total": 5
                            },
                            "institutional_stablecoins": {
                              "checks": [],
                              "passCount": 0,
                              "failCount": 4,
                              "notEvaluatedCount": 4,
                              "total": 8
                            },
                            "tokenized_treasuries": {
                              "checks": [],
                              "passCount": 0,
                              "failCount": 15,
                              "notEvaluatedCount": 1,
                              "total": 16
                            },
                            "stablecoin_deposits": {
                              "checks": [],
                              "passCount": 5,
                              "failCount": 34,
                              "notEvaluatedCount": 0,
                              "total": 39
                            },
                            "wrapped_bitcoin": {
                              "checks": [],
                              "passCount": 0,
                              "failCount": 12,
                              "notEvaluatedCount": 0,
                              "total": 12
                            },
                            "names": {
                              "checks": [],
                              "passCount": 0,
                              "failCount": 2,
                              "notEvaluatedCount": 0,
                              "total": 2
                            },
                            "account": {
                              "checks": [],
                              "passCount": 5,
                              "failCount": 5,
                              "notEvaluatedCount": 0,
                              "total": 10
                            },
                            "solana": {
                              "checks": [],
                              "passCount": 1,
                              "failCount": 13,
                              "notEvaluatedCount": 0,
                              "total": 14
                            }
                          },
                          "summary": {
                            "totalChecks": 169,
                            "totalPassed": 17,
                            "totalFailed": 147,
                            "totalNotEvaluated": 5,
                            "dimensionsWithActivity": 4,
                            "dimensionsChecked": 11
                          },
                          "profiledAt": "2026-10-07T21:53:03.720Z",
                          "expiresAt": "2026-10-07T22:23:03.720Z"
                        },
                        "sig": "<88-char base64, P1363 r||s>",
                        "kid": "insumer-trust-v2",
                        "pqSig": "<base64 ML-DSA-65 signature>",
                        "pqKid": "insumer-trust-pq1"
                      },
                      {
                        "trust": {
                          "id": "TRST-C7EA2",
                          "wallet": "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb",
                          "conditionSetVersion": "2026-10-08",
                          "dimensions": {
                            "stablecoins": {
                              "checks": [],
                              "passCount": 11,
                              "failCount": 41,
                              "notEvaluatedCount": 0,
                              "total": 52
                            },
                            "governance": {
                              "checks": [],
                              "passCount": 2,
                              "failCount": 6,
                              "notEvaluatedCount": 0,
                              "total": 8
                            },
                            "nfts": {
                              "checks": [],
                              "passCount": 0,
                              "failCount": 3,
                              "notEvaluatedCount": 0,
                              "total": 3
                            },
                            "staking": {
                              "checks": [],
                              "passCount": 3,
                              "failCount": 2,
                              "notEvaluatedCount": 0,
                              "total": 5
                            },
                            "institutional_stablecoins": {
                              "checks": [],
                              "passCount": 2,
                              "failCount": 0,
                              "notEvaluatedCount": 6,
                              "total": 8
                            },
                            "tokenized_treasuries": {
                              "checks": [],
                              "passCount": 0,
                              "failCount": 15,
                              "notEvaluatedCount": 1,
                              "total": 16
                            },
                            "stablecoin_deposits": {
                              "checks": [],
                              "passCount": 6,
                              "failCount": 33,
                              "notEvaluatedCount": 0,
                              "total": 39
                            },
                            "wrapped_bitcoin": {
                              "checks": [],
                              "passCount": 4,
                              "failCount": 8,
                              "notEvaluatedCount": 0,
                              "total": 12
                            },
                            "names": {
                              "checks": [],
                              "passCount": 0,
                              "failCount": 2,
                              "notEvaluatedCount": 0,
                              "total": 2
                            },
                            "account": {
                              "checks": [],
                              "passCount": 2,
                              "failCount": 8,
                              "notEvaluatedCount": 0,
                              "total": 10
                            }
                          },
                          "summary": {
                            "totalChecks": 155,
                            "totalPassed": 30,
                            "totalFailed": 118,
                            "totalNotEvaluated": 7,
                            "dimensionsWithActivity": 7,
                            "dimensionsChecked": 10
                          },
                          "profiledAt": "2026-10-07T21:53:03.495Z",
                          "expiresAt": "2026-10-07T22:23:03.495Z"
                        },
                        "sig": "<88-char base64, P1363 r||s>",
                        "kid": "insumer-trust-v2",
                        "pqSig": "<base64 ML-DSA-65 signature>",
                        "pqKid": "insumer-trust-pq1"
                      },
                      {
                        "trust": {
                          "id": "TRST-CFD45",
                          "wallet": "0xB561B1e79E448bC3A7aC4Dc377EeECBc99505f60",
                          "conditionSetVersion": "2026-10-08",
                          "dimensions": {
                            "stablecoins": {
                              "checks": [],
                              "passCount": 2,
                              "failCount": 50,
                              "notEvaluatedCount": 0,
                              "total": 52
                            },
                            "governance": {
                              "checks": [],
                              "passCount": 0,
                              "failCount": 8,
                              "notEvaluatedCount": 0,
                              "total": 8
                            },
                            "nfts": {
                              "checks": [],
                              "passCount": 0,
                              "failCount": 3,
                              "notEvaluatedCount": 0,
                              "total": 3
                            },
                            "staking": {
                              "checks": [],
                              "passCount": 1,
                              "failCount": 4,
                              "notEvaluatedCount": 0,
                              "total": 5
                            },
                            "institutional_stablecoins": {
                              "checks": [],
                              "passCount": 0,
                              "failCount": 2,
                              "notEvaluatedCount": 6,
                              "total": 8
                            },
                            "tokenized_treasuries": {
                              "checks": [],
                              "passCount": 0,
                              "failCount": 15,
                              "notEvaluatedCount": 1,
                              "total": 16
                            },
                            "stablecoin_deposits": {
                              "checks": [],
                              "passCount": 0,
                              "failCount": 39,
                              "notEvaluatedCount": 0,
                              "total": 39
                            },
                            "wrapped_bitcoin": {
                              "checks": [],
                              "passCount": 2,
                              "failCount": 10,
                              "notEvaluatedCount": 0,
                              "total": 12
                            },
                            "names": {
                              "checks": [],
                              "passCount": 0,
                              "failCount": 2,
                              "notEvaluatedCount": 0,
                              "total": 2
                            },
                            "account": {
                              "checks": [],
                              "passCount": 0,
                              "failCount": 10,
                              "notEvaluatedCount": 0,
                              "total": 10
                            }
                          },
                          "summary": {
                            "totalChecks": 155,
                            "totalPassed": 5,
                            "totalFailed": 143,
                            "totalNotEvaluated": 7,
                            "dimensionsWithActivity": 3,
                            "dimensionsChecked": 10
                          },
                          "profiledAt": "2026-10-07T21:53:03.686Z",
                          "expiresAt": "2026-10-07T22:23:03.686Z"
                        },
                        "sig": "<88-char base64, P1363 r||s>",
                        "kid": "insumer-trust-v2",
                        "pqSig": "<base64 ML-DSA-65 signature>",
                        "pqKid": "insumer-trust-pq1"
                      }
                    ],
                    "summary": {
                      "requested": 3,
                      "succeeded": 3,
                      "failed": 0
                    }
                  },
                  "meta": {
                    "creditsCharged": 9,
                    "creditsRemaining": 853,
                    "version": "1.0",
                    "timestamp": "2026-10-07T21:53:03.926Z"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request (invalid wallets array)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "402": {
            "description": "Payment required. For API-key callers: insufficient verification credits (standard error envelope). For credential-less callers this is the x402 pay-per-call quote (X402Quote body): the v2 payment payload is in the JSON body and, base64-encoded, in the payment-required response header. Pay the quoted amount in USDC on any listed network (Base, Polygon, Arbitrum, Arc, or Solana) and retry with the PAYMENT-SIGNATURE header (X-PAYMENT is still accepted).",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ErrorEnvelope"
                    },
                    {
                      "$ref": "#/components/schemas/X402Quote"
                    }
                  ]
                }
              }
            }
          },
          "413": {
            "description": "Body exceeds the pay-per-call size cap. Returned on x402-paid requests whose JSON body is larger than the cap; API-key and wallet-auth calls are not subject to it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "description": "Transient service condition on wallet-auth or x402-paid calls (for example the wallet-auth nonce store or payment verification being temporarily unavailable). Retryable after a short delay. Per-wallet data-source failures do not use this status here; they surface as error entries in the partial-success results array. On an Arc (eip155:5042) pay-per-call payment, a 503 can also mean the settlement was submitted but had not confirmed by the server's deadline, or the payment facilitator did not answer. That payment is UNRESOLVED, not refused: the transfer may still land. Retry the exact same request (same body) with the SAME payment header; it resolves to the same payment and cannot charge twice. Do not sign a new authorization. If the payment ultimately failed, the retry returns 402 with a fresh quote and nothing was charged.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/v1/credits": {
      "get": {
        "operationId": "getCredits",
        "summary": "Check verification credit balance",
        "description": "Returns the verification credit balance, tier, and daily rate limit for the authenticated account. Authentication: this endpoint accepts EITHER the X-API-Key header OR the Authorization: Wallet header (SIWE envelope from a wallet that holds the Insumer Access pass).\n",
        "tags": [
          "Keys & Billing"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "WalletAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Credit balance",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "apiKeyCredits": {
                          "type": "integer"
                        },
                        "tier": {
                          "type": "string",
                          "enum": [
                            "free",
                            "pro",
                            "enterprise",
                            "paid",
                            "x402"
                          ],
                          "description": "\"paid\" is the tier of wallet-native keys purchased with crypto via POST /v1/keys/buy. \"x402\" is the pay-per-call identity tier: the key record auto-created for a wallet that pays per call via x402 (0 stored credits; each call is paid at the transport layer)."
                        },
                        "dailyLimit": {
                          "type": "integer"
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "description": "Transient service condition on wallet-auth calls (for example the wallet-auth nonce store being temporarily unavailable). Retryable after a short delay.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/v1/keys/buy": {
      "post": {
        "operationId": "buyKey",
        "summary": "Buy a new API key with USDC, USDT, or BTC (no auth required)",
        "description": "Agent-friendly key purchase: send USDC, USDT, or BTC to the platform wallet (EVM USDC/USDT: `0xAd982CB19aCCa2923Df8F687C0614a7700255a23` — same on all chains; Solana USDC/USDT: `6a1mLjefhvSJX1sEX8PTnionbE9DqoYjU6F6bNkT4Ydr`; Bitcoin BTC: `bc1qg7qnerdhlmdn899zemtez5tcx2a2snc0dt9dt0`; Tron USDT-TRC20: `TC5yvwkAMakkXtUxYiu2Yn1xbBcwYuD6cn`), then call this endpoint with the transaction hash to receive a new API key with credits. No email or prior authentication needed — the sender wallet address from the transaction becomes the key's identity. One key per wallet address. Alternative: email-based free-tier signup via POST /v1/keys/create (10 free credits, no card). Use POST /v1/credits/buy to top up an existing key. Volume discounts: $5–$99 = 25 credits/$1 ($0.04/call), $100–$499 = 33 credits/$1 ($0.03/call, 25% off), $500+ = 50 credits/$1 ($0.02/call, 50% off). USDC and USDT accepted on EVM chains and Solana (auto-detected from transaction). USDT-TRC20 accepted on Tron. BTC accepted on Bitcoin (converted to USD at market rate, requires 1 confirmation). Crypto sent on unsupported chains cannot be recovered. All purchases are final and non-refundable.\n",
        "tags": [
          "Agent Onboarding"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "txHash",
                  "chainId",
                  "appName"
                ],
                "properties": {
                  "txHash": {
                    "type": "string",
                    "description": "Transaction hash proving payment"
                  },
                  "chainId": {
                    "$ref": "#/components/schemas/PaymentChainId"
                  },
                  "amount": {
                    "type": "number",
                    "minimum": 5,
                    "description": "Stablecoin amount sent (min 5). Not required for BTC — USD value is derived from the on-chain BTC amount at market rate."
                  },
                  "appName": {
                    "type": "string",
                    "maxLength": 100,
                    "description": "Name for this API key (e.g. your agent or app name)"
                  },
                  "channel": {
                    "type": "string",
                    "description": "Optional attribution label recorded with the purchase (e.g. the integration or marketplace the buyer came through)."
                  },
                  "keyDelivery": {
                    "type": "string",
                    "enum": [
                      "wallet",
                      "apiKey",
                      "both"
                    ],
                    "default": "wallet",
                    "description": "Preferred credential shape. Default `wallet` returns no API key string when an Insumer Access SBT is minted to the sender wallet — the wallet + pass becomes the credential, and subsequent calls authenticate via Authorization: Wallet. `apiKey` (or its alias `both`) returns the API key string in the response alongside the pass; the wallet still receives the SBT on EVM payments and can use either credential on /v1/attest and /v1/credits/buy. When the SBT cannot land (non-EVM payment, or deferred EVM mint), the API key is returned regardless of this setting so the caller is never left without a usable credential. Case-insensitive.\n"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "API key created with credits",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "success": {
                          "type": "boolean"
                        },
                        "key": {
                          "type": "string",
                          "description": "Your new API key (store securely — shown only once). CONDITIONALLY PRESENT: omitted when the wallet receives an Insumer Access SBT on this purchase AND the request set `keyDelivery: \"wallet\"` (the default). In that case the wallet + SBT is the credential and the agent authenticates via Authorization: Wallet. The key is always returned when `keyDelivery` is `apiKey` or `both`, or when the SBT cannot land (non-EVM purchase, or `passMint.status: \"deferred\"`).\n"
                        },
                        "authMethod": {
                          "type": "string",
                          "enum": [
                            "wallet",
                            "apiKey",
                            "both"
                          ],
                          "description": "Indicates which credential(s) were delivered. `wallet` — only the wallet + SBT is the credential (no `key` field in this response). `apiKey` — only the API key string was delivered (no SBT in the wallet; non-EVM payment or deferred mint). `both` — the wallet holds the SBT AND the response carries an API key string; either may be used on wallet-auth-eligible endpoints.\n"
                        },
                        "authHint": {
                          "type": "string",
                          "description": "Human-readable guidance for the caller on how to authenticate going forward. Present when `authMethod` is `wallet` or `both`; absent when `authMethod` is `apiKey` (standard X-API-Key usage needs no hint).\n"
                        },
                        "name": {
                          "type": "string"
                        },
                        "tier": {
                          "type": "string"
                        },
                        "dailyLimit": {
                          "type": "integer"
                        },
                        "creditsAdded": {
                          "type": "integer"
                        },
                        "totalCredits": {
                          "type": "integer"
                        },
                        "usdcPaid": {
                          "type": "string",
                          "description": "Stablecoin amount verified. Present on all purchases except Bitcoin."
                        },
                        "btcPaid": {
                          "type": "string",
                          "description": "BTC amount verified. Present on Bitcoin purchases; usdcPaid otherwise."
                        },
                        "btcPrice": {
                          "type": "number",
                          "description": "BTC/USD market rate used for conversion. Present on Bitcoin purchases; usdcPaid otherwise."
                        },
                        "usdEquivalent": {
                          "type": "string",
                          "description": "USD value credited. Present on Bitcoin purchases; usdcPaid otherwise."
                        },
                        "effectiveRate": {
                          "type": "string"
                        },
                        "chainName": {
                          "type": "string"
                        },
                        "registeredWallet": {
                          "type": "string",
                          "description": "Wallet address registered to this key (extracted from transaction)"
                        },
                        "passMint": {
                          "type": "object",
                          "description": "Result of the Insumer Access SBT mint. EVM purchases mint the SBT to the sender wallet on Base mainnet so the wallet can authenticate to /v1/attest via `Authorization: Wallet ...` (SDK: @skyemeta/access). Mint is fail-open — a mint failure does not block the key purchase; the API key + credits are issued regardless. Non-EVM purchases (Solana/BTC/Tron) skip the mint since the sender has no native EVM address; those buyers can use X-API-Key auth, or a future endpoint accepting an explicit EVM mintTo address.\n",
                          "properties": {
                            "status": {
                              "type": "string",
                              "enum": [
                                "minted",
                                "already_held",
                                "deferred",
                                "skipped"
                              ],
                              "description": "`minted` = SBT freshly minted to the sender wallet on Base. `already_held` = wallet already holds a pass (idempotent). `deferred` = the mint did not complete; caller can retry via a future mint-retry endpoint. `skipped` = non-EVM payment chain (Solana/BTC/Tron).\n"
                            },
                            "tokenId": {
                              "type": "string",
                              "nullable": true,
                              "description": "Token ID of the SBT. May be null on `deferred` or if the post-tx verification read failed (mint receipt still confirmed)."
                            },
                            "txHash": {
                              "type": "string",
                              "nullable": true,
                              "description": "Base transaction hash of the mint. Null on `already_held`, `deferred`, or `skipped`."
                            },
                            "collection": {
                              "type": "string",
                              "description": "Insumer Access collection contract address on Base (0x3E2a408cc6eceba04FF9d04A5B8B05aBa8DD50ce)."
                            },
                            "chainId": {
                              "type": "integer",
                              "description": "Base mainnet chain ID (8453)."
                            },
                            "blockNumber": {
                              "type": "string",
                              "nullable": true,
                              "description": "Base block number the mint landed in. Null on `already_held`, `deferred`, or `skipped`."
                            },
                            "reason": {
                              "type": "string",
                              "description": "Present on `deferred` and `skipped`. Human-readable explanation of why the mint did not happen."
                            }
                          }
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "Key already exists for this wallet, or transaction already used",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "422": {
            "description": "On-chain verification failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "description": "On-chain verification temporarily unavailable. Retry in a few seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/v1/keys/purchase": {
      "post": {
        "operationId": "purchaseTieredKey",
        "summary": "Buy a tiered prepaid API key with USDC, USDT, or BTC (no auth required)",
        "description": "Email-based tiered key purchase: send the tier-specific amount in USDC/USDT/BTC to the platform wallet (EVM USDC/USDT: `0xAd982CB19aCCa2923Df8F687C0614a7700255a23` — same on all chains; Solana USDC/USDT: `6a1mLjefhvSJX1sEX8PTnionbE9DqoYjU6F6bNkT4Ydr`; Bitcoin BTC: `bc1qg7qnerdhlmdn899zemtez5tcx2a2snc0dt9dt0`), then call this endpoint with the transaction hash, your email, and the tier you paid for. Returns an API key valid for 30 days at the tier's daily limit and credit allocation. Fixed pricing: Pro = $29 (10000 requests/day, 1,000 attest credits), Enterprise = $99 (100000 requests/day, 5,000 attest credits), the same allocation as the card subscription (POST /v1/keys/checkout). One-month prepaid; to renew, call this endpoint again with a new payment. For pay-what-you-want credit purchases without a fixed tier or expiry, see POST /v1/keys/buy (wallet-native, agent-friendly). Crypto sent on unsupported chains cannot be recovered. All purchases are final and non-refundable. Tron is NOT supported on this endpoint (only EVM, Solana, Bitcoin). **Response envelope note**: this endpoint stands apart from the main router and returns a flat `{success, key, ...}` object — NOT the `{ok, data, meta}` envelope used by the main `/v1/*` router. Its error responses (400, 405, 409, 422) are likewise flat `{\"error\": \"...\"}` objects, matching POST /v1/keys/create.\n",
        "tags": [
          "Agent Onboarding"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "tier",
                  "email",
                  "appName",
                  "txHash",
                  "chainId"
                ],
                "properties": {
                  "tier": {
                    "type": "string",
                    "enum": [
                      "pro",
                      "enterprise"
                    ],
                    "description": "Pricing tier. Pro = $29, Enterprise = $99 (USD-equivalent for BTC payments)."
                  },
                  "email": {
                    "type": "string",
                    "format": "email",
                    "description": "Owner email for account recovery and renewal reminders."
                  },
                  "appName": {
                    "type": "string",
                    "maxLength": 100,
                    "description": "Name for this API key (e.g., your app or service name)."
                  },
                  "txHash": {
                    "type": "string",
                    "description": "Transaction hash proving payment of the tier-specific amount."
                  },
                  "chainId": {
                    "oneOf": [
                      {
                        "type": "integer"
                      },
                      {
                        "type": "string",
                        "enum": [
                          "solana",
                          "bitcoin"
                        ]
                      }
                    ],
                    "description": "EVM chain ID, or 'solana' / 'bitcoin'. Tron not supported on this endpoint."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "API key created with 30-day validity at the tier's limits",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Flat response — not wrapped in {ok, data, meta} envelope.",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "key": {
                      "type": "string",
                      "description": "Your new API key (store securely — shown only once)."
                    },
                    "tier": {
                      "type": "string",
                      "enum": [
                        "pro",
                        "enterprise"
                      ]
                    },
                    "dailyLimit": {
                      "type": "integer",
                      "description": "Pro = 10000, Enterprise = 100000."
                    },
                    "apiKeyCredits": {
                      "type": "integer",
                      "description": "Initial attestation credits. Pro = 100, Enterprise = 500."
                    },
                    "expiresAt": {
                      "type": "string",
                      "format": "date-time",
                      "description": "ISO 8601 timestamp 30 days from purchase. Key stops authenticating after this."
                    },
                    "validDays": {
                      "type": "integer",
                      "const": 30
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error (missing fields, invalid tier, malformed email, unsupported chainId)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed (only POST supported)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Transaction hash already used (replay protection)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "On-chain verification failed (wrong amount, wrong recipient, tx not found, insufficient confirmations)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/credits/buy": {
      "post": {
        "operationId": "buyCredits",
        "summary": "Buy verification credits with USDC, USDT, or BTC",
        "description": "Purchase verification credits by sending USDC, USDT, or BTC to the platform wallet (EVM USDC/USDT: `0xAd982CB19aCCa2923Df8F687C0614a7700255a23` — same on all chains; Solana USDC/USDT: `6a1mLjefhvSJX1sEX8PTnionbE9DqoYjU6F6bNkT4Ydr`; Bitcoin BTC: `bc1qg7qnerdhlmdn899zemtez5tcx2a2snc0dt9dt0`; Tron USDT-TRC20: `TC5yvwkAMakkXtUxYiu2Yn1xbBcwYuD6cn`) and providing the transaction hash. Volume discounts: $5–$99 = 25 credits/$1 ($0.04/call), $100–$499 = 33 credits/$1 ($0.03/call, 25% off), $500+ = 50 credits/$1 ($0.02/call, 50% off). USDC and USDT accepted on EVM chains and Solana (auto-detected from transaction). USDT-TRC20 accepted on Tron. BTC accepted on Bitcoin (converted to USD at market rate, requires 1 confirmation). Crypto sent on unsupported chains cannot be recovered. All purchases are final and non-refundable. Sender verification: the first purchase registers the sender wallet address to the API key. Subsequent purchases must come from the same sender wallet. To change the registered wallet, include `\"updateWallet\": true` — the verified transfer from the new address proves ownership. `updateWallet` is ignored for wallet-auth callers (the SIWE signer is already bound to the registered wallet, and the soulbound pass cannot follow a wallet rotation). Authentication: this endpoint accepts EITHER the X-API-Key header OR the Authorization: Wallet header (SIWE envelope from a wallet that holds the Insumer Access pass). Wallet-auth callers let an SBT-holding agent top up without ever handling an API key.\n",
        "tags": [
          "Agent Onboarding"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "WalletAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "txHash",
                  "chainId"
                ],
                "properties": {
                  "txHash": {
                    "type": "string",
                    "description": "Transaction hash proving payment"
                  },
                  "chainId": {
                    "$ref": "#/components/schemas/PaymentChainId"
                  },
                  "amount": {
                    "type": "number",
                    "minimum": 5,
                    "description": "Stablecoin amount sent (min 5). Not required for BTC."
                  },
                  "updateWallet": {
                    "type": "boolean",
                    "default": false,
                    "description": "Set true to replace the registered sender wallet with this transaction's sender"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Credits purchased",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "creditsAdded": {
                          "type": "integer"
                        },
                        "totalCredits": {
                          "type": "integer"
                        },
                        "usdcPaid": {
                          "type": "string"
                        },
                        "effectiveRate": {
                          "type": "string",
                          "description": "Effective USD cost per credit for this purchase (e.g. \"$0.0400/credit\")."
                        },
                        "chainName": {
                          "type": "string"
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "Transaction sender does not match the wallet registered to this API key (include updateWallet: true to re-register)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "Transaction already used",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "422": {
            "description": "On-chain verification failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "description": "On-chain verification temporarily unavailable. Retry in a few seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/v1/merchants": {
      "get": {
        "operationId": "listMerchants",
        "summary": "List merchants in public directory",
        "description": "Browse merchants with optional filters. Returns public directory listings. A store whose recognition is paused is left out.",
        "tags": [
          "Discovery"
        ],
        "security": [],
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by accepted token symbol (e.g. UNI)"
          },
          {
            "name": "verified",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            },
            "description": "Filter by domain verification status"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 200
            },
            "description": "Results per page"
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Pagination offset"
          }
        ],
        "responses": {
          "200": {
            "description": "Merchant list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/MerchantSummary"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "total": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        },
                        "offset": {
                          "type": "integer"
                        },
                        "version": {
                          "type": "string"
                        },
                        "timestamp": {
                          "type": "string",
                          "format": "date-time"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "post": {
        "operationId": "createMerchant",
        "summary": "Create a new merchant",
        "description": "Create a merchant programmatically. The API key that creates the merchant owns it and pays for it: each discount code or NFC tap at the store that carries a discount uses one regular credit from that key (a 0% result is free), and so does every in-store scan. The store has no credit balance of its own. A key can create a limited number of merchants (429 past it).\n",
        "tags": [
          "Merchant Setup"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "companyName",
                  "companyId"
                ],
                "properties": {
                  "companyName": {
                    "type": "string",
                    "maxLength": 100,
                    "description": "Display name"
                  },
                  "companyId": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 50,
                    "pattern": "^[a-zA-Z0-9_-]+$",
                    "description": "Unique ID (alphanumeric, dash, underscore)"
                  },
                  "location": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "City or region"
                  },
                  "externalId": {
                    "type": "string",
                    "maxLength": 100,
                    "description": "Optional partner handle for this merchant (e.g. a token collection address). Makes the call an idempotent upsert and requires domain verification before the merchant can publish to the directory.\n"
                  },
                  "allowDuplicateName": {
                    "type": "boolean",
                    "description": "Set true to allow creating a merchant whose companyName matches an existing merchant. Without it, a duplicate name is rejected with 409."
                  }
                }
              },
              "example": {
                "companyName": "Acme Coffee",
                "companyId": "ACME-COFFEE",
                "location": "New York, NY"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Merchant already exists and is managed by this same API key — returned as an idempotent upsert (the existing merchant) instead of a 409.\n",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "companyName": {
                          "type": "string"
                        },
                        "credits": {
                          "type": "integer"
                        },
                        "apiAccessEnabled": {
                          "type": "boolean"
                        },
                        "alreadyExists": {
                          "type": "boolean",
                          "const": true
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "201": {
            "description": "Merchant created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "companyName": {
                          "type": "string"
                        },
                        "credits": {
                          "type": "integer",
                          "description": "Current credits of the owner API key, which pays for this store's codes, scans and taps."
                        },
                        "apiAccessEnabled": {
                          "type": "boolean"
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "Merchant ID already exists and is owned by a different API key, or a merchant with the same companyName already exists (set allowDuplicateName: true to override)\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "A key can create a limited number of merchants (429 past it), or daily rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/merchants/{id}": {
      "get": {
        "operationId": "getMerchant",
        "summary": "Get merchant details",
        "description": "Returns full public merchant profile including token tiers and NFT collections. 404 while the store's recognition is paused.",
        "tags": [
          "Discovery"
        ],
        "security": [],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Merchant ID"
          }
        ],
        "responses": {
          "200": {
            "description": "Merchant details",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/MerchantDetail"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid merchant ID format",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "Merchant not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/tokens": {
      "get": {
        "operationId": "listTokens",
        "summary": "List registered tokens and NFTs",
        "description": "Returns all tokens and NFT collections in the registry, with optional filters.",
        "tags": [
          "Discovery"
        ],
        "security": [],
        "parameters": [
          {
            "name": "chain",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/ChainId"
            },
            "description": "Filter by chain ID"
          },
          {
            "name": "symbol",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by token symbol"
          },
          {
            "name": "type",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "token",
                "nft"
              ]
            },
            "description": "Filter by asset type"
          }
        ],
        "responses": {
          "200": {
            "description": "Token and NFT registry",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "tokens": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string"
                              },
                              "symbol": {
                                "type": "string"
                              },
                              "name": {
                                "type": "string"
                              },
                              "chainId": {
                                "$ref": "#/components/schemas/ChainId"
                              },
                              "chainName": {
                                "type": "string"
                              },
                              "contractAddress": {
                                "type": "string"
                              },
                              "decimals": {
                                "type": "integer"
                              },
                              "logo": {
                                "type": "string"
                              }
                            }
                          }
                        },
                        "nfts": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string"
                              },
                              "name": {
                                "type": "string"
                              },
                              "contractAddress": {
                                "type": "string"
                              },
                              "chainId": {
                                "$ref": "#/components/schemas/ChainId"
                              },
                              "chainName": {
                                "type": "string"
                              },
                              "image": {
                                "type": "string"
                              },
                              "standard": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "tokenCount": {
                          "type": "integer"
                        },
                        "nftCount": {
                          "type": "integer"
                        },
                        "version": {
                          "type": "string"
                        },
                        "timestamp": {
                          "type": "string",
                          "format": "date-time"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/discount/check": {
      "get": {
        "operationId": "checkDiscount",
        "summary": "Calculate discount for wallet at merchant",
        "description": "Checks on-chain balances server-side and calculates the total discount. Free to call: it does not consume credits. Returns tier and discount per token, but never raw balance amounts. A frozen XRPL trust line earns no tier.\n",
        "tags": [
          "Discounts & Codes"
        ],
        "security": [],
        "parameters": [
          {
            "name": "wallet",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "EVM wallet address (0x...)"
          },
          {
            "name": "solanaWallet",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Solana wallet address (base58)"
          },
          {
            "name": "xrplWallet",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "XRPL wallet address (classic r-address). The base58 checksum is verified; an address that fails it returns 400."
          },
          {
            "name": "merchant",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Merchant ID"
          }
        ],
        "responses": {
          "200": {
            "description": "Discount calculation",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "eligible": {
                          "type": "boolean"
                        },
                        "totalDiscount": {
                          "type": "integer"
                        },
                        "discountMode": {
                          "type": "string",
                          "enum": [
                            "highest",
                            "stack",
                            "capped"
                          ]
                        },
                        "breakdown": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/DiscountBreakdown"
                          }
                        },
                        "merchantId": {
                          "type": "string"
                        },
                        "merchantName": {
                          "type": "string"
                        },
                        "chainsChecked": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "walletTerms": {
                          "$ref": "#/components/schemas/WalletTerms"
                        },
                        "discountIfProven": {
                          "type": "integer",
                          "description": "Present only when the store gives wallets without proof less. totalDiscount is then what /v1/verify gives without a walletProof, and this is what it gives with one.\n"
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "Merchant not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "The store's recognition is paused by its owner: \"This store's recognition is paused.\" No credit is used and no code is created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "description": "A read did not complete. Nothing is concluded about the wallet. Retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RpcFailureEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/v1/verify": {
      "post": {
        "operationId": "createVerification",
        "summary": "Create signed discount code",
        "description": "Creates a signed discount verification code (INSR-XXXXX) valid for 30 minutes. A code that carries a discount costs 1 regular credit from the API key that owns the store (the key that created it); a 0% result is free. A caller using another key is not charged; when the caller is the owner key, the caller's key pays. Stores run through a licensed platform such as Skye Meta are covered by that platform's license. If merchant has Stripe Connect, a coupon is auto-created. The order is fixed: the result is signed first, then the credit is taken and the code is stored together, and a coupon is created only after the code exists. A result that cannot be signed, or a code that cannot be stored, is a 503 in the standard error envelope with no credit used and no code created. A retry after a timeout on the caller's side is a new verification: if the first request completed, it used a credit and created a code, and the retry does both again. A coupon that cannot be created leaves a valid code with stripeCodeCreated false.\n",
        "tags": [
          "Discounts & Codes"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "merchantId"
                ],
                "description": "At least one of `wallet` (EVM), `solanaWallet` or `xrplWallet` is required; a request with none is a 400.",
                "properties": {
                  "merchantId": {
                    "type": "string"
                  },
                  "wallet": {
                    "type": "string",
                    "description": "EVM wallet address"
                  },
                  "solanaWallet": {
                    "type": "string",
                    "description": "Solana wallet address"
                  },
                  "xrplWallet": {
                    "type": "string",
                    "description": "XRPL wallet address (classic r-address). The base58 checksum is verified; an address that fails it returns 400."
                  },
                  "walletProof": {
                    "$ref": "#/components/schemas/WalletProof"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verification code created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "verified": {
                          "type": "boolean"
                        },
                        "totalDiscount": {
                          "type": "integer"
                        },
                        "code": {
                          "type": "string",
                          "description": "Format: INSR-XXXXX",
                          "example": "INSR-A7K3M"
                        },
                        "expiresAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "breakdown": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/DiscountBreakdown"
                          }
                        },
                        "stripeCodeCreated": {
                          "type": "boolean"
                        },
                        "cloverDiscountName": {
                          "type": "string",
                          "nullable": true
                        },
                        "merchantName": {
                          "type": "string"
                        },
                        "sig": {
                          "type": "string",
                          "description": "ECDSA P-256 signature"
                        },
                        "walletProven": {
                          "type": "boolean",
                          "description": "True when the request carried a valid walletProof. Not part of the signed result."
                        },
                        "discountIfProven": {
                          "type": "integer",
                          "description": "Present only when the store limits unproven wallets and this wallet would get more with a walletProof: the discount it would get."
                        },
                        "usdcPayment": {
                          "type": "object",
                          "nullable": true,
                          "description": "Present when merchant has USDC payments enabled",
                          "properties": {
                            "evmAddress": {
                              "type": "string"
                            },
                            "preferredChainId": {
                              "type": "integer"
                            },
                            "preferredChainName": {
                              "type": "string"
                            },
                            "usdcContract": {
                              "type": "string"
                            },
                            "solanaAddress": {
                              "type": "string",
                              "nullable": true
                            },
                            "supportedChains": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "chainId": {
                                    "type": "integer"
                                  },
                                  "name": {
                                    "type": "string"
                                  },
                                  "usdcContract": {
                                    "type": "string"
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key, or a walletProof that fails (wrong wallet, store, domain, expired, or nonce already used). No credit is used.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "402": {
            "description": "The API key that owns this store has no credits remaining. Its owner can buy more via POST /v1/credits/buy. Returned only when the result carries a discount. No credit is used and no code is created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "Merchant has not enabled API access, or the store has no active owner API key (\"This store has no active owner API key, so it cannot issue codes or record scans and taps.\")",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "Merchant not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "The store's recognition is paused by its owner: \"This store's recognition is paused.\" No credit is used and no code is created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. Either the key's daily limit (the response carries Retry-After and the X-RateLimit headers), or this wallet, sent without a walletProof, has reached the store's own limit on discount codes per day (maxDiscountsPerWalletPerDay in merchant settings; no credit used, no code created; resets at 00:00 UTC). The limit does not apply to a proven wallet. Paid discount codes requested with a key other than the store's owner are subject to an hourly limit (429; the message says when to try again): \"The hourly limit on discount codes has been reached. Try again in N minutes.\" No credit is used and no code is created.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "description": "Data source unavailable after retries. No discount code signed, no credits charged. Retryable after a short delay. A verification that could not be signed or stored is also a 503, in the standard error envelope (\"The verification could not be completed. No credit was used.\"): no credit used, no code created, equally retryable.\n",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/RpcFailureEnvelope"
                    },
                    {
                      "$ref": "#/components/schemas/ErrorEnvelope"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/v1/payment/confirm": {
      "post": {
        "operationId": "confirmPayment",
        "summary": "Verify USDC payment for discount code",
        "description": "After /v1/verify, confirm that a USDC payment was made on-chain. The server checks the transaction receipt to verify USDC arrived at the merchant address.\n",
        "tags": [
          "Discounts & Codes"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "code",
                  "txHash",
                  "chainId",
                  "amount"
                ],
                "properties": {
                  "code": {
                    "type": "string",
                    "description": "Verification code (e.g. INSR-A7K3M)"
                  },
                  "txHash": {
                    "type": "string",
                    "description": "On-chain transaction hash or Solana signature"
                  },
                  "chainId": {
                    "oneOf": [
                      {
                        "type": "integer",
                        "enum": [
                          1,
                          8453,
                          137,
                          42161,
                          10,
                          56,
                          43114
                        ]
                      },
                      {
                        "type": "string",
                        "enum": [
                          "solana"
                        ]
                      }
                    ],
                    "description": "Chains accepted for USDC payment confirmation: Ethereum (1), Base (8453), Polygon (137), Arbitrum (42161), Optimism (10), BNB Chain (56), Avalanche (43114), or \"solana\". Bitcoin and Tron are not accepted here."
                  },
                  "amount": {
                    "oneOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "number"
                      }
                    ],
                    "description": "USDC amount sent"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Payment confirmed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "confirmed": {
                          "type": "boolean"
                        },
                        "code": {
                          "type": "string"
                        },
                        "txHash": {
                          "type": "string"
                        },
                        "chainId": {
                          "oneOf": [
                            {
                              "type": "integer",
                              "enum": [
                                1,
                                8453,
                                137,
                                42161,
                                10,
                                56,
                                43114
                              ]
                            },
                            {
                              "type": "string",
                              "enum": [
                                "solana"
                              ]
                            }
                          ]
                        },
                        "chainName": {
                          "type": "string"
                        },
                        "amountVerified": {
                          "type": "string"
                        },
                        "confirmedAt": {
                          "type": "string",
                          "format": "date-time"
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "Merchant USDC payments not enabled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "Code or merchant not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "Payment already confirmed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "410": {
            "description": "Code expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "422": {
            "description": "On-chain verification failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "description": "On-chain verification temporarily unavailable. Retry in a few seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/v1/merchants/{id}/tokens": {
      "put": {
        "operationId": "updateMerchantTokens",
        "summary": "Configure merchant token tiers",
        "description": "Set up the merchant's own token and/or partner tokens with discount tiers. Max 8 tokens total (own + partner). Must be called by the API key that created the merchant.\n",
        "tags": [
          "Merchant Setup"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Merchant ID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "ownToken": {
                    "oneOf": [
                      {
                        "$ref": "#/components/schemas/TokenConfig"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Merchant's own token config. Send null, or an object with `enabled: false`, to switch the own token off."
                  },
                  "partnerTokens": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/TokenConfig"
                    },
                    "description": "Partner token configs"
                  }
                }
              },
              "example": {
                "ownToken": {
                  "symbol": "ACME",
                  "chainId": 8453,
                  "contractAddress": "0x1234567890abcdef1234567890abcdef12345678",
                  "decimals": 18,
                  "tiers": [
                    {
                      "name": "Bronze",
                      "threshold": 100,
                      "discount": 5
                    },
                    {
                      "name": "Silver",
                      "threshold": 1000,
                      "discount": 10
                    },
                    {
                      "name": "Gold",
                      "threshold": 10000,
                      "discount": 15
                    }
                  ]
                },
                "partnerTokens": []
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Tokens configured",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "ownToken": {
                          "type": "object",
                          "nullable": true,
                          "properties": {
                            "symbol": {
                              "type": "string"
                            },
                            "tiersConfigured": {
                              "type": "integer"
                            }
                          }
                        },
                        "partnerTokens": {
                          "type": "array",
                          "items": {
                            "type": "object"
                          }
                        },
                        "totalTokens": {
                          "type": "integer"
                        },
                        "maxTokens": {
                          "type": "integer",
                          "example": 8
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "API key does not own this merchant",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "Merchant not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/merchants/{id}/nfts": {
      "put": {
        "operationId": "updateMerchantNfts",
        "summary": "Configure NFT collections",
        "description": "Set NFT collections that grant discounts. Max 4 collections. Must be called by the API key that created the merchant.\n",
        "tags": [
          "Merchant Setup"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Merchant ID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "nftCollections"
                ],
                "properties": {
                  "nftCollections": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/NftConfig"
                    },
                    "maxItems": 4
                  }
                }
              },
              "example": {
                "nftCollections": [
                  {
                    "name": "Acme Founders",
                    "contractAddress": "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D",
                    "chainId": 1,
                    "discount": 15
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "NFTs configured",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "nftCollections": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "name": {
                                "type": "string"
                              },
                              "discount": {
                                "type": "integer"
                              },
                              "chainId": {
                                "$ref": "#/components/schemas/ChainId"
                              }
                            }
                          }
                        },
                        "totalCollections": {
                          "type": "integer"
                        },
                        "maxCollections": {
                          "type": "integer",
                          "example": 4
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "API key does not own this merchant",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "Merchant not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/merchants/{id}/settings": {
      "put": {
        "operationId": "updateMerchantSettings",
        "summary": "Update merchant settings",
        "description": "Update discount stacking mode, cap, the store's terms for wallets sent without proof of control (a lower discount or none, and a daily limit), USDC payment settings, and whether the store's recognition is paused. All fields optional. Must be called by the API key that created the merchant.\n",
        "tags": [
          "Merchant Setup"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Merchant ID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "discountMode": {
                    "type": "string",
                    "enum": [
                      "highest",
                      "stack",
                      "capped"
                    ],
                    "description": "'highest' uses best single discount, 'stack' sums all, 'capped' sums all then caps at discountCap"
                  },
                  "discountCap": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 100,
                    "description": "Maximum total discount percentage: a whole number from 1 to 100. A value with a fraction (25.5) is a 400; \"25.0\" is accepted as 25."
                  },
                  "maxDiscountsPerWalletPerDay": {
                    "type": [
                      "integer",
                      "null"
                    ],
                    "minimum": 1,
                    "maximum": 100,
                    "description": "Optional. The store's own limit on discount codes per UTC day for a wallet sent without a walletProof, a whole number from 1 to 100; null removes the limit. Unset means no limit. The limit does not apply to a proven wallet. When an unproven wallet has reached it, /v1/verify, /v1/acp/discount and /v1/ucp/discount return 429 with no credit used and no code created. Only orders that earn a discount count. Only the day's count is held, and it is deleted after the day.\n"
                  },
                  "maxUnprovenDiscount": {
                    "type": [
                      "integer",
                      "null"
                    ],
                    "minimum": 0,
                    "maximum": 100,
                    "description": "Optional. What a wallet sent without a walletProof can get: at most this percent, a whole number from 0 to 100 (0 = no discount); null = the same as a proven wallet. Unset means the same. The verify response then carries discountIfProven, so the caller knows what proof would get. Published to agents in walletTerms on GET /v1/merchants and GET /v1/merchants/{id}.\n"
                  },
                  "usdcPayment": {
                    "oneOf": [
                      {
                        "type": "object",
                        "properties": {
                          "enabled": {
                            "type": "boolean"
                          },
                          "evmAddress": {
                            "type": "string",
                            "description": "EVM wallet for USDC (0x + 40 hex)"
                          },
                          "solanaAddress": {
                            "type": "string",
                            "description": "Solana wallet for USDC (base58)"
                          },
                          "preferredChainId": {
                            "$ref": "#/components/schemas/UsdcChainId"
                          }
                        }
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "USDC payment config, or null to disable"
                  },
                  "paused": {
                    "type": "boolean",
                    "description": "Optional. true pauses the store's recognition; false resumes it. While a store is paused, discount codes for it are refused (409 on /v1/verify, /v1/acp/discount, /v1/ucp/discount and /v1/discount/check; no credit used, no code created), /v1/pass/verify answers recognized false with paused true, it is left out of GET /v1/merchants, and its NFC stickers give no code. Resuming restores everything, including the same stickers. Idempotent.\n"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Settings updated",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "discountMode": {
                          "type": "string"
                        },
                        "discountCap": {
                          "type": "integer"
                        },
                        "maxDiscountsPerWalletPerDay": {
                          "type": [
                            "integer",
                            "null"
                          ]
                        },
                        "maxUnprovenDiscount": {
                          "type": [
                            "integer",
                            "null"
                          ]
                        },
                        "usdcPayment": {
                          "type": "object",
                          "nullable": true,
                          "properties": {
                            "enabled": {
                              "type": "boolean"
                            }
                          }
                        },
                        "paused": {
                          "type": "boolean",
                          "description": "Whether the store's recognition is paused."
                        },
                        "pausedAt": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time",
                          "description": "When the store was paused, or null."
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error or no fields provided",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "API key does not own this merchant",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "Merchant not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/merchants/{id}/credits": {
      "post": {
        "operationId": "buyMerchantCredits",
        "summary": "Buy credits for a store's owner key with USDC, USDT, or BTC (compatibility)",
        "description": "Kept for compatibility. Credits bought here go to the regular credit balance of the API key that owns the merchant, the same balance POST /v1/credits/buy tops up and the one that pays for the store's codes, scans and taps. The store has no balance of its own. Pricing: flat 25 credits per $1 ($0.04/call) at every purchase size. POST /v1/credits/buy is the normal way to top up and carries the volume tiers. Send to the platform wallet: EVM USDC/USDT `0xAd982CB19aCCa2923Df8F687C0614a7700255a23` (same on all chains), Solana USDC/USDT `6a1mLjefhvSJX1sEX8PTnionbE9DqoYjU6F6bNkT4Ydr`, Bitcoin BTC `bc1qg7qnerdhlmdn899zemtez5tcx2a2snc0dt9dt0`, Tron USDT-TRC20 `TC5yvwkAMakkXtUxYiu2Yn1xbBcwYuD6cn`. USDC and USDT auto-detected from EVM and Solana transactions. BTC accepted on Bitcoin (converted to USD at market rate, requires 1 confirmation). USDT-TRC20 accepted on Tron. Supported chains: Ethereum, Base, Polygon, Arbitrum, Optimism, BNB Chain, Avalanche, Solana, Bitcoin, Tron. Crypto sent on unsupported chains cannot be recovered. All purchases are final and non-refundable. Sender verification: the first purchase registers the sender wallet address to the API key. Subsequent purchases must come from the same sender wallet. To change the registered wallet, include `\"updateWallet\": true` — the verified transfer from the new address proves ownership.\n",
        "tags": [
          "Merchant Setup"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Merchant ID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "txHash",
                  "chainId"
                ],
                "properties": {
                  "txHash": {
                    "type": "string",
                    "description": "Transaction hash proving payment"
                  },
                  "chainId": {
                    "$ref": "#/components/schemas/PaymentChainId"
                  },
                  "amount": {
                    "type": "number",
                    "minimum": 5,
                    "description": "Stablecoin amount sent (min 5). Not required for BTC — USD value derived from on-chain BTC amount at market rate."
                  },
                  "updateWallet": {
                    "type": "boolean",
                    "default": false,
                    "description": "Set true to replace the registered sender wallet with this transaction's sender"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Credits purchased",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "creditsAdded": {
                          "type": "integer"
                        },
                        "totalCredits": {
                          "type": "integer"
                        },
                        "usdcPaid": {
                          "type": "string",
                          "description": "Stablecoin amount verified. Present on all purchases except Bitcoin."
                        },
                        "btcPaid": {
                          "type": "string",
                          "description": "BTC amount verified. Present on Bitcoin purchases; usdcPaid otherwise."
                        },
                        "btcPrice": {
                          "type": "number",
                          "description": "BTC/USD market rate used for conversion. Present on Bitcoin purchases; usdcPaid otherwise."
                        },
                        "usdEquivalent": {
                          "type": "string",
                          "description": "USD value credited. Present on Bitcoin purchases; usdcPaid otherwise."
                        },
                        "chainName": {
                          "type": "string"
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "API key does not own this merchant",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "Merchant not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "Transaction already used",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "422": {
            "description": "On-chain verification failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "description": "On-chain verification temporarily unavailable. Retry in a few seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/v1/merchants/{id}/directory": {
      "post": {
        "operationId": "publishToDirectory",
        "summary": "Publish or unpublish merchant in public directory",
        "description": "Publish (or refresh) the merchant's listing in the public directory. No request body needed to publish — call again after updating tokens/settings. Send `{ \"listed\": false }` to unpublish (delist); the company and its tokens stay intact, only the public entry is removed. Partner-provisioned merchants (created with an externalId) must pass domain verification before they can publish — an unverified one is rejected with 403.\n",
        "tags": [
          "Merchant Setup"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Merchant ID"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "listed": {
                    "type": "boolean",
                    "description": "Set to false to unpublish (delist) the merchant. Omit to publish/refresh."
                  },
                  "ownerCredential": {
                    "type": "object",
                    "description": "Optional owner credential to record in the domain-ownership ledger when publishing a merchant with a verified domain (defaults to the managing API key). Lets a partner name the end customer's own credential as the domain owner of record.",
                    "properties": {
                      "type": {
                        "type": "string",
                        "enum": [
                          "license",
                          "key",
                          "wallet",
                          "uid"
                        ]
                      },
                      "id": {
                        "type": "string",
                        "maxLength": 200
                      }
                    }
                  }
                }
              },
              "example": {
                "listed": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Published, or unpublished when listed=false",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "published": {
                          "type": "boolean"
                        },
                        "tokensListed": {
                          "type": "integer"
                        },
                        "nftCollectionsListed": {
                          "type": "integer"
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "API key does not own this merchant, or a partner-provisioned merchant (externalId set) has not passed domain verification yet.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "Merchant not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "The merchant's verified domain is already registered to another owner in the domain-ownership ledger. A claim has been opened; the current owner must approve it before this listing can publish.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/merchants/{id}/status": {
      "get": {
        "operationId": "getMerchantStatus",
        "summary": "Get full private merchant details",
        "description": "Returns full details including credits, token configs, directory status, verification status, and USDC settings. Only accessible by the API key that created the merchant.\n",
        "tags": [
          "Merchant Setup"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Merchant ID"
          }
        ],
        "responses": {
          "200": {
            "description": "Full merchant status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "companyName": {
                          "type": "string"
                        },
                        "location": {
                          "type": "string"
                        },
                        "credits": {
                          "type": "integer",
                          "description": "Credits of the owner API key (the key that created this merchant). That key pays for the store's codes, scans and taps; the store has no balance of its own."
                        },
                        "apiAccessEnabled": {
                          "type": "boolean"
                        },
                        "discountMode": {
                          "type": "string",
                          "enum": [
                            "highest",
                            "stack",
                            "capped"
                          ]
                        },
                        "discountCap": {
                          "type": "integer"
                        },
                        "maxDiscountsPerWalletPerDay": {
                          "type": [
                            "integer",
                            "null"
                          ],
                          "description": "The store's limit on discount codes per UTC day for a wallet without proof; null = no limit."
                        },
                        "maxUnprovenDiscount": {
                          "type": [
                            "integer",
                            "null"
                          ],
                          "description": "The most a wallet without proof can get, in percent; 0 = nothing; null = the same as proven."
                        },
                        "paused": {
                          "type": "boolean",
                          "description": "Whether the store's recognition is paused (see PUT /v1/merchants/{id}/settings)."
                        },
                        "pausedAt": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time",
                          "description": "When the store was paused, or null."
                        },
                        "listedInDirectory": {
                          "type": "boolean"
                        },
                        "ownToken": {
                          "type": "object",
                          "nullable": true
                        },
                        "partnerTokens": {
                          "type": "array",
                          "items": {
                            "type": "object"
                          }
                        },
                        "nftCollections": {
                          "type": "array",
                          "items": {
                            "type": "object"
                          }
                        },
                        "usdcPayment": {
                          "type": "object",
                          "nullable": true,
                          "properties": {
                            "enabled": {
                              "type": "boolean"
                            },
                            "evmAddress": {
                              "type": "string"
                            },
                            "solanaAddress": {
                              "type": "string",
                              "nullable": true
                            }
                          }
                        },
                        "verification": {
                          "type": "object",
                          "description": "Domain verification status (token is never exposed here)",
                          "properties": {
                            "status": {
                              "type": "string",
                              "enum": [
                                "unverified",
                                "pending",
                                "verified"
                              ]
                            },
                            "domain": {
                              "type": "string",
                              "nullable": true
                            },
                            "method": {
                              "type": "string",
                              "nullable": true,
                              "enum": [
                                "dns",
                                "meta",
                                "file",
                                "partner"
                              ]
                            },
                            "verifiedAt": {
                              "type": "string",
                              "format": "date-time",
                              "nullable": true
                            }
                          }
                        },
                        "createdAt": {
                          "type": "string",
                          "format": "date-time",
                          "nullable": true,
                          "description": "ISO 8601 creation timestamp"
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "API key does not own this merchant",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "Merchant not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/merchants/{id}/domain-verification": {
      "post": {
        "operationId": "requestDomainVerification",
        "summary": "Request domain verification token",
        "description": "Generates a verification token for proving domain ownership. The token can be placed via DNS TXT record, HTML meta tag, or a verification file. Each POST regenerates the token, invalidating any previous one. Only the API key that created the merchant can call this.\n",
        "tags": [
          "Merchant Setup"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Merchant ID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "domain"
                ],
                "properties": {
                  "domain": {
                    "type": "string",
                    "description": "Domain to verify (e.g. example.com). No protocol prefix."
                  }
                }
              },
              "example": {
                "domain": "acme-coffee.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verification token generated",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "domain": {
                          "type": "string"
                        },
                        "token": {
                          "type": "string",
                          "description": "Verification token (insumer-XXXXXXXXXXXXXXXX)"
                        },
                        "methods": {
                          "type": "object",
                          "properties": {
                            "dns": {
                              "type": "object",
                              "properties": {
                                "type": {
                                  "type": "string",
                                  "example": "TXT"
                                },
                                "host": {
                                  "type": "string"
                                },
                                "value": {
                                  "type": "string"
                                },
                                "instructions": {
                                  "type": "string"
                                }
                              }
                            },
                            "meta": {
                              "type": "object",
                              "properties": {
                                "tag": {
                                  "type": "string"
                                },
                                "instructions": {
                                  "type": "string"
                                }
                              }
                            },
                            "file": {
                              "type": "object",
                              "properties": {
                                "path": {
                                  "type": "string"
                                },
                                "content": {
                                  "type": "string"
                                },
                                "instructions": {
                                  "type": "string"
                                }
                              }
                            }
                          }
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid domain format or missing domain",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "API key does not own this merchant",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "Merchant not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "put": {
        "operationId": "verifyDomain",
        "summary": "Trigger domain verification check",
        "description": "Checks all three verification methods (DNS TXT, meta tag, file) for the previously requested domain. Rate limited per merchant (429 says when to retry). If already verified, returns the existing verification result. Only the API key that created the merchant can call this.\n",
        "tags": [
          "Merchant Setup"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Merchant ID"
          }
        ],
        "responses": {
          "200": {
            "description": "Verification result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "verified": {
                          "type": "boolean"
                        },
                        "domain": {
                          "type": "string"
                        },
                        "method": {
                          "type": "string",
                          "enum": [
                            "dns",
                            "meta",
                            "file"
                          ],
                          "description": "Present only when verified is true"
                        },
                        "verifiedAt": {
                          "type": "string",
                          "format": "date-time",
                          "description": "Present only when verified is true"
                        },
                        "message": {
                          "type": "string",
                          "description": "Present only when verified is false"
                        },
                        "attemptsRemaining": {
                          "type": "integer",
                          "description": "Present only when verified is false"
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "No verification pending",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "API key does not own this merchant",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "Merchant not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (verification attempts for this merchant, or the key's daily request limit; the message says when to retry)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/merchants/{id}/verification": {
      "put": {
        "operationId": "partnerAssertDomain",
        "summary": "White-label partner asserts domain ownership",
        "description": "Record that a managing white-label partner verified an organization's domain in its own branded flow, so the org can publish to the directory without ever seeing an Insumer-branded challenge. Sets verification.status=verified with method=partner. RESTRICTED to designated white-label partner keys — a normal self-serve key cannot assert verification this way and must use the domain-verification challenge flow (POST/PUT /v1/merchants/{id}/domain-verification).\n",
        "tags": [
          "Merchant Setup"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Merchant ID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "domain"
                ],
                "properties": {
                  "domain": {
                    "type": "string",
                    "description": "Domain the partner verified (no protocol prefix)."
                  },
                  "ownerCredential": {
                    "type": "object",
                    "description": "Optional end-customer credential to record as the domain owner of record in the ownership ledger (defaults to the partner key). Lets the partner distinguish the community that actually owns the domain from the shared pool key.",
                    "properties": {
                      "type": {
                        "type": "string",
                        "enum": [
                          "license",
                          "key",
                          "wallet",
                          "uid"
                        ]
                      },
                      "id": {
                        "type": "string",
                        "maxLength": 200
                      }
                    }
                  },
                  "notify": {
                    "type": "string",
                    "description": "Optional notification contact recorded with the domain binding, used for ownership-claim notices."
                  }
                }
              },
              "example": {
                "domain": "acme-coffee.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Domain marked verified",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "verified": {
                          "type": "boolean",
                          "const": true
                        },
                        "domain": {
                          "type": "string"
                        },
                        "method": {
                          "type": "string",
                          "const": "partner"
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "A valid domain is required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "Key is not a white-label partner key, or does not manage this merchant",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "Merchant not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/registry/submit": {
      "post": {
        "operationId": "submitToRegistry",
        "summary": "Submit a token or NFT to the public registry (pending review)",
        "description": "Submit a token or NFT collection to the public registry. X-API-Key required (free: no credits are charged; the key is only for accountability). A submission is held as pending until approved; some submissions are added at once (the response says which: `pending`, `active`). The submission is routed into one of two buckets by asset type: tokens (ERC-20 utility or ERC-3643 security, plus Solana SPL) and NFTs (ERC-721/1155, including ERC-5192 soulbound). Set `assetType` (\"token\"/\"nft\") explicitly, or it is inferred from `standard` (defaulting to NFT). A token submission requires `symbol`. Idempotent per chain + address: a re-submit of the same asset returns the existing entry rather than creating a duplicate. EVM addresses are normalized lowercase; Solana mint addresses are left as-is. Returns a flat envelope (no `data` wrapper). Rate limited (429).\n",
        "tags": [
          "Merchant Setup"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "chainId"
                ],
                "description": "Provide `contractAddress` (EVM) or `mintAddress` (Solana) along with `name` and `chainId`; if both are sent, `contractAddress` is used. A submission with neither is rejected with 400.\n",
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200
                  },
                  "assetType": {
                    "type": "string",
                    "enum": [
                      "token",
                      "nft"
                    ],
                    "description": "Which registry to list the submission in. \"token\": the token registry (ERC-20, ERC-3643, SPL and similar); \"nft\": the NFT registry (ERC-721/1155/5192). If omitted, inferred from `standard`, defaulting to \"nft\". A \"token\" submission requires `symbol`. `type` is accepted as an alias for this field.\n"
                  },
                  "contractAddress": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "EVM contract address. Provide this or mintAddress."
                  },
                  "mintAddress": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Solana mint address. Provide this or contractAddress."
                  },
                  "chainId": {
                    "oneOf": [
                      {
                        "type": "integer"
                      },
                      {
                        "type": "string"
                      }
                    ],
                    "description": "Positive integer for EVM, or the string \"solana\"."
                  },
                  "chainName": {
                    "type": "string",
                    "maxLength": 50
                  },
                  "symbol": {
                    "type": "string",
                    "maxLength": 20,
                    "description": "Ticker symbol. Required for token submissions; ignored for NFTs."
                  },
                  "decimals": {
                    "type": "integer",
                    "description": "Token decimals (token submissions only)."
                  },
                  "image": {
                    "type": "string",
                    "maxLength": 500,
                    "description": "Collection image URL (NFT submissions). For tokens, use `logo`."
                  },
                  "logo": {
                    "type": "string",
                    "maxLength": 500,
                    "description": "Token logo URL (token submissions). `image` is accepted as a fallback."
                  },
                  "standard": {
                    "type": "string",
                    "maxLength": 50,
                    "description": "e.g. ERC-721, ERC-20, ERC-3643. Used to infer `assetType` when it is omitted."
                  },
                  "website": {
                    "type": "string",
                    "maxLength": 500
                  },
                  "description": {
                    "type": "string",
                    "maxLength": 1000
                  },
                  "coingeckoId": {
                    "type": "string",
                    "maxLength": 100,
                    "description": "CoinGecko id for market-cap lookup (token submissions only)."
                  },
                  "source": {
                    "type": "string",
                    "maxLength": 50,
                    "description": "Provenance tag shown in the admin review queue (e.g. \"partner-app\")."
                  }
                }
              },
              "examples": {
                "nft": {
                  "summary": "NFT collection (ERC-721)",
                  "value": {
                    "name": "Acme Founders",
                    "assetType": "nft",
                    "contractAddress": "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D",
                    "chainId": 8453,
                    "chainName": "Base",
                    "standard": "ERC-721",
                    "source": "partner-app"
                  }
                },
                "token": {
                  "summary": "Security token (ERC-3643)",
                  "value": {
                    "name": "Acme Equity",
                    "assetType": "token",
                    "symbol": "ACME",
                    "contractAddress": "0x80dE9bCc7540DCcb9cD7826F9dd19099B876aF54",
                    "chainId": 8453,
                    "chainName": "Base",
                    "decimals": 18,
                    "standard": "ERC-3643",
                    "source": "partner-app"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Already listed (idempotent)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "alreadyListed": {
                      "type": "boolean",
                      "const": true
                    },
                    "pending": {
                      "type": "boolean"
                    },
                    "active": {
                      "type": "boolean"
                    },
                    "docId": {
                      "type": "string"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "201": {
            "description": "Submitted (pending review)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "pending": {
                      "type": "boolean",
                      "description": "Whether the submission awaits human review. false when the submitting key is registry-trusted (the entry goes live immediately)."
                    },
                    "active": {
                      "type": "boolean",
                      "description": "Whether the entry is live in the registry. true only for registry-trusted keys; mirrors the inverse of pending."
                    },
                    "docId": {
                      "type": "string"
                    },
                    "assetType": {
                      "type": "string",
                      "enum": [
                        "token",
                        "nft"
                      ],
                      "description": "Which bucket the submission was routed into."
                    },
                    "message": {
                      "type": "string"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing name/contractAddress/chainId, or invalid chainId",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed (only POST supported)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Submission limit reached",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/merchants/{id}/scanners": {
      "post": {
        "operationId": "manageMerchantScanners",
        "summary": "Add or remove an in-person scanner PIN",
        "description": "Add or remove a scanner PIN on a merchant you manage, so a partner can run a login-less branded scanner with no account of its own. Only the API key that created the merchant can call this. A merchant can hold a limited number of scanners. PINs are stored salted + hashed and are never returned. Send `{ name?, pin }` to add, or `{ remove: scannerId }` to remove.\n",
        "tags": [
          "Point of Sale"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Merchant ID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "object",
                    "required": [
                      "pin"
                    ],
                    "properties": {
                      "name": {
                        "type": "string",
                        "maxLength": 50,
                        "description": "Scanner label (defaults to \"Register\")."
                      },
                      "pin": {
                        "type": "string",
                        "pattern": "^\\d{4,8}$",
                        "description": "4-8 digit PIN."
                      }
                    }
                  },
                  {
                    "type": "object",
                    "required": [
                      "remove"
                    ],
                    "properties": {
                      "remove": {
                        "type": "string",
                        "description": "Scanner id to remove."
                      }
                    }
                  }
                ]
              },
              "examples": {
                "add": {
                  "value": {
                    "name": "Front Register",
                    "pin": "4821"
                  }
                },
                "remove": {
                  "value": {
                    "remove": "a1b2c3d4e5f6"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Scanner removed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "removed": {
                          "type": "string"
                        },
                        "totalScanners": {
                          "type": "integer"
                        },
                        "changed": {
                          "type": "boolean"
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "201": {
            "description": "Scanner added",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        },
                        "totalScanners": {
                          "type": "integer"
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "PIN not 4-8 digits, or the merchant has reached its limit on scanners",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "API key does not own this merchant",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "Merchant not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "get": {
        "operationId": "listMerchantScanners",
        "summary": "List a merchant's scanners",
        "description": "List the scanners configured on a merchant you manage. Owner key only. Returns id and name only — PINs are never exposed.\n",
        "tags": [
          "Point of Sale"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Merchant ID"
          }
        ],
        "responses": {
          "200": {
            "description": "Scanner list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "scanners": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string"
                              },
                              "name": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "API key does not own this merchant",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "Merchant not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/scanner/session": {
      "post": {
        "operationId": "scannerSession",
        "summary": "Validate a scanner PIN and return merchant config",
        "description": "Validate a scanner PIN and return the merchant config for a login-less branded scanner. Owner key only (the partner key that provisioned the merchant). Lets a scanner with no account of its own authenticate with just the merchant id + a PIN. Repeated failed PIN attempts are limited per merchant (429).\n",
        "tags": [
          "Point of Sale"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "merchantId",
                  "pin"
                ],
                "properties": {
                  "merchantId": {
                    "type": "string"
                  },
                  "pin": {
                    "type": "string",
                    "description": "4-8 digit PIN."
                  }
                }
              },
              "example": {
                "merchantId": "acme-coffee",
                "pin": "4821"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "PIN valid",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "valid": {
                          "type": "boolean",
                          "const": true
                        },
                        "scannerId": {
                          "type": "string"
                        },
                        "scannerName": {
                          "type": "string"
                        },
                        "merchantName": {
                          "type": "string"
                        },
                        "discountMode": {
                          "type": "string",
                          "enum": [
                            "highest",
                            "stack",
                            "capped"
                          ]
                        },
                        "discountCap": {
                          "type": "integer"
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing merchantId or pin",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Invalid scanner code or PIN",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "API key does not own this merchant",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "Merchant not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Too many failed PIN attempts, or the key's daily request limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/pass/verify": {
      "post": {
        "operationId": "verifyPass",
        "summary": "Verify a scanned pass and compute the discount",
        "description": "Verify a scanned pass and compute the discount. X-API-Key required (metered on the partner key). All cryptography stays server-side: InsumerAPI verifies the ECDSA signature on the scanned QR, enforces 65-second freshness, then computes the discount against the merchant config. The partner's scanner only displays the result. A bad signature is rejected with no discount. There is deliberately no companion \"sign\" endpoint — passes are issued by InsumerAPI's own pass surface; signing is the primitive and is never exposed as an API call.\n",
        "tags": [
          "Point of Sale"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "merchantId",
                  "qr"
                ],
                "properties": {
                  "merchantId": {
                    "type": "string"
                  },
                  "qr": {
                    "type": "object",
                    "description": "The scanned pass object exactly as encoded, including its `sig`. The signed bytes are the QR object with `sig` removed, re-serialized (`sig` is always the last key).\n",
                    "properties": {
                      "w": {
                        "type": "string",
                        "description": "Truncated wallet address."
                      },
                      "t": {
                        "type": "string",
                        "description": "Encoded token balances."
                      },
                      "nft": {
                        "type": "string",
                        "description": "Encoded NFT holdings."
                      },
                      "ts": {
                        "type": "integer",
                        "description": "Issue timestamp in ms (65-second freshness window)."
                      },
                      "n": {
                        "type": "string",
                        "description": "Nonce."
                      },
                      "sig": {
                        "type": "string",
                        "description": "Base64 P1363 ECDSA signature."
                      }
                    },
                    "required": [
                      "sig"
                    ]
                  }
                }
              },
              "example": {
                "merchantId": "acme-coffee",
                "qr": {
                  "w": "0x1234…5678",
                  "t": "ACME:1500.00@8453",
                  "ts": 1749150000000,
                  "n": "a1b2c3",
                  "sig": "<base64 P1363 ECDSA signature>"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Pass verified",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "recognized": {
                          "type": "boolean"
                        },
                        "matched": {
                          "type": "array",
                          "description": "Which configured assets the pass holds. A superset of breakdown: recognition entries carry no discount.",
                          "items": {
                            "type": "object",
                            "properties": {
                              "symbol": {
                                "type": "string",
                                "description": "Token symbol, or collection name for NFTs"
                              },
                              "kind": {
                                "type": "string",
                                "enum": [
                                  "token",
                                  "nft"
                                ]
                              }
                            }
                          }
                        },
                        "configured": {
                          "type": "integer",
                          "description": "How many assets this merchant recognizes at all. Distinguishes \"nothing configured yet\" from \"pass not recognized\"."
                        },
                        "discount": {
                          "type": "integer"
                        },
                        "breakdown": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "symbol": {
                                "type": "string"
                              },
                              "tier": {
                                "type": "string"
                              },
                              "discount": {
                                "type": "integer"
                              }
                            }
                          }
                        },
                        "merchantName": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "The merchant's display name, or null when none is configured."
                        },
                        "paused": {
                          "type": "boolean",
                          "description": "Present and true when the store's owner has paused its recognition: recognized is false, discount is 0, and configured still counts what the store recognizes. Show the store as paused, not as unconfigured."
                        }
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing merchantId, or qr/sig",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Invalid signature or expired pass",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "Merchant not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/acp/discount": {
      "post": {
        "operationId": "acpDiscount",
        "summary": "ACP-format discount eligibility check",
        "description": "ACP discount check. Same verification as POST /v1/verify, wrapped in OpenAI/Stripe Agentic Commerce Protocol format (coupon objects, allocations, applied/rejected arrays). A code that carries a discount costs 1 regular credit from the API key that owns the store; a 0% result is free. A caller using another key is not charged. Source: \"acp\".\n",
        "tags": [
          "Agent Commerce Protocols"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "merchantId"
                ],
                "description": "At least one of `wallet` (EVM), `solanaWallet` or `xrplWallet` is required; a request with none is a 400.",
                "properties": {
                  "merchantId": {
                    "type": "string",
                    "description": "Merchant identifier"
                  },
                  "wallet": {
                    "type": "string",
                    "description": "EVM wallet address (0x...)"
                  },
                  "solanaWallet": {
                    "type": "string",
                    "description": "Solana wallet address"
                  },
                  "xrplWallet": {
                    "type": "string",
                    "description": "XRPL wallet address (classic r-address). The base58 checksum is verified; an address that fails it returns 400."
                  },
                  "walletProof": {
                    "$ref": "#/components/schemas/WalletProof"
                  },
                  "items": {
                    "type": "array",
                    "description": "Optional line items. Supply these (or subtotal) to receive an applied discount entry: ACP's applied_discount requires an integer amount in minor units, and coupon.percent_off does not substitute for it. Allocations always sum exactly to the discount amount.\n",
                    "items": {
                      "type": "object",
                      "properties": {
                        "path": {
                          "type": "string",
                          "description": "JSONPath reference to the line item",
                          "example": "$.line_items[0]"
                        },
                        "amount": {
                          "type": "number",
                          "minimum": 0,
                          "description": "Item price in minor units (cents for USD); a fraction is truncated",
                          "example": 2500
                        }
                      }
                    }
                  },
                  "subtotal": {
                    "type": "number",
                    "minimum": 0,
                    "description": "Optional order-level base in minor units, for callers that do not send line items. Ignored when items[] is supplied. With neither, the response carries no applied entry; the verified discount is still returned in the verification object.\n",
                    "example": 5000
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "ACP-format discount response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "protocol": {
                          "type": "string",
                          "const": "acp"
                        },
                        "version": {
                          "type": "string",
                          "description": "ACP release this payload targets",
                          "example": "2026-04-17"
                        },
                        "discounts": {
                          "type": "object",
                          "properties": {
                            "codes": {
                              "type": "array",
                              "description": "Echo of discount codes submitted by the caller. This endpoint accepts none, so this is always empty. The INSR redemption code is returned in the verification object.\n",
                              "items": {
                                "type": "string"
                              }
                            },
                            "applied": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "id": {
                                    "type": "string"
                                  },
                                  "coupon": {
                                    "type": "object",
                                    "properties": {
                                      "id": {
                                        "type": "string"
                                      },
                                      "name": {
                                        "type": "string"
                                      },
                                      "percent_off": {
                                        "type": "integer"
                                      }
                                    }
                                  },
                                  "amount": {
                                    "type": "integer",
                                    "minimum": 0,
                                    "description": "Discount total in minor units. Never null — the entry is omitted entirely when no monetary base was supplied.\n"
                                  },
                                  "automatic": {
                                    "type": "boolean",
                                    "const": true,
                                    "description": "Always true. The discount follows from wallet contents rather than a code anyone entered, so it is an automatic discount and the entry carries no code field.\n"
                                  },
                                  "method": {
                                    "type": "string"
                                  },
                                  "priority": {
                                    "type": "integer"
                                  },
                                  "allocations": {
                                    "type": "array",
                                    "items": {
                                      "type": "object",
                                      "properties": {
                                        "path": {
                                          "type": "string"
                                        },
                                        "amount": {
                                          "type": "integer"
                                        }
                                      }
                                    }
                                  },
                                  "start": {
                                    "type": "string",
                                    "format": "date-time"
                                  },
                                  "end": {
                                    "type": "string",
                                    "format": "date-time"
                                  }
                                }
                              }
                            },
                            "rejected": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "code": {
                                    "type": "string"
                                  },
                                  "reason": {
                                    "type": "string"
                                  }
                                }
                              }
                            }
                          }
                        },
                        "verification": {
                          "type": "object",
                          "properties": {
                            "code": {
                              "type": "string"
                            },
                            "expiresAt": {
                              "type": "string",
                              "format": "date-time"
                            },
                            "breakdown": {
                              "type": "array",
                              "items": {
                                "$ref": "#/components/schemas/DiscountBreakdown"
                              }
                            },
                            "sig": {
                              "type": "string"
                            },
                            "kid": {
                              "type": "string",
                              "description": "Always insumer-attest-v1. Commerce discount responses sign under the v1 scheme regardless of the API key's signing generation; resolve the public key from the JWKS by this kid.",
                              "example": "insumer-attest-v1"
                            },
                            "walletProven": {
                              "type": "boolean",
                              "description": "True when the request carried a valid walletProof. Not part of the signed result."
                            },
                            "discountIfProven": {
                              "type": "integer",
                              "description": "Present only when the store limits unproven wallets and a walletProof would get this wallet more."
                            }
                          }
                        }
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "creditsRemaining": {
                          "type": "integer",
                          "description": "Credits left on the caller's API key after this call. Never another key's balance."
                        },
                        "creditsCharged": {
                          "type": "integer",
                          "description": "1 when the caller's key owns the store and the code carries a discount (the caller's key paid); otherwise 0. A code at a store another key owns is paid by that key, which this field never shows."
                        },
                        "version": {
                          "type": "string"
                        },
                        "timestamp": {
                          "type": "string",
                          "format": "date-time"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key, or a walletProof that fails (wrong wallet, store, domain, expired, or nonce already used). No credit is used.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "402": {
            "description": "The API key that owns this store has no credits remaining. Its owner can buy more via POST /v1/credits/buy. Returned only when the result carries a discount. No credit is used and no code is created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "Merchant has not enabled third-party app access, or the store has no active owner API key (\"This store has no active owner API key, so it cannot issue codes or record scans and taps.\")",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "Merchant not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "The store's recognition is paused by its owner: \"This store's recognition is paused.\" No credit is used and no code is created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. Either the key's daily limit (the response carries Retry-After and the X-RateLimit headers), or this wallet, sent without a walletProof, has reached the store's own limit on discount codes per day (maxDiscountsPerWalletPerDay in merchant settings; no credit used, no code created; resets at 00:00 UTC). The limit does not apply to a proven wallet. Paid discount codes requested with a key other than the store's owner are subject to an hourly limit (429; the message says when to try again): \"The hourly limit on discount codes has been reached. Try again in N minutes.\" No credit is used and no code is created.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "description": "Data source unavailable — retryable after a short delay. No discount signed, no credits charged. A verification that could not be signed or stored is also a 503, in the standard error envelope: no credit used, no code created, equally retryable.\n",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/RpcFailureEnvelope"
                    },
                    {
                      "$ref": "#/components/schemas/ErrorEnvelope"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/v1/ucp/discount": {
      "post": {
        "operationId": "ucpDiscount",
        "summary": "UCP-format discount eligibility check",
        "description": "UCP discount check. Same verification as POST /v1/verify, returned as a dev.ucp.shopping.discount fragment (a discounts object, not a full UCP Cart or Checkout resource) matching UCP release 2026-08-25. A code that carries a discount costs 1 regular credit from the API key that owns the store; a 0% result is free. A caller using another key is not charged. Source: \"ucp\".\n",
        "tags": [
          "Agent Commerce Protocols"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "merchantId"
                ],
                "description": "At least one of `wallet` (EVM), `solanaWallet` or `xrplWallet` is required; a request with none is a 400.",
                "properties": {
                  "merchantId": {
                    "type": "string",
                    "description": "Merchant identifier"
                  },
                  "wallet": {
                    "type": "string",
                    "description": "EVM wallet address (0x...)"
                  },
                  "solanaWallet": {
                    "type": "string",
                    "description": "Solana wallet address"
                  },
                  "xrplWallet": {
                    "type": "string",
                    "description": "XRPL wallet address (classic r-address). The base58 checksum is verified; an address that fails it returns 400."
                  },
                  "walletProof": {
                    "$ref": "#/components/schemas/WalletProof"
                  },
                  "items": {
                    "type": "array",
                    "description": "Optional line items. Supply these (or subtotal) to receive an applied discount entry: UCP's applied_discount carries an absolute amount and has no percentage field, so without a monetary base no conformant entry can be returned. Allocations always sum exactly to the discount amount.\n",
                    "items": {
                      "type": "object",
                      "properties": {
                        "path": {
                          "type": "string",
                          "description": "JSONPath reference to the line item",
                          "example": "$.line_items[0]"
                        },
                        "amount": {
                          "type": "number",
                          "minimum": 0,
                          "description": "Item price in minor units (cents for USD); a fraction is truncated",
                          "example": 2500
                        }
                      }
                    }
                  },
                  "subtotal": {
                    "type": "number",
                    "minimum": 0,
                    "description": "Optional order-level base in minor units, for callers that do not send line items. Ignored when items[] is supplied. With neither items[] nor subtotal the response carries no applied entry and discounts.codes is empty; the verified discount is still returned in the verification object.\n",
                    "example": 5000
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "UCP-format discount response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "protocol": {
                          "type": "string",
                          "const": "ucp"
                        },
                        "version": {
                          "type": "string",
                          "description": "UCP release this payload targets",
                          "example": "2026-08-25"
                        },
                        "extension": {
                          "type": "string",
                          "const": "dev.ucp.shopping.discount"
                        },
                        "discounts": {
                          "type": "object",
                          "properties": {
                            "codes": {
                              "type": "array",
                              "description": "Echo of discount codes submitted by the caller. This endpoint accepts none, so this is always empty. The INSR redemption code is returned in the verification object.\n",
                              "items": {
                                "type": "string"
                              }
                            },
                            "applied": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "title": {
                                    "type": "string"
                                  },
                                  "amount": {
                                    "type": "integer",
                                    "minimum": 0,
                                    "description": "Discount total in minor units. Never null — the entry is omitted entirely when no monetary base was supplied.\n"
                                  },
                                  "automatic": {
                                    "type": "boolean",
                                    "const": true,
                                    "description": "Always true. The discount follows from wallet contents rather than a code anyone entered, so it is an automatic discount and the entry carries no code field.\n"
                                  },
                                  "method": {
                                    "type": "string"
                                  },
                                  "priority": {
                                    "type": "integer"
                                  },
                                  "allocations": {
                                    "type": "array",
                                    "items": {
                                      "type": "object",
                                      "properties": {
                                        "path": {
                                          "type": "string"
                                        },
                                        "amount": {
                                          "type": "integer"
                                        }
                                      }
                                    }
                                  }
                                }
                              }
                            }
                          }
                        },
                        "verification": {
                          "type": "object",
                          "properties": {
                            "code": {
                              "type": "string"
                            },
                            "expiresAt": {
                              "type": "string",
                              "format": "date-time"
                            },
                            "sig": {
                              "type": "string"
                            },
                            "kid": {
                              "type": "string",
                              "description": "Always insumer-attest-v1. Commerce discount responses sign under the v1 scheme regardless of the API key's signing generation; resolve the public key from the JWKS by this kid.",
                              "example": "insumer-attest-v1"
                            },
                            "walletProven": {
                              "type": "boolean",
                              "description": "True when the request carried a valid walletProof. Not part of the signed result."
                            },
                            "discountIfProven": {
                              "type": "integer",
                              "description": "Present only when the store limits unproven wallets and a walletProof would get this wallet more."
                            }
                          }
                        }
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "creditsRemaining": {
                          "type": "integer",
                          "description": "Credits left on the caller's API key after this call. Never another key's balance."
                        },
                        "creditsCharged": {
                          "type": "integer",
                          "description": "1 when the caller's key owns the store and the code carries a discount (the caller's key paid); otherwise 0. A code at a store another key owns is paid by that key, which this field never shows."
                        },
                        "version": {
                          "type": "string"
                        },
                        "timestamp": {
                          "type": "string",
                          "format": "date-time"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key, or a walletProof that fails (wrong wallet, store, domain, expired, or nonce already used). No credit is used.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "402": {
            "description": "The API key that owns this store has no credits remaining. Its owner can buy more via POST /v1/credits/buy. Returned only when the result carries a discount. No credit is used and no code is created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "Merchant has not enabled third-party app access, or the store has no active owner API key (\"This store has no active owner API key, so it cannot issue codes or record scans and taps.\")",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "Merchant not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "The store's recognition is paused by its owner: \"This store's recognition is paused.\" No credit is used and no code is created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. Either the key's daily limit (the response carries Retry-After and the X-RateLimit headers), or this wallet, sent without a walletProof, has reached the store's own limit on discount codes per day (maxDiscountsPerWalletPerDay in merchant settings; no credit used, no code created; resets at 00:00 UTC). The limit does not apply to a proven wallet. Paid discount codes requested with a key other than the store's owner are subject to an hourly limit (429; the message says when to try again): \"The hourly limit on discount codes has been reached. Try again in N minutes.\" No credit is used and no code is created.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "description": "Data source unavailable — retryable after a short delay. No discount signed, no credits charged. A verification that could not be signed or stored is also a 503, in the standard error envelope: no credit used, no code created, equally retryable.\n",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/RpcFailureEnvelope"
                    },
                    {
                      "$ref": "#/components/schemas/ErrorEnvelope"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/v1/codes/{code}": {
      "get": {
        "operationId": "validateCode",
        "summary": "Validate INSR-XXXXX discount code",
        "description": "Validates a discount code for merchant backends during ACP/UCP checkout flows. No authentication required. Does not expose wallet address, token breakdown, or analytics. Returns only what the merchant needs to apply the discount.\n",
        "tags": [
          "Discounts & Codes"
        ],
        "security": [],
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^INSR-[A-Z0-9]{5}$"
            },
            "description": "Discount code in INSR-XXXXX format",
            "example": "INSR-A7K3M"
          }
        ],
        "responses": {
          "200": {
            "description": "Code validation result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "oneOf": [
                        {
                          "type": "object",
                          "description": "Valid code",
                          "properties": {
                            "valid": {
                              "type": "boolean",
                              "const": true
                            },
                            "code": {
                              "type": "string"
                            },
                            "merchantId": {
                              "type": "string"
                            },
                            "discountPercent": {
                              "type": "integer"
                            },
                            "expiresAt": {
                              "type": "string",
                              "format": "date-time"
                            },
                            "createdAt": {
                              "type": "string",
                              "format": "date-time"
                            },
                            "walletProven": {
                              "type": "boolean",
                              "description": "True when the code was issued to a caller that proved control of the wallet."
                            }
                          }
                        },
                        {
                          "type": "object",
                          "description": "Invalid code",
                          "properties": {
                            "valid": {
                              "type": "boolean",
                              "const": false
                            },
                            "code": {
                              "type": "string"
                            },
                            "reason": {
                              "type": "string",
                              "enum": [
                                "expired",
                                "already_used",
                                "not_found"
                              ]
                            }
                          }
                        }
                      ]
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid code format",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed (only GET supported)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/registry/tokens": {
      "get": {
        "operationId": "getRegistryTokens",
        "summary": "List active registry tokens and NFT collections (no auth required)",
        "description": "Public read of the approved token and NFT registries, used by browser-side integrations to know which assets to scan for. Only active entries are returned. Flat response, not the standard envelope. Cached at the edge.\n",
        "tags": [
          "Discovery"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Active registry entries",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tokens": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "active": {
                            "type": "boolean"
                          },
                          "name": {
                            "type": "string"
                          },
                          "symbol": {
                            "type": "string"
                          },
                          "chainId": {
                            "oneOf": [
                              {
                                "type": "integer"
                              },
                              {
                                "type": "string"
                              }
                            ],
                            "nullable": true
                          },
                          "chainName": {
                            "type": "string"
                          },
                          "contractAddress": {
                            "type": "string",
                            "nullable": true,
                            "description": "EVM contract address (null for Solana tokens)"
                          },
                          "mintAddress": {
                            "type": "string",
                            "nullable": true,
                            "description": "Solana mint address (null for EVM tokens)"
                          },
                          "decimals": {
                            "type": "integer",
                            "nullable": true
                          },
                          "logo": {
                            "type": "string"
                          },
                          "coingeckoId": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "nfts": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "active": {
                            "type": "boolean"
                          },
                          "name": {
                            "type": "string"
                          },
                          "contractAddress": {
                            "type": "string"
                          },
                          "chainId": {
                            "oneOf": [
                              {
                                "type": "integer"
                              },
                              {
                                "type": "string"
                              }
                            ],
                            "nullable": true
                          },
                          "chainName": {
                            "type": "string"
                          },
                          "image": {
                            "type": "string"
                          },
                          "standard": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/registry/merchants": {
      "get": {
        "operationId": "getRegistryMerchants",
        "summary": "List public-directory merchants with domains (no auth required)",
        "description": "Public read of the merchant directory in the shape browser-side integrations consume: each entry carries its recognized domains, token tiers, and NFT collections. Flat response, not the standard envelope. For the filterable, paginated directory use GET /v1/merchants instead.\n",
        "tags": [
          "Discovery"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Directory merchants",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "merchants": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "companyName": {
                            "type": "string"
                          },
                          "website": {
                            "type": "string"
                          },
                          "location": {
                            "type": "string"
                          },
                          "domains": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "tokens": {
                            "type": "array",
                            "items": {
                              "type": "object"
                            }
                          },
                          "nftCollections": {
                            "type": "array",
                            "items": {
                              "type": "object"
                            }
                          },
                          "verified": {
                            "type": "boolean"
                          },
                          "verifiedDomain": {
                            "type": "string"
                          },
                          "discountStacking": {
                            "type": "string",
                            "enum": [
                              "highest",
                              "stack",
                              "capped"
                            ]
                          },
                          "maxDiscountCap": {
                            "type": "integer"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/health": {
      "get": {
        "operationId": "healthCheck",
        "summary": "Service health check (no auth required)",
        "description": "Liveness probe covering the API, its datastore, and the attestation signing key. Returns 200 when all checks pass, 503 when any fails. Response is a flat status object, not the standard envelope.\n",
        "tags": [
          "Platform"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "All checks passing",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "checks": {
                      "type": "object",
                      "properties": {
                        "api": {
                          "type": "string",
                          "example": "ok"
                        },
                        "timestamp": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "datastore": {
                          "type": "string",
                          "example": "ok"
                        },
                        "signing": {
                          "type": "string",
                          "example": "ok"
                        }
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "version": {
                          "type": "string",
                          "example": "1.0"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "description": "One or more checks failing (same shape, ok=false)"
          }
        }
      }
    },
    "/v1/keys/create": {
      "post": {
        "operationId": "createFreeKey",
        "summary": "Create a free-tier API key with an email (no auth required)",
        "description": "Instant free-tier signup: send an email address and an app name, get a working `insr_live_` key in the response. Free tier = 10 free verifications plus 100 requests a day. The key string is returned exactly once, in this response; it is never emailed (a management link is emailed instead). One free key per email; keys are also rate-limited per client address. For paid tiers use POST /v1/keys/checkout (card) or POST /v1/keys/purchase (crypto); for wallet-native keys with no email use POST /v1/keys/buy. Every key minted here (and on every other creation path) signs under the v2 scheme: attest responses carry `kid: insumer-attest-v2`, trust responses `insumer-trust-v2`, and `/v1/attest` thresholds must be decimal strings (a JSON number is rejected with 400). Pre-cutover v1 keys keep their original behavior. **Response envelope note**: standalone endpoint — returns a flat `{success, key, ...}` object, NOT the `{ok, data, meta}` envelope.\n",
        "tags": [
          "Keys & Billing"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "appName",
                  "tier"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email",
                    "description": "Owner email. One free key per email."
                  },
                  "appName": {
                    "type": "string",
                    "maxLength": 100,
                    "description": "Name for this key (your app or agent name)."
                  },
                  "tier": {
                    "type": "string",
                    "enum": [
                      "free"
                    ],
                    "description": "Must be 'free'. Paid tiers use /v1/keys/checkout or /v1/keys/purchase."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Key created (shown once — save it now)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": true
                    },
                    "key": {
                      "type": "string",
                      "example": "insr_live_..."
                    },
                    "name": {
                      "type": "string"
                    },
                    "tier": {
                      "type": "string",
                      "example": "free"
                    },
                    "dailyLimit": {
                      "type": "integer",
                      "example": 100
                    },
                    "apiKeyCredits": {
                      "type": "integer",
                      "example": 10
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid email, appName, or tier. Like all error responses on this standalone endpoint, the body is a flat object with a single \"error\" string, not the standard envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed (only POST supported)"
          },
          "409": {
            "description": "A free key already exists for this email (flat error body)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many key requests from this client — try again tomorrow (flat error body)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/keys/checkout": {
      "post": {
        "operationId": "createKeyCheckout",
        "summary": "Start a card subscription for a Pro or Enterprise key (no auth required)",
        "description": "Creates a Stripe Checkout session for a monthly subscription — Pro $29/mo (10,000 requests/day, 1,000 credits/mo) or Enterprise $99/mo (100,000 requests/day, 5,000 credits/mo). Returns a hosted checkout URL; after payment the key is retrieved once via GET /v1/keys/retrieve. Pass `keyHash` (from POST /v1/keys/lookup) to upgrade an existing key in place — email and app name are then optional and carried over. **Response envelope note**: standalone endpoint — flat `{success, url}`.\n",
        "tags": [
          "Keys & Billing"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "tier"
                ],
                "properties": {
                  "tier": {
                    "type": "string",
                    "enum": [
                      "pro",
                      "enterprise"
                    ]
                  },
                  "email": {
                    "type": "string",
                    "format": "email",
                    "description": "Required unless upgrading via keyHash."
                  },
                  "appName": {
                    "type": "string",
                    "maxLength": 100,
                    "description": "Required unless upgrading via keyHash."
                  },
                  "keyHash": {
                    "type": "string",
                    "description": "64-hex identifier of an existing key to upgrade (returned by /v1/keys/lookup)."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Hosted checkout session created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": true
                    },
                    "url": {
                      "type": "string",
                      "description": "Stripe Checkout URL to complete the subscription."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid tier, email, appName, or keyHash"
          },
          "404": {
            "description": "keyHash provided but no active key found"
          },
          "405": {
            "description": "Method not allowed (only POST supported)"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/keys/retrieve": {
      "get": {
        "operationId": "retrieveKeyAfterCheckout",
        "summary": "Retrieve a purchased key after checkout (one-time, no auth required)",
        "description": "Called by the post-checkout redirect with the checkout `sessionId`. Returns the new key exactly once, then invalidates the retrieval — a second call returns 404. Waits briefly for payment confirmation before giving up. **Response envelope note**: standalone endpoint — flat `{success, key, ...}`.\n",
        "tags": [
          "Keys & Billing"
        ],
        "security": [],
        "parameters": [
          {
            "name": "sessionId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Checkout session ID from the success redirect."
          }
        ],
        "responses": {
          "200": {
            "description": "Key returned (shown once — save it now)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": true
                    },
                    "key": {
                      "type": "string",
                      "example": "insr_live_..."
                    },
                    "name": {
                      "type": "string"
                    },
                    "tier": {
                      "type": "string"
                    },
                    "dailyLimit": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid sessionId",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "sessionId is required."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not found — payment may still be processing, or the key was already retrieved"
          },
          "405": {
            "description": "Method not allowed (only GET supported)"
          },
          "410": {
            "description": "Retrieval link expired — contact support"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/keys/lookup": {
      "post": {
        "operationId": "lookupAccount",
        "summary": "Look up a key's account details (key in body, no header auth)",
        "description": "Paste-your-key account lookup used by the developer account page. Returns a safe subset: name, tier, key suffix, owner email, credit balance, daily limit, usage counters, timestamps, expiry, whether the key has an active card subscription, and the `keyHash` used by /v1/keys/checkout and /v1/credits/topup. Rate-limited per client address (429 on abuse). **Response envelope note**: standalone endpoint — flat `{success, ...}`.\n",
        "tags": [
          "Keys & Billing"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "key"
                ],
                "properties": {
                  "key": {
                    "type": "string",
                    "description": "The full insr_live_ key (50 chars)."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Account details",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": true
                    },
                    "name": {
                      "type": "string"
                    },
                    "tier": {
                      "type": "string",
                      "example": "pro"
                    },
                    "keySuffix": {
                      "type": "string"
                    },
                    "ownerEmail": {
                      "type": "string"
                    },
                    "apiKeyCredits": {
                      "type": "integer"
                    },
                    "dailyLimit": {
                      "type": "integer"
                    },
                    "totalRequests": {
                      "type": "integer"
                    },
                    "totalAttestations": {
                      "type": "integer"
                    },
                    "createdAt": {
                      "type": "string",
                      "format": "date-time",
                      "nullable": true
                    },
                    "lastUsedAt": {
                      "type": "string",
                      "format": "date-time",
                      "nullable": true
                    },
                    "hasStripe": {
                      "type": "boolean"
                    },
                    "paidWithUsdc": {
                      "type": "boolean"
                    },
                    "expiresAt": {
                      "type": "string",
                      "format": "date-time",
                      "nullable": true
                    },
                    "rateLimitUsage": {
                      "type": "integer",
                      "description": "Requests used in the current daily window."
                    },
                    "keyHash": {
                      "type": "string",
                      "description": "Identifier for /v1/keys/checkout upgrades and /v1/credits/topup."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid key format"
          },
          "403": {
            "description": "Key deactivated or expired"
          },
          "404": {
            "description": "Key not found"
          },
          "405": {
            "description": "Method not allowed (only POST supported)"
          },
          "429": {
            "description": "Too many lookups — try again in a few minutes"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/credits/topup": {
      "post": {
        "operationId": "buyCreditsWithCard",
        "summary": "Buy extra credits by card (subscribers only, no header auth)",
        "description": "Creates a one-time Stripe payment for 100–50,000 additional verification credits at the subscriber's tier rate ($0.029/credit Pro, $0.02/credit Enterprise). Free-tier keys get 403 — top-ups require a Pro or Enterprise subscription; free and crypto keys buy credits on-chain via POST /v1/credits/buy instead. **Response envelope note**: standalone endpoint — flat `{success, url}`.\n",
        "tags": [
          "Keys & Billing"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "keyHash",
                  "credits"
                ],
                "properties": {
                  "keyHash": {
                    "type": "string",
                    "description": "64-hex identifier from /v1/keys/lookup."
                  },
                  "credits": {
                    "type": "integer",
                    "minimum": 100,
                    "maximum": 50000
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Hosted payment session created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": true
                    },
                    "url": {
                      "type": "string",
                      "description": "Stripe Checkout URL for the one-time payment."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid credits amount or keyHash"
          },
          "403": {
            "description": "Free-tier key — top-ups require a subscription"
          },
          "404": {
            "description": "Key not found or inactive"
          },
          "405": {
            "description": "Method not allowed (only POST supported)"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/billing/portal": {
      "post": {
        "operationId": "openBillingPortal",
        "summary": "Open the billing portal for a subscribed key (key in body)",
        "description": "Returns a Stripe Billing Portal URL where a subscriber manages or cancels their subscription. Only keys with an active card subscription qualify (400 otherwise). Rate-limited per client address. **Response envelope note**: standalone endpoint — flat `{success, url}`.\n",
        "tags": [
          "Keys & Billing"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "key"
                ],
                "properties": {
                  "key": {
                    "type": "string",
                    "description": "The full insr_live_ key (50 chars)."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Portal session created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": true
                    },
                    "url": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid key format, or key has no card subscription"
          },
          "403": {
            "description": "Key deactivated"
          },
          "404": {
            "description": "Key not found"
          },
          "405": {
            "description": "Method not allowed (only POST supported)"
          },
          "429": {
            "description": "Too many requests — try again in a few minutes"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/chain-request": {
      "post": {
        "operationId": "requestChainSupport",
        "summary": "Request support for a new blockchain (no auth required)",
        "description": "Public intake for chain-support requests. Submissions are reviewed by a human; nothing is enabled automatically. Rate limited per email. **Response envelope note**: standalone endpoint — flat `{success, message}`.\n",
        "tags": [
          "Platform"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "chainName",
                  "chainId",
                  "networkType",
                  "contactName",
                  "contactEmail"
                ],
                "properties": {
                  "chainName": {
                    "type": "string"
                  },
                  "chainId": {
                    "type": "number",
                    "description": "Numeric chain ID."
                  },
                  "networkType": {
                    "type": "string",
                    "enum": [
                      "evm",
                      "non-evm"
                    ]
                  },
                  "rpcUrl": {
                    "type": "string",
                    "description": "Optional public RPC endpoint for the chain."
                  },
                  "contactName": {
                    "type": "string"
                  },
                  "contactEmail": {
                    "type": "string",
                    "format": "email"
                  },
                  "organizationName": {
                    "type": "string"
                  },
                  "message": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Request recorded for review",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string",
                      "example": "Chain request submitted successfully."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid fields"
          },
          "405": {
            "description": "Method not allowed (only POST supported)"
          },
          "429": {
            "description": "Too many requests from this email — try again tomorrow"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/merchants/{id}/claims": {
      "get": {
        "operationId": "listDomainClaims",
        "summary": "List pending claims on this merchant's domain (owner key only)",
        "description": "Domain-ownership dispute flow: when another party claims your verified domain, the claim queues here for your decision. Returns pending claims for the merchant's verified domain. 403 if this merchant is not the owner of record for the domain.\n",
        "tags": [
          "Merchant Setup"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Pending claims (empty list if the merchant has no verified domain)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "domain": {
                          "type": "string",
                          "nullable": true
                        },
                        "claims": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string"
                              },
                              "domain": {
                                "type": "string"
                              },
                              "claimantCompanyId": {
                                "type": "string"
                              },
                              "createdAt": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "403": {
            "description": "API key does not manage this merchant, or not the owner of record for this domain"
          },
          "404": {
            "description": "Merchant not found"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "post": {
        "operationId": "resolveDomainClaim",
        "summary": "Approve or deny a domain claim (owner key only)",
        "description": "Resolves one pending claim on this merchant's verified domain. Approving associates the claimant with the domain record; denying closes the claim. Each claim resolves once — a second attempt returns 409.\n",
        "tags": [
          "Merchant Setup"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "claimId",
                  "action"
                ],
                "properties": {
                  "claimId": {
                    "type": "string"
                  },
                  "action": {
                    "type": "string",
                    "enum": [
                      "approve",
                      "deny"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Claim resolved",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "claimId": {
                          "type": "string"
                        },
                        "action": {
                          "type": "string",
                          "enum": [
                            "approved",
                            "denied"
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing claimId or invalid action, or merchant has no verified domain"
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "403": {
            "description": "API key does not manage this merchant, not the owner of record, or claim belongs to another domain"
          },
          "404": {
            "description": "Claim or merchant not found"
          },
          "409": {
            "description": "Claim already resolved"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/v1/merchants/{id}/release": {
      "post": {
        "operationId": "releaseDomain",
        "summary": "Release this merchant's domain binding (owner key only)",
        "description": "Marks the merchant's verified-domain binding as cancelled, which starts the 30-day lapse window after which another party may verify and take ownership of the domain. Idempotent and best-effort: always returns 200 with `released` true or false plus a reason.\n",
        "tags": [
          "Merchant Setup"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Release outcome",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "released": {
                          "type": "boolean"
                        },
                        "domain": {
                          "type": "string",
                          "description": "Present when released."
                        },
                        "reason": {
                          "type": "string",
                          "description": "Present when not released (no verified domain, or not owner of record)."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "403": {
            "description": "API key does not manage this merchant"
          },
          "404": {
            "description": "Merchant not found"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    }
  },
  "tags": [
    {
      "name": "Wallet Auth",
      "description": "The primitive. Read wallet state, evaluate it against caller-supplied conditions, return a signed boolean. Conditions in, signed attestations out. Balances are never exposed. This group also carries the pre-configured condition templates and the public key set every signed response is checked against, so the full loop (read, evaluate, sign, verify independently) lives in one place. Reachable with an API key, with wallet-signed auth, or with no credential at all via x402 pay-per-call.\n"
    },
    {
      "name": "Trust Fact Profiles",
      "description": "Structured, signed fact profiles for a wallet, organized by dimension, singly or in batches. No score, no opinion, just cryptographically verifiable evidence. Reachable with an API key, with wallet-signed auth, or with no credential at all via x402 pay-per-call.\n"
    },
    {
      "name": "Agent Onboarding",
      "description": "How software gets and keeps access with no human in the loop. Buy a key or top up credits with USDC, USDT, or BTC; the transaction sender wallet becomes the key identity, and the payment is the auth. No email, no card, no account creation. An agent that wants no account at all skips this group entirely and pays per call with x402 on Wallet Auth and Trust Fact Profiles.\n"
    },
    {
      "name": "Keys & Billing",
      "description": "Key lifecycle and billing. Free email signup, on-chain purchase, card subscriptions, credit balance and top-ups, account lookup, billing portal.\n"
    },
    {
      "name": "Discovery",
      "description": "Browse merchants, tokens, and NFT collections in the public directory."
    },
    {
      "name": "Discounts & Codes",
      "description": "Turn a condition verdict into a price. Calculate a discount, create a signed code (INSR-XXXXX, valid 30 minutes), validate that code from a merchant backend, and confirm stablecoin payment.\n"
    },
    {
      "name": "Agent Commerce Protocols",
      "description": "The same discount decision returned in ACP (OpenAI/Stripe) and UCP (Google) formats for AI agent commerce flows.\n"
    },
    {
      "name": "Merchant Setup",
      "description": "Create and administer a merchant programmatically. Token and NFT tiers, discount settings, domain verification, directory publishing, credits, ownership claims, and registry submissions. The API key that creates a merchant owns it.\n"
    },
    {
      "name": "Point of Sale",
      "description": "In-person recognition. Partner-operated scanner PINs, login-less scanner sessions, and pass verification. The partner builds only UI; signing stays inside the primitive and is never exposed as an API call.\n"
    },
    {
      "name": "Platform",
      "description": "Service health and chain-support requests."
    }
  ]
}
