Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: Insumer Keys & Billing API
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), ChatGPT plugin (OpenAI''s plugin directory). 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/'
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: []
tags:
- 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.
paths:
/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).'
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/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.'
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}`.'
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, ...}`.'
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, ...}`.'
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
- 'null'
format: date-time
lastUsedAt:
type:
- string
- 'null'
format: date-time
hasStripe:
type: boolean
paidWithUsdc:
type: boolean
expiresAt:
type:
- string
- 'null'
format: date-time
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}`.'
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}`.'
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'
components:
schemas:
Meta:
type: object
properties:
version:
type: string
example: '1.0'
timestamp:
type: string
format: date-time
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'
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).
'
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.
'
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/ErrorEnvelope'
- type: object
properties:
error:
type: string
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.
'
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.'