Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: Insumer Point of Sale 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: 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.
paths:
/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.'
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.
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).
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.'
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).
'
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'
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.'