← InsumerAPICONTENT HISTORY

Update to InsumerAPI

Snapshot Oct 29, 2026 · 19:10 UTC · version 0.2.2

Collection source: downloaded plugin package.

WHAT CHANGED

Instructions updated for insumer-attest

Skill instructions — Now says: version: "0.3.2"

Observed in instructions or declared skills. Runtime behavior has not been tested.

Save InsumerAPI and check future changes in Following.

Up to 10 plugins free · no card required.

All fields and original values.

Skill instructions

Before

Oct 28, 2026 · 18:06 UTC

version: "0.3.1"

After

Oct 29, 2026 · 19:10 UTC

version: "0.3.2"

Supporting files

Before

Oct 28, 2026 · 18:06 UTC

[{"relative_path":"references/chains.md","size_in_bytes":4171},{"relative_path":"references/condition-shapes.md","size_in_bytes":9087},{"relative_path":"scripts/attest.py","size_in_bytes":2148}]

After

Oct 29, 2026 · 19:10 UTC

[{"relative_path":"references/chains.md","size_in_bytes":4471},{"relative_path":"references/condition-shapes.md","size_in_bytes":9289},{"relative_path":"scripts/attest.py","size_in_bytes":2148}]

Compare saved observations

Download comparison JSON

SKILL.md text changes

− removed · + added

--- before
+++ after
@@ -9,7 +9,7 @@
   holds with InsumerAPI, or to compose an InsumerAPI wallet_state signal in a
   multi-issuer trust envelope. Read, evaluate, sign, in one call.
 metadata:
-  version: "0.3.1"
+  version: "0.3.2"
   author: InsumerAPI
 ---
 
Full technical diff · 2 changed fields

changed /included_files

BEFORE
[
  {
    "relative_path": "references/chains.md",
    "size_in_bytes": 4171
  },
  {
    "relative_path": "references/condition-shapes.md",
    "size_in_bytes": 9087
  },
  {
    "relative_path": "scripts/attest.py",
    "size_in_bytes": 2148
  }
]
AFTER
[
  {
    "relative_path": "references/chains.md",
    "size_in_bytes": 4471
  },
  {
    "relative_path": "references/condition-shapes.md",
    "size_in_bytes": 9289
  },
  {
    "relative_path": "scripts/attest.py",
    "size_in_bytes": 2148
  }
]

changed /skill_md_contents

