You need to check if a wallet holds a specific token. Maybe you are building token-gated access, verifying eligibility for a discount, or scoring a wallet for a trust system. The traditional approach means running an RPC node (or paying for one), handling each chain separately, parsing contract ABIs, and managing decimals. Or you can do it in one API call across 33 chains. Here is how.
What you need
- A free InsumerAPI key. Get one here (10 free credits, no credit card).
- A wallet address to verify.
- The token contract address and chain ID.
That is it. No node. No ABI. No Web3 library.
The endpoint
The attestation endpoint is POST /v1/attest. You send a wallet address and an array of conditions. Each condition specifies a token, a chain, and a threshold. The API verifies on-chain whether the wallet meets each condition and returns a signed boolean result.
The response never reveals the actual amount in the wallet. You get true or false for each condition, plus an ECDSA P-256 signature proving the result is authentic.
Example 1: Verify USDC holdings on Ethereum
curl:
curl -X POST https://api.insumermodel.com/v1/attest \
-H "X-API-Key: insr_live_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{
"wallet": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
"conditions": [
{
"type": "token_balance",
"contractAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"chainId": 1,
"threshold": 100,
"decimals": 6,
"label": "USDC on Ethereum"
}
]
}'
Python:
import requests
API_KEY = "insr_live_YOUR_KEY_HERE"
BASE = "https://api.insumermodel.com"
resp = requests.post(
f"{BASE}/v1/attest",
headers={
"X-API-Key": API_KEY,
"Content-Type": "application/json",
},
json={
"wallet": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
"conditions": [
{
"type": "token_balance",
"contractAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"chainId": 1,
"threshold": 100,
"decimals": 6,
"label": "USDC on Ethereum",
}
],
},
)
data = resp.json()
print(f"Pass: {data['data']['attestation']['pass']}")
for r in data["data"]["attestation"]["results"]:
print(f" {r['label']}: {'met' if r['met'] else 'not met'}")
JavaScript (Node.js or browser):
const API_KEY = "insr_live_YOUR_KEY_HERE";
const BASE = "https://api.insumermodel.com";
const resp = await fetch(`${BASE}/v1/attest`, {
method: "POST",
headers: {
"X-API-Key": API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
wallet: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
conditions: [
{
type: "token_balance",
contractAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
chainId: 1,
threshold: 100,
decimals: 6,
label: "USDC on Ethereum",
},
],
}),
});
const data = await resp.json();
console.log("Pass:", data.data.attestation.pass);
data.data.attestation.results.forEach((r) => {
console.log(` ${r.label}: ${r.met ? "met" : "not met"}`);
});
What comes back
The response looks like this:
{
"ok": true,
"data": {
"attestation": {
"id": "ATST-A7C3E1B2D4F56789",
"pass": true,
"results": [
{
"condition": 0,
"label": "USDC on Ethereum",
"type": "token_balance",
"chainId": 1,
"met": true,
"evaluatedCondition": {
"type": "token_balance",
"chainId": 1,
"contractAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"operator": "gte",
"threshold": 100,
"decimals": 6
},
"conditionHash": "0x3a7f1b2c...",
"blockNumber": "0x12f4a80",
"blockTimestamp": "2026-02-28T12:00:00.000Z"
}
],
"passCount": 1,
"failCount": 0,
"attestedAt": "2026-02-28T12:00:00.000Z",
"expiresAt": "2026-02-28T12:30:00.000Z"
},
"sig": "...",
"kid": "insumer-attest-v1"
},
"meta": { "creditsRemaining": 99, "creditsCharged": 1, "version": "1.0", "timestamp": "2026-02-28T12:00:01.000Z" }
}
Key fields:
passistrueonly when all conditions are met.results[].mettells you whether each individual condition passed.sigis the ECDSA P-256 signature. You can verify it against the public key atGET /v1/jwksor the static/.well-known/jwks.json.expiresAtis 30 minutes from attestation time.- No balance amount appears anywhere in the response.
Example 2: Multiple conditions, multiple chains
You can verify up to 10 conditions in a single call, each on a different chain. This costs 1 credit total regardless of how many conditions you include.
curl -X POST https://api.insumermodel.com/v1/attest \
-H "X-API-Key: insr_live_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{
"wallet": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
"conditions": [
{
"type": "token_balance",
"contractAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"chainId": 1,
"threshold": 100,
"decimals": 6,
"label": "USDC on Ethereum"
},
{
"type": "token_balance",
"contractAddress": "0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE",
"chainId": 1,
"threshold": 1000000,
"decimals": 18,
"label": "SHIB on Ethereum"
},
{
"type": "nft_ownership",
"contractAddress": "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D",
"chainId": 1,
"label": "Bored Ape Yacht Club"
}
]
}'
Each result comes back independently. If the wallet holds USDC and SHIB but not a Bored Ape, you get met: true for the first two and met: false for the third. The overall pass will be false because not all conditions were met.
Example 3: NFT ownership check
For NFTs, use type: "nft_ownership". No threshold needed. The API verifies whether the wallet owns at least one NFT from the collection.
resp = requests.post(
f"{BASE}/v1/attest",
headers={"X-API-Key": API_KEY, "Content-Type": "application/json"},
json={
"wallet": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
"conditions": [
{
"type": "nft_ownership",
"contractAddress": "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D",
"chainId": 1,
"label": "Bored Ape Yacht Club",
}
],
},
)
result = resp.json()
owns_ape = result["data"]["attestation"]["results"][0]["met"]
print(f"Owns a Bored Ape: {owns_ape}")
Example 4: Solana tokens
Solana works the same way. Pass "solana" as the chain ID instead of a number.
curl -X POST https://api.insumermodel.com/v1/attest \
-H "X-API-Key: insr_live_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{
"solanaWallet": "YOUR_SOLANA_WALLET_ADDRESS",
"conditions": [
{
"type": "token_balance",
"contractAddress": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"chainId": "solana",
"threshold": 10,
"decimals": 6,
"label": "USDC on Solana"
}
]
}'
Verifying the signature
Every response includes an ECDSA P-256 signature in the sig field. To verify it independently, use the insumer-verify npm package:
npm install insumer-verify
import { verifyAttestation } from "insumer-verify";
// Pass the full API response envelope, not apiResponse.data
const result = await verifyAttestation(apiResponse);
console.log("Signature valid:", result.valid);
console.log("Signer:", result.kid);
The package fetches the public key from /.well-known/jwks.json and verifies the signature locally. No API call needed for verification. You can also pass a custom jwksUrl if you want to pin the key.
Supported chains
The API covers 32 blockchains with a single endpoint. No chain-switching, no different endpoints, no different libraries:
- EVM (26 chains): Ethereum, BNB Chain, Base, Avalanche, Polygon, Arbitrum, Optimism, Chiliz, Soneium, Plume, World Chain, Sonic, Gnosis, Mantle, Scroll, Linea, ZKsync, Blast, Celo, Moonbeam, opBNB, Unichain, Ink, Sei, Berachain, ApeChain
- EVM (4 additional): Taiko, Ronin, Moonriver, Viction
- Non-EVM: Solana, XRP Ledger
Use the chain ID number for EVM chains and "solana" as a string for Solana. The full list with chain IDs is in the OpenAPI spec.
Pricing
Each attestation call costs 1 credit regardless of how many conditions are included (up to 10). Free tier includes 10 credits. Credits are $0.04 each on paid plans.
For a full breakdown of tiers and pricing, see the developer portal.
What to build with this
Developers are using the attestation endpoint for:
- Token-gated access. Verify a wallet meets a condition before granting access to content, features, or communities.
- AI agent trust scoring. Check if an agent's wallet holds governance tokens, stablecoins, or NFTs as part of a trust evaluation.
- Discount eligibility. Verify token holdings at checkout and apply discounts automatically.
- Compliance gating. Use EAS attestation conditions to verify Coinbase KYC or Gitcoin Passport credentials on-chain.
- DAO tooling. Verify governance token holdings before allowing votes or proposals.
The full API reference covers additional endpoints including wallet trust profiles (POST /v1/trust), merchant discovery (GET /v1/merchants), and compliance templates (GET /v1/compliance/templates).
Get a free API key in 30 seconds
10 free credits. 32 blockchains. No credit card. Start verifying token holdings with one API call.
View Developer Portal