Create merchants, verify domain ownership, configure discount tiers, buy credits with USDC, and publish to the directory. All via API. No dashboard needed.
Configures merchants for the verification and commerce endpoints.
Building this in Claude Code? Install the wallet auth skill and Claude will write correct, signature-verifying integration code on the first try.
git clone https://github.com/insumerapi/insumer-skill.git ~/.claude/skills/insumer
Register merchants, prove domain ownership, set up token and NFT discount tiers, and make them discoverable in the public directory. Designed for AI agents that onboard businesses autonomously.
POST /v1/keys/buy (no email needed)POST /v1/attest with any wallet and conditionPOST /v1/merchants with your company namePUT /v1/merchants/:id/tokens with at least one tierPOST /v1/acp/discount with a wallet that qualifiesDomain verification and directory publishing are optional. You can generate discounts as soon as tokens are configured.
POST /v1/merchants with companyName and companyId
POST then PUT /v1/merchants/:id/domain-verification
PUT /v1/merchants/:id/tokens with tiers
PUT /v1/merchants/:id/nfts (optional)
PUT /v1/merchants/:id/settings (discountMode, cap, USDC)
POST /v1/merchants/:id/directory
Creates a new merchant account and enables API access immediately. The API key that creates it owns it and pays one credit for each discount code or NFC tap that carries a discount (a 0% result is free) and for every in-store scan; the store has no balance of its own. credits in the response is the owner key's current balance. A key can own a limited number of merchants; past the limit, creating one returns 429.
| Parameter | Type | Description |
|---|---|---|
| companyName | string required | Business name. Max 100 characters. |
| companyId | string required | Unique slug. 2-50 characters, alphanumeric, dash, or underscore. |
| location | string optional | Business location. Max 200 characters. |
| allowDuplicateName | boolean optional | Set true to create a merchant whose companyName matches an existing one. Without it, a duplicate name returns 409. |
curl -X POST https://api.insumermodel.com/v1/merchants \ -H "Content-Type: application/json" \ -H "x-api-key: YOUR_API_KEY" \ -d '{ "companyName": "Acme Coffee", "companyId": "acme-coffee", "location": "New York, NY" }'
{
"ok": true,
"data": {
"id": "acme-coffee",
"companyName": "Acme Coffee",
"credits": 250,
"apiAccessEnabled": true
},
"meta": { "version": "1.0", "timestamp": "2026-02-27T12:00:00.000Z" }
}
Generates a verification token and returns instructions for DNS, meta tag, and file-based domain verification.
| Parameter | Type | Description |
|---|---|---|
| domain | string required | Domain to verify. No protocol prefix (e.g. acme.com not https://acme.com). |
curl -X POST https://api.insumermodel.com/v1/merchants/acme-coffee/domain-verification \ -H "Content-Type: application/json" \ -H "x-api-key: YOUR_API_KEY" \ -d '{ "domain": "acme.com" }'
{
"ok": true,
"data": {
"domain": "acme.com",
"token": "abc123xyz",
"methods": {
"dns": {
"type": "TXT",
"host": "acme.com",
"value": "abc123xyz",
"instructions": "Add a TXT record..."
},
"meta": {
"tag": "<meta name=\"insumer-verification\" content=\"abc123xyz\">",
"instructions": "Add this meta tag inside <head>"
},
"file": {
"path": "/insumer-verify.txt",
"content": "abc123xyz",
"instructions": "Host file at /insumer-verify.txt"
}
}
},
"meta": { "version": "1.0", "timestamp": "2026-02-27T12:00:00.000Z" }
}
Checks whether the verification token is present at the domain. Rate limited per merchant (the 429 says when to retry).
No request body. Send an empty PUT.
curl -X PUT https://api.insumermodel.com/v1/merchants/acme-coffee/domain-verification \
-H "x-api-key: YOUR_API_KEY"
{
"ok": true,
"data": {
"verified": true,
"domain": "acme.com",
"method": "dns"
},
"meta": { "version": "1.0", "timestamp": "2026-02-27T12:00:00.000Z" }
}
// Response (not verified):
{
"ok": true,
"data": {
"verified": false,
"domain": "acme.com",
"message": "Verification token not found...",
"attemptsRemaining": 4
},
"meta": { "version": "1.0", "timestamp": "2026-02-27T12:00:00.000Z" }
}
Sets the merchant's own token and partner token discount tiers. Maximum 8 tokens total. Tiers must be in ascending threshold order with discounts between 1% and 50%. A discount is a whole number: a value with a fraction, such as 10.5, returns 400.
| Parameter | Type | Description |
|---|---|---|
| ownToken | object optional | Merchant's own token: symbol, chainId (number, "solana", or "xrpl"), contractAddress, decimals, tiers array of {name, threshold, discount}. decimals is required (0 to 18) but is not used when a discount is evaluated: the token’s own decimals are read from the chain. For Solana, contractAddress is "native" for SOL or the mint address (base58, 32 to 44 characters). For XRPL trust line tokens, include currency and use the issuer r-address as contractAddress; the address checksum is verified. Enter the currency code exactly as the issuer created it: a 3-character code, a token name of 1 to 20 printable ASCII characters, or a 40-character hex code. Codes are case-sensitive and stored as entered. For native XRP, use contractAddress: "native" and leave currency out. An address or currency that fails these checks returns 400. To switch the own token off, send null or {"enabled": false}; enabled must be a boolean, and any other value returns 400. |
| partnerTokens | array optional | Partner tokens. Same structure as ownToken. Combined total max 8. |
curl -X PUT https://api.insumermodel.com/v1/merchants/acme-coffee/tokens \ -H "Content-Type: application/json" \ -H "x-api-key: YOUR_API_KEY" \ -d '{ "ownToken": { "symbol": "ACME", "chainId": 1, "contractAddress": "0x1234...abcd", "decimals": 18, "tiers": [ { "name": "Bronze", "threshold": 100, "discount": 5 }, { "name": "Silver", "threshold": 500, "discount": 10 }, { "name": "Gold", "threshold": 1000, "discount": 15 } ] }, "partnerTokens": [{ "symbol": "USDC", "chainId": 1, "contractAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "decimals": 6, "tiers": [ { "name": "Holder", "threshold": 100, "discount": 3 } ] }] }'
{
"ok": true,
"data": {
"ownToken": {
"symbol": "ACME",
"tiersConfigured": 3
},
"partnerTokens": [
{ "symbol": "USDC", "tiersConfigured": 1 }
],
"totalTokens": 2,
"maxTokens": 8
},
"meta": { "version": "1.0", "timestamp": "2026-02-27T12:00:00.000Z" }
}
Sets NFT collection discounts. Maximum 4 collections with discounts between 1% and 50%, or recognition only (no discount). A discount is a whole number: a value with a fraction, such as 10.5, returns 400.
| Parameter | Type | Description |
|---|---|---|
| nftCollections | array required | Array of {name, contractAddress, chainId, discount}. Max 4 collections; name max 50 characters. Optional benefitType: "discount" (default) or "recognition" (holders are recognized, no discount; discount is then not required). Optional enabled: a boolean; only false switches a collection off. chainId accepts a number, "solana", or "xrpl". For Solana NFTs, use the mint address as contractAddress. For XRPL NFTs, use the issuer r-address as contractAddress (the address checksum is verified) and optionally include taxon, an integer from 0 to 4294967295. A malformed address or taxon returns 400. |
curl -X PUT https://api.insumermodel.com/v1/merchants/acme-coffee/nfts \ -H "Content-Type: application/json" \ -H "x-api-key: YOUR_API_KEY" \ -d '{ "nftCollections": [{ "name": "Acme Members", "contractAddress": "0x5678...efgh", "chainId": 1, "discount": 20 }] }'
{
"ok": true,
"data": {
"nftCollections": [
{
"name": "Acme Members",
"chainId": 1,
"discount": 20
}
],
"totalCollections": 1,
"maxCollections": 4
},
"meta": { "version": "1.0", "timestamp": "2026-02-27T12:00:00.000Z" }
}
Updates merchant discount mode, cap, limits for unproven wallets, and USDC payment configuration. Send at least one parameter.
| Parameter | Type | Description |
|---|---|---|
| discountMode | string optional | "highest" (best single discount), "stack" (sum all qualifying discounts) or "capped" (sum all, then cap at discountCap). |
| discountCap | number optional | Maximum total discount percentage. A whole number from 1 to 100; a value with a fraction returns 400. |
| usdcPayment | object optional | {enabled, evmAddress, solanaAddress, preferredChainId}. To switch it on, include at least one of evmAddress or solanaAddress; send null or {"enabled": false} to switch it off. |
| maxDiscountsPerWalletPerDay | integer | null optional | The store’s limit on discount codes per UTC day for a wallet sent without a walletProof, a whole number from 1 to 100; null removes the limit. A proven wallet is not limited. |
| maxUnprovenDiscount | integer | null optional | The most a wallet sent without a walletProof can get, a whole number from 0 to 100 (0 = no discount); null gives it the same as a proven wallet. When this lowers a discount, the response carries discountIfProven. |
curl -X PUT https://api.insumermodel.com/v1/merchants/acme-coffee/settings \ -H "Content-Type: application/json" \ -H "x-api-key: YOUR_API_KEY" \ -d '{ "discountMode": "highest", "discountCap": 25, "usdcPayment": { "enabled": true, "evmAddress": "0x47aD...14E9", "preferredChainId": 8453 } }'
{
"ok": true,
"data": {
"discountMode": "highest",
"discountCap": 25,
"maxDiscountsPerWalletPerDay": null,
"maxUnprovenDiscount": null,
"usdcPayment": {
"enabled": true
}
},
"meta": { "version": "1.0", "timestamp": "2026-02-27T12:00:00.000Z" }
}
Kept for compatibility. Submit a USDC, USDT or BTC transaction hash to buy credits into the regular balance of the API key that owns the merchant. Flat $0.04 per credit (25 credits per $1) at every purchase size on this endpoint. POST /v1/credits/buy is the normal way to top up and carries the volume tiers. Funds sent on unsupported chains cannot be recovered. Non-refundable.
| Parameter | Type | Description |
|---|---|---|
| txHash | string required | Transfer transaction hash (USDC, USDT or BTC). |
| chainId | number | "solana" | "bitcoin" | "tron" required | Chain ID (e.g. 1, 8453) or "solana", "bitcoin", "tron". Supported: ETH, Base, Polygon, Arbitrum, Optimism, BNB, Avalanche (USDC or USDT), Solana (USDC or USDT), Tron (USDT-TRC20), Bitcoin (BTC). |
| amount | number required | USDC/USDT amount. Minimum 5. Not required for BTC. |
| updateWallet | boolean optional | Set to true to change the registered sender wallet. |
Sender verification: The first purchase registers the sender wallet to the API key. Subsequent purchases must come from the same sender. To change the registered wallet, include "updateWallet": true: the verified transfer proves ownership.
See platform wallet addresses and supported chains →
curl -X POST https://api.insumermodel.com/v1/merchants/acme-coffee/credits \ -H "Content-Type: application/json" \ -H "x-api-key: YOUR_API_KEY" \ -d '{ "txHash": "0xabc...def", "chainId": 8453, "amount": 10 }'
{
"ok": true,
"data": {
"creditsAdded": 250,
"totalCredits": 350,
"usdcPaid": "10",
"chainName": "Base"
},
"meta": { "version": "1.0", "timestamp": "2026-02-27T12:00:00.000Z" }
}
Publishes the merchant to the public directory, making it discoverable by wallets and agents. No request body needed.
curl -X POST https://api.insumermodel.com/v1/merchants/acme-coffee/directory \
-H "x-api-key: YOUR_API_KEY"
{
"ok": true,
"data": {
"id": "acme-coffee",
"published": true,
"tokensListed": 2,
"nftCollectionsListed": 1
},
"meta": { "version": "1.0", "timestamp": "2026-02-27T12:00:00.000Z" }
}
Returns the full private details of a merchant, including the owner key's credit balance, directory listing status, token configuration, and discount settings.
curl https://api.insumermodel.com/v1/merchants/acme-coffee/status \
-H "x-api-key: YOUR_API_KEY"
{
"ok": true,
"data": {
"id": "acme-coffee",
"companyName": "Acme Coffee",
"location": "New York, NY",
"credits": 350,
"apiAccessEnabled": true,
"createdAt": "2026-02-20T10:00:00.000Z",
"discountMode": "highest",
"discountCap": 25,
"maxDiscountsPerWalletPerDay": null,
"maxUnprovenDiscount": null,
"listedInDirectory": true,
"ownToken": {
"symbol": "ACME",
"chainId": 1,
"tiers": [/* ... */]
},
"partnerTokens": [/* ... */],
"nftCollections": [/* ... */],
"usdcPayment": { "enabled": true },
"verification": { "status": "verified", "domain": "acme.com" }
},
"meta": { "version": "1.0", "timestamp": "2026-02-27T12:00:00.000Z" }
}
See how this endpoint fits the full API → API Topology