BEFORE
"---\nname: insumer-attest\ndescription: >\n  Wallet auth via InsumerAPI: condition-based access with ES256-signed,\n  JWKS-verifiable boolean responses (token balances across 37 chains, plus NFT\n  ownership, EAS attestations, Farcaster IDs and other condition types). Use\n  when the user wants InsumerAPI to give a \"verified yes or no\" on whether a\n  wallet satisfies an on-chain condition, to gate a feature by what a wallet\n  holds with InsumerAPI, or to compose an InsumerAPI wallet_state signal in a\n  multi-issuer trust envelope. Read, evaluate, sign, in one call.\nmetadata:\n  version: \"0.3.1\"\n  author: InsumerAPI\n---\n\n# InsumerAPI Wallet Condition Attestation\n\n**Boolean, not balance.** A signed `true`/`false` answering \"does this wallet satisfy this condition right now?\", never the underlying balance. The response is signed twice (ES256 and a post-quantum ML-DSA-65 signature) and verifiable offline against the public JWKS at `https://insumermodel.com/.well-known/jwks.json`. The signing key never leaves the issuer; anyone holding the JWKS can independently re-run the verification.\n\nYou send conditions in. You get cryptographically verifiable results out.\n\n## The primitive\n\nWallet auth is the OAuth-equivalent for what a wallet holds. The pattern is **read → evaluate → sign**:\n\n1. **Read**: InsumerAPI reads the wallet's on-chain state on the requested chain\n2. **Evaluate**: wallet state is checked against the supplied condition\n3. **Sign**: a boolean result is returned, ES256-signed, with a `conditionHash` for tamper detection and a block anchor for replay defense\n\n**No secrets. No identity-first. No static credentials.** Token gating is one form of condition-based access; this is the general primitive.\n\n## Capabilities\n\n- Single-call attestation across 37 chains: 31 EVM, Solana, XRPL, Bitcoin, Tron, Stellar, Sui\n- Up to 10 conditions per request: overall `pass` is `true` only if every condition is `true`\n- Ten condition types: `token_balance`, `nft_ownership` (33 of 37 chains: EVM + Solana + XRPL), `eas_attestation` (Ethereum, Optimism, Polygon, Base, Arbitrum), `farcaster_id`, `evm_view_call` (single-address-argument view function returning bool; `contractAddress`, `chainId` and `selector` required, EVM chains only), `ratio_to_amount` (EVM chains only; `contractAddress`, `chainId`, `multiple` and `amount` required; met when the balance is at least `multiple` times `amount`), `ratio_to_supply` (EVM chains, ERC-20 contracts only; `contractAddress`, `chainId` and `minFraction` required, a fraction above 0 and up to 1; met when the balance is at least that share of total supply). On v2 keys `multiple`, `amount` and `minFraction` are decimal strings, like `threshold`. `erc8004_agent` (Base; `chainId` and `agentId` required), `erc7710_delegation` (Base; `chainId`, `delegationManager`, `expectedDelegator`, `delegation` required; max 3 per call, 5-minute expiry), `account_code` (EVM chains only; `expect` required: `\"none\"` for a plain key account with no code, `\"eip7702\"` for an EIP-7702 delegation designator, `\"contract\"` for any other code; optional `delegate`, only with `\"eip7702\"`, met only when the designator points at that address; a non-EVM `chainId` or a `delegate` with another `expect` is a `400`)\n- Every response is signed twice: ES256 (`sig`, `kid`) and a post-quantum ML-DSA-65 signature (`pqSig`, `pqKid`, optional fields: check them when present). `format: \"jwt\"` adds an ES256 JWT (`jwt`) for standard JWT-library verification, with the same claims as a post-quantum JWT (`pqJwt`)\n- Optional EIP-1186 Merkle proofs (`proof: \"merkle\"`) for 27 of the 31 EVM chains (not ZKsync Era, Sei, Viction or XDC Network, nor any non-EVM chain): storage proofs on token_balance and ratio_to_amount conditions, account proofs (`subject: \"account_code\"`) on account_code conditions, plus revocation-slot proofs for erc7710_delegation on the verified v1.3.0 manager\n- 30-minute attestation TTL, 5 minutes when the request includes an `erc7710_delegation` condition (`expiresAt` in response)\n\n## Setup\n\nGet the API key from the `insumer-auth` skill, then:\n\n```bash\nexport INSUMER_API_KEY='insr_live_...'\n```\n\n## Reference values (do not hallucinate)\n\n- **API base**: `https://api.insumermodel.com`\n- **JWKS URL**: `https://insumermodel.com/.well-known/jwks.json`\n- **Signing algorithm**: ES256 (ECDSA P-256)\n- **Key IDs (`kid`)**: three over the same P-256 key: `insumer-attest-v2` (attest, every key issued since 2026-06-10), `insumer-trust-v2` (trust), `insumer-attest-v1` (pre-cutover keys, and the commerce discount path). **Resolve the key by the `kid` on the response; never pin one and never take `keys[0]`.** The `kid` also selects the verification rules: v1 signs bare JSON, v2 signs a domain-separated canonical preimage.\n- **Auth header**: `X-API-Key: insr_live_...`\n- **Attestation TTL**: 30 minutes, or 5 when the request includes an `erc7710_delegation` condition (`expiresAt` in response)\n- **Signature format**: base64 P1363 (88 chars) on the `sig` field; ES256 JWT on the `jwt` field when `format: \"jwt\"` is requested\n\n## Usage\n\n### Example 1: ERC-20 balance threshold\n\nUser says: \"Check if `0xd8dA...6045` holds at least 100 USDC on Base.\"\n\n```bash\ncurl -X POST https://api.insumermodel.com/v1/attest \\\n  -H \"X-API-Key: $INSUMER_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"wallet\": \"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045\",\n    \"conditions\": [\n      {\n        \"type\": \"token_balance\",\n        \"contractAddress\": \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\",\n        \"chainId\": 8453,\n        \"threshold\": \"100\",\n        \"label\": \"USDC >= 100 on Base\"\n      }\n    ]\n  }'\n```\n\nReturns `{ \"ok\": true, \"data\": { \"attestation\": { \"pass\": true|false, ... }, \"sig\": \"...\", \"kid\": \"insumer-attest-v2\", \"pqSig\": \"...\", \"pqKid\": \"insumer-attest-pq1\" }, \"meta\": { \"creditsRemaining\": ..., \"creditsCharged\": 1, ... } }`.\n\n### Example 2: NFT ownership\n\n```bash\ncurl -X POST https://api.insumermodel.com/v1/attest \\\n  -H \"X-API-Key: $INSUMER_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"wallet\": \"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045\",\n    \"conditions\": [\n      {\n        \"type\": \"nft_ownership\",\n        \"contractAddress\": \"0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D\",\n        \"chainId\": 1,\n        \"label\": \"Bored Ape holder\"\n      }\n    ]\n  }'\n```\n\n### Example 3: EAS attestation via compliance template\n\n```bash\ncurl -X POST https://api.insumermodel.com/v1/attest \\\n  -H \"X-API-Key: $INSUMER_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"wallet\": \"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045\",\n    \"conditions\": [\n      {\n        \"type\": \"eas_attestation\",\n        \"template\": \"coinbase_verified_account\",\n        \"label\": \"Coinbase KYC verified\"\n      }\n    ]\n  }'\n```\n\nAvailable templates: see `references/condition-shapes.md` or `GET https://api.insumermodel.com/v1/compliance/templates`.\n\n### Example 4: JWT format for standard library verification\n\nAdd `\"format\": \"jwt\"` to the request body to receive an ES256 JWT in the response (no extra cost). Verify with `jose` (Node), `PyJWT` (Python), `go-jose` (Go), etc., pointed at the JWKS URL. See the `insumer-jwks-verify` skill for the canonical recipe.\n\n### Example 5: Merkle storage proofs (advanced)\n\n```bash\ncurl -X POST https://api.insumermodel.com/v1/attest \\\n  -H \"X-API-Key: $INSUMER_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"wallet\": \"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045\",\n    \"proof\": \"merkle\",\n    \"conditions\": [\n      {\n        \"type\": \"token_balance\",\n        \"contractAddress\": \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\",\n        \"chainId\": 8453,\n        \"threshold\": \"100\",\n        \"label\": \"USDC >= 100 on Base\"\n      }\n    ]\n  }'\n```\n\n`proof: \"merkle\"` returns EIP-1186 storage proofs alongside the boolean and **costs 2 credits instead of 1** (1 if no proof could be delivered). **Note**: Merkle mode reveals the raw on-chain balance to the caller. Standard mode does not. Only opt in if the consumer needs the raw balance.\n\nProof subjects are three: `account_balance`, `account_code` and `delegation_revocation`, plus the subject-less ERC-20 slot proof. An `account_code` condition in proof mode carries an EIP-1186 account proof with `subject: \"account_code\"` and the fields `blockNumber`, `nonce`, `balance`, `storageHash`, `codeHash`, `accountProof`. `codeHash` is the proven value: 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 (checkable only with the `delegate` the verifier supplies); anything else means contract code. An account absent from the state trie may report all zeros, which also means no code. Standard mode never returns the code or the delegation target, only `met`.\n\n### Example 6: Account code state\n\n```bash\ncurl -X POST https://api.insumermodel.com/v1/attest \\\n  -H \"X-API-Key: $INSUMER_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"wallet\": \"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045\",\n    \"conditions\": [\n      { \"type\": \"account_code\", \"chainId\": 8453, \"expect\": \"eip7702\" }\n    ]\n  }'\n```\n\nReturns `met: true` for this wallet on Base (it carries an EIP-7702 delegation designator there). The signed `evaluatedCondition` is `{\"type\":\"account_code\",\"chainId\":8453,\"expect\":\"eip7702\",\"operator\":\"code_state\"}`. Add `\"delegate\": \"0x…\"` to require a specific delegation target; it is echoed, lowercase, inside the signed `evaluatedCondition`. See `references/condition-shapes.md`.\n\n### Example 7: XRPL trust line\n\n```bash\ncurl -X POST https://api.insumermodel.com/v1/attest \\\n  -H \"X-API-Key: $INSUMER_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"xrplWallet\": \"rN7n7otQDd6FczFgLdSqtcsAUxDkw6fzRH\",\n    \"conditions\": [\n      {\n        \"type\": \"token_balance\",\n        \"contractAddress\": \"rMxCKbEDwqr76QuheSUMdEGf4B9xJ8m5De\",\n        \"chainId\": \"xrpl\",\n        \"currency\": \"RLUSD\",\n        \"threshold\": \"50\",\n        \"label\": \"RLUSD >= 50 on XRPL\"\n      }\n    ]\n  }'\n```\n\nXRPL conditions use `xrplWallet` instead of `wallet`. A trust-line token also needs a `currency` field; native XRP and NFTs do not. See `references/chains.md` for the full chain coverage table.\n\n## Code emission rules\n\nWhen emitting integration code that calls `/v1/attest`, the agent MUST:\n\n1. **Read the API key from an env var.** Never inline `insr_live_...`.\n2. **Verify the signature offline.** Pair this skill with `insumer-jwks-verify`. The signed boolean is the product: the JSON body alone is untrusted.\n3. **Do not send `decimals`.** It is optional. Leave it out: the token's own decimals are always read from the chain. If sent it is only a cross-check: on EVM chains, Tron and Sui a value that differs from the token's own decimals is rejected with a `400`.\n3a. **Send the `token_balance` `threshold` as a decimal string** (`\"100\"`, not `100`). Keys created from 2026-06-10 sign with `kid: insumer-attest-v2` and reject a JSON number with a `400`; a string is accepted by both v1 and v2 keys.\n4. **Call from a backend, not a browser.** The API key is a backend credential.\n5. **Don't cache the verdict.** Cache the JWKS (the `jose` library's `createRemoteJWKSet` does this for you). Pass/fail expires at `expiresAt` (30 minutes, or 5 for an `erc7710_delegation` condition), and wallet state changes.\n6. **Don't request `proof: \"merkle\"` unless the caller needs the raw balance.** Standard mode is boolean-not-balance by construction; Merkle mode opts out of that privacy property.\n\n## Helper script\n\n`scripts/attest.py`: Python helper that wraps `POST /v1/attest`. Reads `INSUMER_API_KEY` from env, accepts the full JSON request body (wallet + conditions) on stdin or via `--body-file`, prints the signed response.\n\n```bash\necho '{\"wallet\":\"0x...\",\"conditions\":[{\"type\":\"token_balance\",...}]}' | python scripts/attest.py\n```\n\n## Error handling\n\n| Status | Cause | Fix |\n|---|---|---|\n| `400` | Missing/invalid wallet, conditions, or condition fields | Check request body against `references/condition-shapes.md` |\n| `401` | Invalid API key | See `insumer-auth` skill |\n| `402` | With a key: out of verification credits. With no key at all: a pay-per-call quote, not a credit problem | With a key, top up via Path 4 in `insumer-auth`, only after the user approves the payment. With no key, set `INSUMER_API_KEY` and call again |\n| `429` | Daily request limit reached | It resets on a timer, not by slowing down: wait the number of seconds in the `Retry-After` header |\n| `503` | Upstream blockchain data source unavailable | Retryable after a short delay; no credits charged |\n\nA `503` carries error code `rpc_failure`. It means a read did not complete and nothing was signed. It is never a `false`: do not report it as a condition that was not met. Retry the call.\n\n## Related skills\n\n| Skill | Purpose |\n|---|---|\n| `insumer-auth` | Get a free API key, configure env vars |\n| `insumer-jwks-verify` | Offline ES256 verification of the response |\n| `insumer-trust` | Curated multi-dimensional wallet profile (alternative to custom conditions) |\n\n## References\n\n- [chains.md](references/chains.md): full 37-chain coverage table\n- [condition-shapes.md](references/condition-shapes.md): every supported condition type with full request shape\n- [InsumerAPI OpenAPI spec](https://insumermodel.com/openapi.yaml)\n- [Public JWKS](https://insumermodel.com/.well-known/jwks.json)\n"
AFTER
"---\nname: insumer-attest\ndescription: >\n  Wallet auth via InsumerAPI: condition-based access with ES256-signed,\n  JWKS-verifiable boolean responses (token balances across 37 chains, plus NFT\n  ownership, EAS attestations, Farcaster IDs and other condition types). Use\n  when the user wants InsumerAPI to give a \"verified yes or no\" on whether a\n  wallet satisfies an on-chain condition, to gate a feature by what a wallet\n  holds with InsumerAPI, or to compose an InsumerAPI wallet_state signal in a\n  multi-issuer trust envelope. Read, evaluate, sign, in one call.\nmetadata:\n  version: \"0.3.2\"\n  author: InsumerAPI\n---\n\n# InsumerAPI Wallet Condition Attestation\n\n**Boolean, not balance.** A signed `true`/`false` answering \"does this wallet satisfy this condition right now?\", never the underlying balance. The response is signed twice (ES256 and a post-quantum ML-DSA-65 signature) and verifiable offline against the public JWKS at `https://insumermodel.com/.well-known/jwks.json`. The signing key never leaves the issuer; anyone holding the JWKS can independently re-run the verification.\n\nYou send conditions in. You get cryptographically verifiable results out.\n\n## The primitive\n\nWallet auth is the OAuth-equivalent for what a wallet holds. The pattern is **read → evaluate → sign**:\n\n1. **Read**: InsumerAPI reads the wallet's on-chain state on the requested chain\n2. **Evaluate**: wallet state is checked against the supplied condition\n3. **Sign**: a boolean result is returned, ES256-signed, with a `conditionHash` for tamper detection and a block anchor for replay defense\n\n**No secrets. No identity-first. No static credentials.** Token gating is one form of condition-based access; this is the general primitive.\n\n## Capabilities\n\n- Single-call attestation across 37 chains: 31 EVM, Solana, XRPL, Bitcoin, Tron, Stellar, Sui\n- Up to 10 conditions per request: overall `pass` is `true` only if every condition is `true`\n- Ten condition types: `token_balance`, `nft_ownership` (33 of 37 chains: EVM + Solana + XRPL), `eas_attestation` (Ethereum, Optimism, Polygon, Base, Arbitrum), `farcaster_id`, `evm_view_call` (single-address-argument view function returning bool; `contractAddress`, `chainId` and `selector` required, EVM chains only), `ratio_to_amount` (EVM chains only; `contractAddress`, `chainId`, `multiple` and `amount` required; met when the balance is at least `multiple` times `amount`), `ratio_to_supply` (EVM chains, ERC-20 contracts only; `contractAddress`, `chainId` and `minFraction` required, a fraction above 0 and up to 1; met when the balance is at least that share of total supply). On v2 keys `multiple`, `amount` and `minFraction` are decimal strings, like `threshold`. `erc8004_agent` (Base; `chainId` and `agentId` required), `erc7710_delegation` (Base; `chainId`, `delegationManager`, `expectedDelegator`, `delegation` required; max 3 per call, 5-minute expiry), `account_code` (EVM chains only; `expect` required: `\"none\"` for a plain key account with no code, `\"eip7702\"` for an EIP-7702 delegation designator, `\"contract\"` for any other code; optional `delegate`, only with `\"eip7702\"`, met only when the designator points at that address; a non-EVM `chainId` or a `delegate` with another `expect` is a `400`)\n- Every response is signed twice: ES256 (`sig`, `kid`) and a post-quantum ML-DSA-65 signature (`pqSig`, `pqKid`, optional fields: check them when present). `format: \"jwt\"` adds an ES256 JWT (`jwt`) for standard JWT-library verification, with the same claims as a post-quantum JWT (`pqJwt`)\n- Optional EIP-1186 Merkle proofs (`proof: \"merkle\"`) for 27 of the 31 EVM chains (not ZKsync Era, Sei, Viction or XDC Network, nor any non-EVM chain): storage proofs on token_balance and ratio_to_amount conditions, account proofs (`subject: \"account_code\"`) on account_code conditions, plus revocation-slot proofs for erc7710_delegation on the verified v1.3.0 manager\n- 30-minute attestation TTL, 5 minutes when the request includes an `erc7710_delegation` condition (`expiresAt` in response)\n\n## Setup\n\nGet the API key from the `insumer-auth` skill, then:\n\n```bash\nexport INSUMER_API_KEY='insr_live_...'\n```\n\n## Reference values (do not hallucinate)\n\n- **API base**: `https://api.insumermodel.com`\n- **JWKS URL**: `https://insumermodel.com/.well-known/jwks.json`\n- **Signing algorithm**: ES256 (ECDSA P-256)\n- **Key IDs (`kid`)**: three over the same P-256 key: `insumer-attest-v2` (attest, every key issued since 2026-06-10), `insumer-trust-v2` (trust), `insumer-attest-v1` (pre-cutover keys, and the commerce discount path). **Resolve the key by the `kid` on the response; never pin one and never take `keys[0]`.** The `kid` also selects the verification rules: v1 signs bare JSON, v2 signs a domain-separated canonical preimage.\n- **Auth header**: `X-API-Key: insr_live_...`\n- **Attestation TTL**: 30 minutes, or 5 when the request includes an `erc7710_delegation` condition (`expiresAt` in response)\n- **Signature format**: base64 P1363 (88 chars) on the `sig` field; ES256 JWT on the `jwt` field when `format: \"jwt\"` is requested\n\n## Usage\n\n### Example 1: ERC-20 balance threshold\n\nUser says: \"Check if `0xd8dA...6045` holds at least 100 USDC on Base.\"\n\n```bash\ncurl -X POST https://api.insumermodel.com/v1/attest \\\n  -H \"X-API-Key: $INSUMER_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"wallet\": \"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045\",\n    \"conditions\": [\n      {\n        \"type\": \"token_balance\",\n        \"contractAddress\": \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\",\n        \"chainId\": 8453,\n        \"threshold\": \"100\",\n        \"label\": \"USDC >= 100 on Base\"\n      }\n    ]\n  }'\n```\n\nReturns `{ \"ok\": true, \"data\": { \"attestation\": { \"pass\": true|false, ... }, \"sig\": \"...\", \"kid\": \"insumer-attest-v2\", \"pqSig\": \"...\", \"pqKid\": \"insumer-attest-pq1\" }, \"meta\": { \"creditsRemaining\": ..., \"creditsCharged\": 1, ... } }`.\n\n### Example 2: NFT ownership\n\n```bash\ncurl -X POST https://api.insumermodel.com/v1/attest \\\n  -H \"X-API-Key: $INSUMER_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"wallet\": \"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045\",\n    \"conditions\": [\n      {\n        \"type\": \"nft_ownership\",\n        \"contractAddress\": \"0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D\",\n        \"chainId\": 1,\n        \"label\": \"Bored Ape holder\"\n      }\n    ]\n  }'\n```\n\n### Example 3: EAS attestation via compliance template\n\n```bash\ncurl -X POST https://api.insumermodel.com/v1/attest \\\n  -H \"X-API-Key: $INSUMER_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"wallet\": \"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045\",\n    \"conditions\": [\n      {\n        \"type\": \"eas_attestation\",\n        \"template\": \"coinbase_verified_account\",\n        \"label\": \"Coinbase KYC verified\"\n      }\n    ]\n  }'\n```\n\nAvailable templates: see `references/condition-shapes.md` or `GET https://api.insumermodel.com/v1/compliance/templates`.\n\n### Example 4: JWT format for standard library verification\n\nAdd `\"format\": \"jwt\"` to the request body to receive an ES256 JWT in the response (no extra cost). Verify with `jose` (Node), `PyJWT` (Python), `go-jose` (Go), etc., pointed at the JWKS URL. See the `insumer-jwks-verify` skill for the canonical recipe.\n\n### Example 5: Merkle storage proofs (advanced)\n\n```bash\ncurl -X POST https://api.insumermodel.com/v1/attest \\\n  -H \"X-API-Key: $INSUMER_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"wallet\": \"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045\",\n    \"proof\": \"merkle\",\n    \"conditions\": [\n      {\n        \"type\": \"token_balance\",\n        \"contractAddress\": \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\",\n        \"chainId\": 8453,\n        \"threshold\": \"100\",\n        \"label\": \"USDC >= 100 on Base\"\n      }\n    ]\n  }'\n```\n\n`proof: \"merkle\"` returns EIP-1186 storage proofs alongside the boolean and **costs 2 credits instead of 1** (1 if no proof could be delivered). **Note**: Merkle mode reveals the raw on-chain balance to the caller. Standard mode does not. Only opt in if the consumer needs the raw balance.\n\nProof subjects are three: `account_balance`, `account_code` and `delegation_revocation`, plus the subject-less ERC-20 slot proof. An `account_code` condition in proof mode carries an EIP-1186 account proof with `subject: \"account_code\"` and the fields `blockNumber`, `nonce`, `balance`, `storageHash`, `codeHash`, `accountProof`. `codeHash` is the proven value: 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 (checkable only with the `delegate` the verifier supplies); anything else means contract code. An account absent from the state trie may report all zeros, which also means no code. Standard mode never returns the code or the delegation target, only `met`.\n\n### Example 6: Account code state\n\n```bash\ncurl -X POST https://api.insumermodel.com/v1/attest \\\n  -H \"X-API-Key: $INSUMER_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"wallet\": \"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045\",\n    \"conditions\": [\n      { \"type\": \"account_code\", \"chainId\": 8453, \"expect\": \"eip7702\" }\n    ]\n  }'\n```\n\nReturns `met: true` for this wallet on Base (it carries an EIP-7702 delegation designator there). The signed `evaluatedCondition` is `{\"type\":\"account_code\",\"chainId\":8453,\"expect\":\"eip7702\",\"operator\":\"code_state\"}`. Add `\"delegate\": \"0x…\"` to require a specific delegation target; it is echoed, lowercase, inside the signed `evaluatedCondition`. See `references/condition-shapes.md`.\n\n### Example 7: XRPL trust line\n\n```bash\ncurl -X POST https://api.insumermodel.com/v1/attest \\\n  -H \"X-API-Key: $INSUMER_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"xrplWallet\": \"rN7n7otQDd6FczFgLdSqtcsAUxDkw6fzRH\",\n    \"conditions\": [\n      {\n        \"type\": \"token_balance\",\n        \"contractAddress\": \"rMxCKbEDwqr76QuheSUMdEGf4B9xJ8m5De\",\n        \"chainId\": \"xrpl\",\n        \"currency\": \"RLUSD\",\n        \"threshold\": \"50\",\n        \"label\": \"RLUSD >= 50 on XRPL\"\n      }\n    ]\n  }'\n```\n\nXRPL conditions use `xrplWallet` instead of `wallet`. A trust-line token also needs a `currency` field; native XRP and NFTs do not. See `references/chains.md` for the full chain coverage table.\n\n## Code emission rules\n\nWhen emitting integration code that calls `/v1/attest`, the agent MUST:\n\n1. **Read the API key from an env var.** Never inline `insr_live_...`.\n2. **Verify the signature offline.** Pair this skill with `insumer-jwks-verify`. The signed boolean is the product: the JSON body alone is untrusted.\n3. **Do not send `decimals`.** It is optional. Leave it out: the token's own decimals are always read from the chain. If sent it is only a cross-check: on EVM chains, Tron and Sui a value that differs from the token's own decimals is rejected with a `400`.\n3a. **Send the `token_balance` `threshold` as a decimal string** (`\"100\"`, not `100`). Keys created from 2026-06-10 sign with `kid: insumer-attest-v2` and reject a JSON number with a `400`; a string is accepted by both v1 and v2 keys.\n4. **Call from a backend, not a browser.** The API key is a backend credential.\n5. **Don't cache the verdict.** Cache the JWKS (the `jose` library's `createRemoteJWKSet` does this for you). Pass/fail expires at `expiresAt` (30 minutes, or 5 for an `erc7710_delegation` condition), and wallet state changes.\n6. **Don't request `proof: \"merkle\"` unless the caller needs the raw balance.** Standard mode is boolean-not-balance by construction; Merkle mode opts out of that privacy property.\n\n## Helper script\n\n`scripts/attest.py`: Python helper that wraps `POST /v1/attest`. Reads `INSUMER_API_KEY` from env, accepts the full JSON request body (wallet + conditions) on stdin or via `--body-file`, prints the signed response.\n\n```bash\necho '{\"wallet\":\"0x...\",\"conditions\":[{\"type\":\"token_balance\",...}]}' | python scripts/attest.py\n```\n\n## Error handling\n\n| Status | Cause | Fix |\n|---|---|---|\n| `400` | Missing/invalid wallet, conditions, or condition fields | Check request body against `references/condition-shapes.md` |\n| `401` | Invalid API key | See `insumer-auth` skill |\n| `402` | With a key: out of verification credits. With no key at all: a pay-per-call quote, not a credit problem | With a key, top up via Path 4 in `insumer-auth`, only after the user approves the payment. With no key, set `INSUMER_API_KEY` and call again |\n| `429` | Daily request limit reached | It resets on a timer, not by slowing down: wait the number of seconds in the `Retry-After` header |\n| `503` | Upstream blockchain data source unavailable | Retryable after a short delay; no credits charged |\n\nA `503` carries error code `rpc_failure`. It means a read did not complete and nothing was signed. It is never a `false`: do not report it as a condition that was not met. Retry the call.\n\n## Related skills\n\n| Skill | Purpose |\n|---|---|\n| `insumer-auth` | Get a free API key, configure env vars |\n| `insumer-jwks-verify` | Offline ES256 verification of the response |\n| `insumer-trust` | Curated multi-dimensional wallet profile (alternative to custom conditions) |\n\n## References\n\n- [chains.md](references/chains.md): full 37-chain coverage table\n- [condition-shapes.md](references/condition-shapes.md): every supported condition type with full request shape\n- [InsumerAPI OpenAPI spec](https://insumermodel.com/openapi.yaml)\n- [Public JWKS](https://insumermodel.com/.well-known/jwks.json)\n"
Full snapshot data
{
  "description": "Wallet auth via InsumerAPI: condition-based access with ES256-signed, JWKS-verifiable boolean responses (token balances across 37 chains, plus NFT ownership, EAS attestations, Farcaster IDs and other condition types). Use when the user wants InsumerAPI to give a \"verified yes or no\" on whether a wallet satisfies an on-chain condition, to gate a feature by what a wallet holds with InsumerAPI, or to compose an InsumerAPI wallet_state signal in a multi-issuer trust envelope. Read, evaluate, sign, in one call.\n",
  "included_files": [
    {
      "relative_path": "references/chains.md",
      "size_in_bytes": 4471
    },
    {
      "relative_path": "references/condition-shapes.md",
      "size_in_bytes": 9289
    },
    {
      "relative_path": "scripts/attest.py",
      "size_in_bytes": 2148
    }
  ],
  "name": "insumer-attest",
  "skill_md_contents": "---\nname: insumer-attest\ndescription: >\n  Wallet auth via InsumerAPI: condition-based access with ES256-signed,\n  JWKS-verifiable boolean responses (token balances across 37 chains, plus NFT\n  ownership, EAS attestations, Farcaster IDs and other condition types). Use\n  when the user wants InsumerAPI to give a \"verified yes or no\" on whether a\n  wallet satisfies an on-chain condition, to gate a feature by what a wallet\n  holds with InsumerAPI, or to compose an InsumerAPI wallet_state signal in a\n  multi-issuer trust envelope. Read, evaluate, sign, in one call.\nmetadata:\n  version: \"0.3.2\"\n  author: InsumerAPI\n---\n\n# InsumerAPI Wallet Condition Attestation\n\n**Boolean, not balance.** A signed `true`/`false` answering \"does this wallet satisfy this condition right now?\", never the underlying balance. The response is signed twice (ES256 and a post-quantum ML-DSA-65 signature) and verifiable offline against the public JWKS at `https://insumermodel.com/.well-known/jwks.json`. The signing key never leaves the issuer; anyone holding the JWKS can independently re-run the verification.\n\nYou send conditions in. You get cryptographically verifiable results out.\n\n## The primitive\n\nWallet auth is the OAuth-equivalent for what a wallet holds. The pattern is **read → evaluate → sign**:\n\n1. **Read**: InsumerAPI reads the wallet's on-chain state on the requested chain\n2. **Evaluate**: wallet state is checked against the supplied condition\n3. **Sign**: a boolean result is returned, ES256-signed, with a `conditionHash` for tamper detection and a block anchor for replay defense\n\n**No secrets. No identity-first. No static credentials.** Token gating is one form of condition-based access; this is the general primitive.\n\n## Capabilities\n\n- Single-call attestation across 37 chains: 31 EVM, Solana, XRPL, Bitcoin, Tron, Stellar, Sui\n- Up to 10 conditions per request: overall `pass` is `true` only if every condition is `true`\n- Ten condition types: `token_balance`, `nft_ownership` (33 of 37 chains: EVM + Solana + XRPL), `eas_attestation` (Ethereum, Optimism, Polygon, Base, Arbitrum), `farcaster_id`, `evm_view_call` (single-address-argument view function returning bool; `contractAddress`, `chainId` and `selector` required, EVM chains only), `ratio_to_amount` (EVM chains only; `contractAddress`, `chainId`, `multiple` and `amount` required; met when the balance is at least `multiple` times `amount`), `ratio_to_supply` (EVM chains, ERC-20 contracts only; `contractAddress`, `chainId` and `minFraction` required, a fraction above 0 and up to 1; met when the balance is at least that share of total supply). On v2 keys `multiple`, `amount` and `minFraction` are decimal strings, like `threshold`. `erc8004_agent` (Base; `chainId` and `agentId` required), `erc7710_delegation` (Base; `chainId`, `delegationManager`, `expectedDelegator`, `delegation` required; max 3 per call, 5-minute expiry), `account_code` (EVM chains only; `expect` required: `\"none\"` for a plain key account with no code, `\"eip7702\"` for an EIP-7702 delegation designator, `\"contract\"` for any other code; optional `delegate`, only with `\"eip7702\"`, met only when the designator points at that address; a non-EVM `chainId` or a `delegate` with another `expect` is a `400`)\n- Every response is signed twice: ES256 (`sig`, `kid`) and a post-quantum ML-DSA-65 signature (`pqSig`, `pqKid`, optional fields: check them when present). `format: \"jwt\"` adds an ES256 JWT (`jwt`) for standard JWT-library verification, with the same claims as a post-quantum JWT (`pqJwt`)\n- Optional EIP-1186 Merkle proofs (`proof: \"merkle\"`) for 27 of the 31 EVM chains (not ZKsync Era, Sei, Viction or XDC Network, nor any non-EVM chain): storage proofs on token_balance and ratio_to_amount conditions, account proofs (`subject: \"account_code\"`) on account_code conditions, plus revocation-slot proofs for erc7710_delegation on the verified v1.3.0 manager\n- 30-minute attestation TTL, 5 minutes when the request includes an `erc7710_delegation` condition (`expiresAt` in response)\n\n## Setup\n\nGet the API key from the `insumer-auth` skill, then:\n\n```bash\nexport INSUMER_API_KEY='insr_live_...'\n```\n\n## Reference values (do not hallucinate)\n\n- **API base**: `https://api.insumermodel.com`\n- **JWKS URL**: `https://insumermodel.com/.well-known/jwks.json`\n- **Signing algorithm**: ES256 (ECDSA P-256)\n- **Key IDs (`kid`)**: three over the same P-256 key: `insumer-attest-v2` (attest, every key issued since 2026-06-10), `insumer-trust-v2` (trust), `insumer-attest-v1` (pre-cutover keys, and the commerce discount path). **Resolve the key by the `kid` on the response; never pin one and never take `keys[0]`.** The `kid` also selects the verification rules: v1 signs bare JSON, v2 signs a domain-separated canonical preimage.\n- **Auth header**: `X-API-Key: insr_live_...`\n- **Attestation TTL**: 30 minutes, or 5 when the request includes an `erc7710_delegation` condition (`expiresAt` in response)\n- **Signature format**: base64 P1363 (88 chars) on the `sig` field; ES256 JWT on the `jwt` field when `format: \"jwt\"` is requested\n\n## Usage\n\n### Example 1: ERC-20 balance threshold\n\nUser says: \"Check if `0xd8dA...6045` holds at least 100 USDC on Base.\"\n\n```bash\ncurl -X POST https://api.insumermodel.com/v1/attest \\\n  -H \"X-API-Key: $INSUMER_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"wallet\": \"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045\",\n    \"conditions\": [\n      {\n        \"type\": \"token_balance\",\n        \"contractAddress\": \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\",\n        \"chainId\": 8453,\n        \"threshold\": \"100\",\n        \"label\": \"USDC >= 100 on Base\"\n      }\n    ]\n  }'\n```\n\nReturns `{ \"ok\": true, \"data\": { \"attestation\": { \"pass\": true|false, ... }, \"sig\": \"...\", \"kid\": \"insumer-attest-v2\", \"pqSig\": \"...\", \"pqKid\": \"insumer-attest-pq1\" }, \"meta\": { \"creditsRemaining\": ..., \"creditsCharged\": 1, ... } }`.\n\n### Example 2: NFT ownership\n\n```bash\ncurl -X POST https://api.insumermodel.com/v1/attest \\\n  -H \"X-API-Key: $INSUMER_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"wallet\": \"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045\",\n    \"conditions\": [\n      {\n        \"type\": \"nft_ownership\",\n        \"contractAddress\": \"0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D\",\n        \"chainId\": 1,\n        \"label\": \"Bored Ape holder\"\n      }\n    ]\n  }'\n```\n\n### Example 3: EAS attestation via compliance template\n\n```bash\ncurl -X POST https://api.insumermodel.com/v1/attest \\\n  -H \"X-API-Key: $INSUMER_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"wallet\": \"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045\",\n    \"conditions\": [\n      {\n        \"type\": \"eas_attestation\",\n        \"template\": \"coinbase_verified_account\",\n        \"label\": \"Coinbase KYC verified\"\n      }\n    ]\n  }'\n```\n\nAvailable templates: see `references/condition-shapes.md` or `GET https://api.insumermodel.com/v1/compliance/templates`.\n\n### Example 4: JWT format for standard library verification\n\nAdd `\"format\": \"jwt\"` to the request body to receive an ES256 JWT in the response (no extra cost). Verify with `jose` (Node), `PyJWT` (Python), `go-jose` (Go), etc., pointed at the JWKS URL. See the `insumer-jwks-verify` skill for the canonical recipe.\n\n### Example 5: Merkle storage proofs (advanced)\n\n```bash\ncurl -X POST https://api.insumermodel.com/v1/attest \\\n  -H \"X-API-Key: $INSUMER_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"wallet\": \"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045\",\n    \"proof\": \"merkle\",\n    \"conditions\": [\n      {\n        \"type\": \"token_balance\",\n        \"contractAddress\": \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\",\n        \"chainId\": 8453,\n        \"threshold\": \"100\",\n        \"label\": \"USDC >= 100 on Base\"\n      }\n    ]\n  }'\n```\n\n`proof: \"merkle\"` returns EIP-1186 storage proofs alongside the boolean and **costs 2 credits instead of 1** (1 if no proof could be delivered). **Note**: Merkle mode reveals the raw on-chain balance to the caller. Standard mode does not. Only opt in if the consumer needs the raw balance.\n\nProof subjects are three: `account_balance`, `account_code` and `delegation_revocation`, plus the subject-less ERC-20 slot proof. An `account_code` condition in proof mode carries an EIP-1186 account proof with `subject: \"account_code\"` and the fields `blockNumber`, `nonce`, `balance`, `storageHash`, `codeHash`, `accountProof`. `codeHash` is the proven value: 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 (checkable only with the `delegate` the verifier supplies); anything else means contract code. An account absent from the state trie may report all zeros, which also means no code. Standard mode never returns the code or the delegation target, only `met`.\n\n### Example 6: Account code state\n\n```bash\ncurl -X POST https://api.insumermodel.com/v1/attest \\\n  -H \"X-API-Key: $INSUMER_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"wallet\": \"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045\",\n    \"conditions\": [\n      { \"type\": \"account_code\", \"chainId\": 8453, \"expect\": \"eip7702\" }\n    ]\n  }'\n```\n\nReturns `met: true` for this wallet on Base (it carries an EIP-7702 delegation designator there). The signed `evaluatedCondition` is `{\"type\":\"account_code\",\"chainId\":8453,\"expect\":\"eip7702\",\"operator\":\"code_state\"}`. Add `\"delegate\": \"0x…\"` to require a specific delegation target; it is echoed, lowercase, inside the signed `evaluatedCondition`. See `references/condition-shapes.md`.\n\n### Example 7: XRPL trust line\n\n```bash\ncurl -X POST https://api.insumermodel.com/v1/attest \\\n  -H \"X-API-Key: $INSUMER_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"xrplWallet\": \"rN7n7otQDd6FczFgLdSqtcsAUxDkw6fzRH\",\n    \"conditions\": [\n      {\n        \"type\": \"token_balance\",\n        \"contractAddress\": \"rMxCKbEDwqr76QuheSUMdEGf4B9xJ8m5De\",\n        \"chainId\": \"xrpl\",\n        \"currency\": \"RLUSD\",\n        \"threshold\": \"50\",\n        \"label\": \"RLUSD >= 50 on XRPL\"\n      }\n    ]\n  }'\n```\n\nXRPL conditions use `xrplWallet` instead of `wallet`. A trust-line token also needs a `currency` field; native XRP and NFTs do not. See `references/chains.md` for the full chain coverage table.\n\n## Code emission rules\n\nWhen emitting integration code that calls `/v1/attest`, the agent MUST:\n\n1. **Read the API key from an env var.** Never inline `insr_live_...`.\n2. **Verify the signature offline.** Pair this skill with `insumer-jwks-verify`. The signed boolean is the product: the JSON body alone is untrusted.\n3. **Do not send `decimals`.** It is optional. Leave it out: the token's own decimals are always read from the chain. If sent it is only a cross-check: on EVM chains, Tron and Sui a value that differs from the token's own decimals is rejected with a `400`.\n3a. **Send the `token_balance` `threshold` as a decimal string** (`\"100\"`, not `100`). Keys created from 2026-06-10 sign with `kid: insumer-attest-v2` and reject a JSON number with a `400`; a string is accepted by both v1 and v2 keys.\n4. **Call from a backend, not a browser.** The API key is a backend credential.\n5. **Don't cache the verdict.** Cache the JWKS (the `jose` library's `createRemoteJWKSet` does this for you). Pass/fail expires at `expiresAt` (30 minutes, or 5 for an `erc7710_delegation` condition), and wallet state changes.\n6. **Don't request `proof: \"merkle\"` unless the caller needs the raw balance.** Standard mode is boolean-not-balance by construction; Merkle mode opts out of that privacy property.\n\n## Helper script\n\n`scripts/attest.py`: Python helper that wraps `POST /v1/attest`. Reads `INSUMER_API_KEY` from env, accepts the full JSON request body (wallet + conditions) on stdin or via `--body-file`, prints the signed response.\n\n```bash\necho '{\"wallet\":\"0x...\",\"conditions\":[{\"type\":\"token_balance\",...}]}' | python scripts/attest.py\n```\n\n## Error handling\n\n| Status | Cause | Fix |\n|---|---|---|\n| `400` | Missing/invalid wallet, conditions, or condition fields | Check request body against `references/condition-shapes.md` |\n| `401` | Invalid API key | See `insumer-auth` skill |\n| `402` | With a key: out of verification credits. With no key at all: a pay-per-call quote, not a credit problem | With a key, top up via Path 4 in `insumer-auth`, only after the user approves the payment. With no key, set `INSUMER_API_KEY` and call again |\n| `429` | Daily request limit reached | It resets on a timer, not by slowing down: wait the number of seconds in the `Retry-After` header |\n| `503` | Upstream blockchain data source unavailable | Retryable after a short delay; no credits charged |\n\nA `503` carries error code `rpc_failure`. It means a read did not complete and nothing was signed. It is never a `false`: do not report it as a condition that was not met. Retry the call.\n\n## Related skills\n\n| Skill | Purpose |\n|---|---|\n| `insumer-auth` | Get a free API key, configure env vars |\n| `insumer-jwks-verify` | Offline ES256 verification of the response |\n| `insumer-trust` | Curated multi-dimensional wallet profile (alternative to custom conditions) |\n\n## References\n\n- [chains.md](references/chains.md): full 37-chain coverage table\n- [condition-shapes.md](references/condition-shapes.md): every supported condition type with full request shape\n- [InsumerAPI OpenAPI spec](https://insumermodel.com/openapi.yaml)\n- [Public JWKS](https://insumermodel.com/.well-known/jwks.json)\n"
}

SHA-256 of public snapshot: c2873cc0bf9c889a898936c3aaaba944eda3f5bfa2e65b0f30666be11fad00e5