Privacy-preserving boolean attestation across 38 blockchains. Read token balances, NFT ownership, EAS attestations, Farcaster identity, arbitrary boolean view calls, ratio rules that never need re-tuning, and agent standing on Base. Signed attestations back.
Core primitive. Trust profiles, compliance gating, and commerce all extend this signed attestation.
Auth: X-API-Key, or Authorization: Wallet for EVM agents who bought their key via /v1/keys/buy. See Authentication →
Building this in Claude Code? Install the wallet auth skill and Claude will write correct, signature-verifying integration code on the first try.
smithery skill add douglasborthwick/insumer-skill
Check if a wallet meets conditions without exposing balances. The API returns an ECDSA-signed true/false result with condition hashes and block anchoring, so any party can independently verify the attestation without trusting the caller. Trust profiles, compliance gating, and commerce endpoints all build on this same signed attestation model.
Check if a wallet holds at least 1,000 USDC on Ethereum.
const res = await fetch("https://api.insumermodel.com/v1/attest", { method: "POST", headers: { "Content-Type": "application/json", "x-api-key": "YOUR_API_KEY" }, body: JSON.stringify({ wallet: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", conditions: [{ type: "token_balance", contractAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC on Ethereum chainId: 1, // Ethereum mainnet threshold: "1000", // decimal string — new keys are v2 and reject a JSON number with 400 decimals: 6 // USDC has 6 decimals }] }) }); const response = await res.json(); console.log(response.data.attestation.pass); // true or false
import requests res = requests.post( "https://api.insumermodel.com/v1/attest", headers={"x-api-key": "YOUR_API_KEY"}, json={ "wallet": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "conditions": [{ "type": "token_balance", "contractAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", # USDC on Ethereum "chainId": 1, # Ethereum mainnet "threshold": "1000", # decimal string — new keys are v2 and reject a JSON number with 400 "decimals": 6 # USDC has 6 decimals }] } ) response = res.json() print(response["data"]["attestation"]["pass"]) # True or False
curl -X POST https://api.insumermodel.com/v1/attest \ -H "Content-Type: application/json" \ -H "x-api-key: YOUR_API_KEY" \ -d '{ "wallet": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "conditions": [{ "type": "token_balance", "contractAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "chainId": 1, "threshold": "1000", "decimals": 6, "label": "USDC >= 1000" }] }' # contractAddress: USDC on Ethereum (chainId 1, 6 decimals) # threshold: a decimal string ("1000"), not a number. New keys are v2 and reject a JSON number with 400; a string also works on legacy v1 keys.
Each condition type evaluates wallet state a different way — from a single balance to a relationship like share-of-supply. Combine multiple conditions in a single call.
token_balanceCheck if a wallet holds at least a threshold amount of any ERC-20 token. Works on all 32 EVM chains, Solana, and XRP Ledger.
contractAddress - Token contractchainId - Network IDthreshold - Minimum amount (human-readable)decimals - Token decimals (e.g. 6 for USDC)nft_ownershipVerify ownership of ERC-721 or ERC-1155 NFTs. Checks that the wallet holds at least one NFT from the collection.
contractAddress - NFT contractchainId - Network IDthreshold - Min count, defaults to any (optional)eas_attestationVerify on-chain EAS attestations by schema ID or use pre-configured compliance templates. See compliance docs.
schemaId - EAS schema UIDtemplate - e.g. coinbase_verified_accountfarcaster_idCheck if a wallet has a registered Farcaster ID. Uses the IdRegistry contract on Optimism. Returns a boolean indicating registration status.
contractAddress neededchainId neededratio_to_amountSelf-scaling agent-spend rule: met when the wallet holds at least multiple times a per-request amount. One rule that adjusts to every transaction size, no re-tuning. RPC EVM chains.
contractAddress - Token contract (or native)chainId - EVM network IDmultiple - e.g. 10 for “10× the amount”amount - Reference amount (token units)ratio_to_supplyShare-of-supply rule: met when the wallet holds at least minFraction of the token’s on-chain total supply. For project and governance tokens, not stablecoins. RPC EVM chains, ERC-20 only.
contractAddress - ERC-20 token contractchainId - EVM network IDminFraction - Fraction in (0,1], e.g. 0.005 = 0.5%erc8004_agentIs this wallet a registered ERC-8004 agent? Met when the wallet owns the agent NFT or is the registry’s signature-verified agentWallet binding. Base only at launch. Available on any API key, or with no key at all via x402 pay-per-call.
chainId - 8453 (Base) at launchagentId - uint256 decimal string, requirederc7710_delegationIs this signed ERC-7710 delegation from principal P to this agent wallet currently valid, and what limits does it declare? Signature, revocation, and time-window checked at the anchored block. Base only at launch. Available on any API key, or with no key at all via x402 pay-per-call.
delegationManager - Recognized manager on BaseexpectedDelegator - Asserted principal, requireddelegation - The signed delegation objectevm_view_callCall any boolean view function on any RPC EVM chain and attest the result. Met when the function returns true for the attested wallet. Use this when a contract already encodes your eligibility rule and you would rather read it than restate it. Single-address-argument view functions only.
contractAddress - Contract to callchainId - EVM network IDselector - Signature, e.g. hasAccess(address)Boolean attestation. Returns an ECDSA-signed pass/fail for one or more conditions.
* Provide wallet for EVM chains, solanaWallet for Solana, xrplWallet for XRP Ledger, or bitcoinWallet for Bitcoin. Use one or more as needed.
{
"ok": true,
"data": {
"attestation": {
"id": "ATST-E365DA8B1C2F4790",
"pass": true,
"results": [
{
"condition": 0,
"label": "USDC >= 1000",
"type": "token_balance",
"chainId": 1,
"met": true,
"evaluatedCondition": {
"type": "token_balance",
"chainId": 1,
"contractAddress": "0xA0b8...eB48",
"operator": "gte",
"threshold": 1000,
"decimals": 6
},
"conditionHash": "0x448ddd3e...",
"blockNumber": "0x1772dde",
"blockTimestamp": "2026-03-05T00:41:11.000Z"
}
],
"passCount": 1,
"failCount": 0,
"attestedAt": "2026-03-05T00:41:14.934Z",
"expiresAt": "2026-03-05T01:11:14.934Z"
},
"sig": "rHObYHqV...",
"kid": "insumer-attest-v1"
},
"meta": {
"creditsRemaining": 99,
"creditsCharged": 1,
"version": "1.0",
"timestamp": "2026-03-05T00:41:14.934Z"
}
}
pass is true only when ALL conditions are met.
sig is an ECDSA P-256 signature over the attestation payload.
kid identifies the signing key. Fetch the public key from /.well-known/jwks.json.
Standard attestation: 1 credit ($0.04). With Merkle proofs: 2 credits ($0.08).
{
"condition": 0,
"label": "RLUSD >= 50",
"type": "token_balance",
"chainId": "xrpl",
"met": true,
"evaluatedCondition": {
"type": "token_balance",
"chainId": "xrpl",
"contractAddress": "rMxCKbEDwqr76QuheSUMdEGf4B9xJ8m5De",
"currency": "RLUSD",
"threshold": 50
},
"conditionHash": "0x7f2a...",
"ledgerIndex": 95482163,
"ledgerHash": "BB9023D447285923...",
"trustLineState": { "frozen": false }
}
ledgerIndex + ledgerHash replace blockNumber/blockTimestamp for XRPL conditions. They identify the validated ledger at verification time.
trustLineState is present only for non-native XRPL token conditions. Shows whether the trust line is frozen.
Frozen trust lines return met: false regardless of balance — frozen tokens are not spendable.
InsumerAPI is the neutral verifier: off-chain attestation of on-chain state. At settlement time three questions exist: can this wallet pay (payment rails), is the decision sound (reasoning verifiers), and does this party have standing to act. These two condition types answer the third, straight from chain state. Both are generally available, so every API key can send them with no flag to request. Base (chainId 8453) only at launch. 1 credit each. erc8004_agent does not support Merkle proofs; erc7710_delegation does: a revocation proof, covered below.
They also work with no API key at all, via x402 pay-per-call: send POST /v1/attest with no credential headers, take the 402 quote, sign an EIP-3009 USDC authorization on Base, and retry with the X-PAYMENT header. A standard call prices at the $0.05 rate. An agent can ask whether a counterparty has standing to act without ever opening an account.
erc8004_agentIs this wallet a registered ERC-8004 agent? Checked against the ERC-8004 Identity Registry at 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432 on Base.
{
"type": "erc8004_agent",
"chainId": 8453,
"agentId": "123",
"label": "Registered agent"
}
met is true iff the attested wallet either owns the agent NFT (ownerOf) or is the registry’s on-chain signature-verified agentWallet binding (getAgentWallet). tokenURI JSON is never trusted.
agentId is required (uint256 decimal string): the deployed registry has no wallet-to-agentId reverse lookup.
Result extras (inside the signed results array): agentExists (boolean), matchedVia ("owner" | "agent_wallet" | "none"). The evaluatedCondition carries operator: "owner_or_bound_wallet".
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”. It implies no vetting, no reputation, no endorsement.
The registry clears the agentWallet binding automatically when the agent NFT transfers, so a block-anchored verdict reflects binding truth at that block.
erc7710_delegationIs this signed delegation from principal P to this agent wallet currently valid, and what limits does it declare? Verified against a recognized MetaMask Delegation Framework manager on Base (versions 1.0.0 / 1.1.0 / 1.3.0). Root authority only: delegation chains are unsupported in v1. Max 16 caveats, max 3 delegation conditions per request.
{
"type": "erc7710_delegation",
"chainId": 8453,
"delegationManager": "0xdb9B1e94B5b69Df7e401DDbedE43491141047dB3",
"expectedDelegator": "0x<principal address>",
"delegation": {
"delegator": "0x<principal>",
"delegate": "0x<agent wallet>",
"authority": "0xffff...ffff",
"caveats": [
{ "enforcer": "0x<enforcer>", "terms": "0x<hex>" }
],
"salt": "42",
"signature": "0x<hex>"
},
"label": "Authorized by principal"
}
met is true 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.
expectedDelegator is required: without it a self-delegation would read as authority, so there is no structural-only mode.
Recognized enforcers at launch (5 kinds): timestamp (time window, evaluated now), erc20_transfer_amount, native_transfer_amount, allowed_targets, limited_calls. The last four are reported as declared limits: on-chain redemption enforces them, and the attestation states what the principal signed rather than simulating enforcement.
signatureType semantics: "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.
Result extras: declaredLimits (decoded caveat limits, decimal-string amounts, each entry carrying the raw terms hex it was decoded from, and not part of the met verdict; see below), unrecognizedEnforcers (when failing on unknown caveats), failReason (delegate_mismatch, principal_mismatch, invalid_signature, delegator_not_deployed, revoked, unknown_caveat_enforcer, outside_time_window). delegator_not_deployed means the principal address held no contract code at the anchored block: the state a smart-contract wallet is in until its first transaction. It is kept separate from invalid_signature because no signature was evaluated, so your code can retry once the principal deploys instead of treating it as a bad signature.
5-minute expiry: 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” (blockNumber is in the signed result).
Revocation proofs: add proof: "merkle" and the result carries an EIP-1186 storage proof of the revocation slot (subject: "delegation_revocation", 2 credits). “Not revoked as of block N” stops being something you take our word for. See below.
met is the verdict, and it is exactly the boolean above: the attested wallet is the delegate, the declared delegator matches expectedDelegator, the EIP-712 signature verifies, the delegation is unrevoked as of the anchored block, every caveat uses a recognized enforcer, and any time-window caveat is currently satisfied.
declaredLimits is not part of that boolean. It is a signed decode of the caveat terms the caller itself submitted, riding alongside the verdict inside the signed results: a sibling of evaluatedCondition, inside the signed payload but outside conditionHash. InsumerAPI returns signed booleans, never raw wallet data. On a delegation, the boolean is met, and the declared limits travel next to it, signed. They ride on passing and failing verdicts alike, once the signature and revocation checks pass: a delegation failing on unknown_caveat_enforcer or outside_time_window still carries the decode of its recognized caveats, while earlier failures (bad signature, revoked, mismatched parties) carry none. Worth knowing which is which before you build on either.
{
"kind": "erc20_transfer_amount",
"enforcer": "0xf100b0819427117ecf76ed94b358b1a5b5c6d2fc",
"terms": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913000000000000000000000000000000000000000000000000000000003b9aca00",
"token": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
"maxAmount": "1000000000"
}
All numeric values are decimal strings in base units: "1000000000" here is 1,000 USDC at 6 decimals.
Every entry carries terms: the exact hex bytes it was decoded from. You supplied those bytes in your own request, so verification needs no external lookup and no second API call.
getTermsInfo byte layout against terms, and compare the result to the decoded values in the entry. In the example above, the first 20 bytes are the token and the next 32 are the amount.delegationHash (the EIP-712 struct hash, carried in the signed evaluatedCondition, that commits to every caveat’s enforcer and terms) from the delegation object you already hold, and confirm it matches.Together those two steps make the decode a checkable claim rather than a trust-us assertion: the hash pins which caveats were evaluated, and the byte layout pins what each one says.
declaredLimits: "omit"A delegation attestation in JWT form is portable, which means that by default the principal’s declared limits travel to anyone the token is forwarded to. Usually that is exactly right: a relying party needs the limits to act on them. Sometimes it is not.
Send the top-level declaredLimits modifier (a sibling of proof and format) to control it. Absent or "include" is the default: the limits are returned in the signed results, and therefore travel inside the JWT when format: "jwt" is used. Set it to "omit" and the decoded limits are left out; the result carries declaredLimitsOmitted: true instead.
{
"wallet": "0x<agent wallet>",
"format": "jwt",
"declaredLimits": "omit",
"conditions": [ { "type": "erc7710_delegation", ... } ]
}
You lose nothing by omitting: you submitted the caveats, so you already hold them. And the guarantee that makes this safe to forward: met, delegationHash, and conditionHash are byte-identical whether or not the limits are omitted. 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.
A delegation verdict has three parts, and until now they were not equally checkable. The EIP-712 signature check you could always reproduce yourself: you hold the delegation object. The caveat decode you could always reproduce yourself: you submitted the raw terms bytes, and the steps above show how. But “not revoked as of block N” was ours to assert and yours to accept.
Send proof: "merkle" alongside a delegation condition and that gap closes. The result carries an EIP-1186 storage proof of disabledDelegations[delegationHash] in the DelegationManager’s storage, against the anchored block’s state root. Verify it against a block header and the whole verdict is checkable rather than partly trusted.
{
"available": true,
"type": "merkle",
"subject": "delegation_revocation",
"blockNumber": "0x12a05f200",
"contractAddress": "0xdb9B1e94B5b69Df7e401DDbedE43491141047dB3",
"mappingSlot": 1,
"storageKey": "0x<keccak256(abi.encode(delegationHash, mappingSlot))>",
"accountProof": [ "0x...", ... ],
"storageProof": [ { "key": "0x...", "value": "0x0", "proof": [ "0x...", ... ] } ],
"storageHash": "0x..."
}
subject is what tells a delegation proof apart from a balance proof: balance proofs carry no subject field at all.
storageKey = keccak256(abi.encode(delegationHash, mappingSlot)) using the delegationHash from the signed evaluatedCondition, and confirm it equals the returned storageKey. Do not skip this step: it is what binds the proof to this delegation. A proof of some other slot would verify against the header perfectly well.accountProof and storageProof against the state root of the block header for blockNumber.1 means revoked, 0 means not revoked. Absence is proven here as firmly as presence: a proven 0 is positive evidence that no revocation exists, not a report that none was found.Proofs are returned only for DelegationManager deployments whose storage layout has been verified on-chain. Today that is the v1.3.0 manager on Base, 0xdb9B1e94B5b69Df7e401DDbedE43491141047dB3. The other recognized manager versions return proof.available: false with a reason saying the layout is unverified; the boolean verdict is computed and signed exactly as normal.
That restraint is the point. An inferred slot number would produce a proof of the wrong storage location that still verifies cleanly against the block header, a confident answer to a question nobody asked. Worse than no proof at all. So a slot gets proven only once it has been confirmed against the deployed contract.
Proof mode on a delegation condition costs 2 credits instead of 1, the same premium as any other proof-mode request. If a proof cannot be produced for a transient RPC reason, the premium is refunded and the call costs 1.
Every attestation can be verified without trusting us. One API call, three verification layers.
Every attestation is signed with ECDSA P-256. The algorithm is swappable via JWKS without breaking verifiers. Verify the signature using the insumer-verify library or raw Web Crypto.
// npm install insumer-verify import { verifyAttestation } from "insumer-verify"; // Pass the full API response envelope, not response.data const response = await res.json(); const result = await verifyAttestation(response, { jwksUrl: "https://insumermodel.com/.well-known/jwks.json" }); console.log(result.valid); // true
// Fetch the public key from JWKS const jwks = await fetch("https://insumermodel.com/.well-known/jwks.json") .then(r => r.json()); const key = jwks.keys.find(k => k.kid === data.kid); // Import the public key const publicKey = await crypto.subtle.importKey( "jwk", key, { name: "ECDSA", namedCurve: "P-256" }, false, ["verify"] ); // Verify the signature (canonical JSON — sorted keys) const sorted = Object.keys(data.attestation).sort(); const payload = new TextEncoder().encode( JSON.stringify(data.attestation, sorted) ); const sigBytes = Uint8Array.from( atob(data.sig), c => c.charCodeAt(0) ); const valid = await crypto.subtle.verify( { name: "ECDSA", hash: "SHA-256" }, publicKey, sigBytes, payload ); console.log(valid); // true
Each result includes a conditionHash computed from evaluatedCondition. Recompute it yourself to confirm the attestation matches the condition you requested.
const condition = result.evaluatedCondition; const sortedKeys = Object.keys(condition).sort(); const canonical = JSON.stringify(condition, sortedKeys); const hashBuffer = await crypto.subtle.digest( "SHA-256", new TextEncoder().encode(canonical) ); const hashHex = "0x" + [...new Uint8Array(hashBuffer)] .map(b => b.toString(16).padStart(2, "0")) .join(""); console.log(hashHex === result.conditionHash); // true
Add proof: "merkle" to get an EIP-1186 storage proof anchored to a block state root. Verify the balance against the Ethereum state trie without any intermediary. Available on 28 of 32 EVM chains for token_balance, and on erc7710_delegation conditions, where the proof covers the revocation slot instead of a balance slot.
curl -X POST https://api.insumermodel.com/v1/attest \ -H "Content-Type: application/json" \ -H "x-api-key: YOUR_API_KEY" \ -d '{ "wallet": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "proof": "merkle", "conditions": [{ "type": "token_balance", "contractAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "chainId": 1, "threshold": "1000", "decimals": 6, "label": "USDC >= 1000" }] }' # Response includes a proof object with storageProof, storageHash, # and blockNumber alongside the standard attestation fields
Merkle proofs cost 2 credits ($0.08) per attestation; if a proof cannot be produced for a transient RPC reason, the premium is refunded and the call costs 1. The response includes a proof object containing the raw storageProof array, storageHash, and blockNumber, allowing full trustless verification against the chain state. On a delegation condition the object also carries subject: "delegation_revocation" and the contractAddress of the DelegationManager (see Agent conditions for the verification steps).
Add format: "jwt" to receive an ES256-signed JWT alongside the standard response. Verifiable by any standard JWT library using the JWKS at /.well-known/jwks.json. See the full Wallet Auth section below.
Every existing auth system proves who you are. Wallet Auth proves what you own. It is a new category of API access control where access is gated on wallet state — what a wallet holds, what it has staked, what attestations it carries — rather than identity.
Call POST /v1/attest with format: "jwt". InsumerAPI reads the blockchain, evaluates the conditions, and returns an ES256-signed JWT alongside the standard attestation response. Point any standard API gateway at the JWKS endpoint. No blockchain infrastructure needed on the verifying side. No balance exposure. No additional cost — same 1 credit as a standard attestation.
Gateway compatible. Wallet Auth JWTs are standard ES256 JWTs backed by a JWKS endpoint. Compatible with any system that accepts JWKS-backed JWTs:
Kong · Nginx (ngx_http_auth_jwt) · Cloudflare Access · AWS API Gateway · Azure API Management · Traefik · Envoy · any OAuth 2.0 middleware
Add "format": "jwt" to any attestation request. The response includes a jwt field alongside the standard sig and kid.
curl -X POST https://api.insumermodel.com/v1/attest \ -H "Content-Type: application/json" \ -H "x-api-key: YOUR_API_KEY" \ -d '{ "wallet": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "format": "jwt", "conditions": [{ "type": "token_balance", "contractAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "chainId": 1, "threshold": "1000", "decimals": 6, "label": "USDC >= 1000" }] }' # Response includes data.jwt alongside data.sig and data.kid # The jwt field is the Wallet Auth token — an ES256-signed JWT string
Pass either the full response object or the JWT string directly — insumer-verify v1.3.0 auto-detects the format.
// npm install insumer-verify import { verifyAttestation } from "insumer-verify"; // Option A: pass the full API response envelope const response = await res.json(); const result = await verifyAttestation(response, { jwksUrl: "https://insumermodel.com/.well-known/jwks.json" }); // Option B: pass just the JWT string const result = await verifyAttestation(response.data.jwt, { jwksUrl: "https://insumermodel.com/.well-known/jwks.json" }); console.log(result.valid); // true console.log(result.payload); // the verified attestation data
The JWT is a standard three-part token. Decode the payload to see the claims structure. Any JWT library in any language can read these claims.
{
"iss": "https://api.insumermodel.com", // issuer
"sub": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", // wallet address
"jti": "ATST-A7C3E1B2D4F56789", // attestation ID
"iat": 1741089600, // issued at (unix)
"exp": 1741091400, // expires in 30 min
"pass": true, // all conditions met
"conditionHash": ["0x3a7f..."], // array of all hashes
"blockNumber": "0x12a3b4f", // from first result
"blockTimestamp": "2026-03-04T12:00:00.000Z", // from first result
"results": [ // per-condition results
{
"condition": 0,
"label": "USDC >= 1000",
"type": "token_balance",
"chainId": 1,
"met": true,
"evaluatedCondition": { "type": "token_balance", ... },
"conditionHash": "0x3a7f...",
"blockNumber": "0x12a3b4f",
"blockTimestamp": "2026-03-04T12:00:00Z"
}
]
}
A Wallet Auth JWT can be forwarded from Service A to Service B and verified without re-querying the chain. The receiving service fetches the JWKS public key once, checks the ES256 signature, reads the claims, and makes an access decision — all without any blockchain infrastructure, any Insumer SDK, or any network call back to InsumerAPI. The JWT is self-contained proof of wallet state at a specific block height, valid for 30 minutes.
POST /v1/attestZero dependencies on the verifying side. Service B needs no blockchain node, no Insumer SDK, and no API key. Standard JWT verification with any language or gateway.
Use case: An AI agent obtains a Wallet Auth JWT from InsumerAPI and presents it as a bearer token when calling a downstream API. The downstream API verifies the JWT against the JWKS endpoint and grants access based on the pass claim — no blockchain interaction required.
JWKS endpoint: https://insumermodel.com/.well-known/jwks.json — also available at GET /v1/jwks. Key ID: insumer-attest-v1.
If we can’t verify, we don’t sign. When a data source is unavailable after retries, the API returns 503 with error code rpc_failure. No attestation signed, no JWT issued, no credits charged.
{
"ok": false,
"error": {
"code": "rpc_failure",
"message": "Unable to verify all conditions — data source unavailable after retries",
"failedConditions": [
{ "chainId": 1, "contractAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "message": "fetch failed" }
]
},
"meta": { "version": "1.0", "timestamp": "..." }
}
This is NOT a verification failure. Do not treat it as pass: false. It means the data source was temporarily unavailable and the API refused to sign an unverified result.
Retryable. Retry after 2–5 seconds. The failedConditions array tells you exactly which data source and chain failed.
Applies to: POST /v1/attest, POST /v1/trust, POST /v1/trust/batch, POST /v1/verify, POST /v1/acp/discount, POST /v1/ucp/discount.
How EIP-1186 storage proofs let you verify token balances against the Ethereum state trie without trusting any intermediary.
A deep dive into boolean attestation, condition types, ECDSA signing, and how the verification endpoint works under the hood.
Verify if a wallet owns an NFT from any collection across 38 chains. One API call, boolean result, no balance exposed.
Verify governance token holdings server-side for voting eligibility. Working code examples in Python, curl, and JavaScript.
Gate your API endpoints on wallet token holdings using JWT bearer tokens. Complete end-to-end tutorial.
See how this endpoint fits the full API → API Topology