OpenAI's Agentic Commerce Protocol (ACP) defines how AI agents request and apply discounts during checkout. This guide walks through integrating the InsumerAPI ACP discount endpoint, from your first API call to parsing coupon objects and validating codes at checkout.
What You Need
- An InsumerAPI key (free tier includes 10 credits). Get one here.
- A merchant ID. Browse available merchants with
GET /v1/merchantsor create your own. - A wallet address to verify. The endpoint verifies on-chain token holdings without exposing actual amounts.
Step 1: Call the ACP Endpoint
The endpoint is POST /v1/acp/discount. Send a wallet address and merchant ID. InsumerAPI acts as an attestation authority: it verifies token holdings on-chain and returns a signed discount in ACP format.
curl:
curl -X POST \
https://api.insumermodel.com/v1/acp/discount \
-H "X-API-Key: insr_live_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{
"merchantId": "demo-coffee-shop",
"wallet": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
}'
Python:
import requests
BASE = "https://api.insumermodel.com"
KEY = "insr_live_YOUR_KEY_HERE"
resp = requests.post(
f"{BASE}/v1/acp/discount",
headers={"X-API-Key": KEY, "Content-Type": "application/json"},
json={
"merchantId": "demo-coffee-shop",
"wallet": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
},
)
data = resp.json()
print(data)
Node.js:
const BASE = "https://api.insumermodel.com";
const KEY = "insr_live_YOUR_KEY_HERE";
const resp = await fetch(`${BASE}/v1/acp/discount`, {
method: "POST",
headers: { "X-API-Key": KEY, "Content-Type": "application/json" },
body: JSON.stringify({
merchantId: "demo-coffee-shop",
wallet: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
}),
});
const data = await resp.json();
console.log(data);
Step 2: Parse the ACP Response
A successful response returns the discount wrapped in ACP coupon objects. Here is the full shape:
{
"ok": true,
"data": {
"protocol": "acp",
"version": "2026-01-30",
"discounts": {
"codes": ["INSR-A7K3M"],
"applied": [
{
"id": "INSR-A7K3M",
"code": "INSR-A7K3M",
"coupon": {
"id": "insumer-insr-a7k3m",
"name": "Token Holder Discount (15% off)",
"percent_off": 15
},
"automatic": false,
"method": "across",
"priority": 10,
"start": "2026-02-27T12:00:00.000Z",
"end": "2026-02-27T12:30:00.000Z"
}
],
"rejected": []
},
"verification": {
"code": "INSR-A7K3M",
"expiresAt": "2026-02-27T12:30:00.000Z",
"breakdown": [
{ "symbol": "USDC", "tier": "Holder", "discount": 10 },
{ "symbol": "UNI", "tier": "Holder", "discount": 5 }
],
"sig": "MEYCIQDx...base64...",
"kid": "insumer-attest-v1"
}
},
"meta": {
"creditsCharged": 1,
"creditsRemaining": 94
}
}
Key fields to extract:
discounts.applied[0].coupon.percent_offis the discount percentage your agent should apply.discounts.codes[0]is theINSR-XXXXXcode to present at checkout.discounts.applied[0].endis the code expiry (30 minutes from creation).verification.sigis the ECDSA P-256 signature proving authenticity.verification.breakdownshows which tokens matched and which tier each triggered.
If the wallet does not qualify for any discount, applied is empty and rejected contains the reason:
"discounts": {
"codes": [],
"applied": [],
"rejected": [
{ "code": "INSUMER_CHECK", "reason": "user_ineligible" }
]
}
Step 3: Parse Coupon Objects in Your Agent
Here is how an agent extracts and applies the discount in Python:
result = resp.json()
if not result["ok"]:
print(f"Error: {result['error']['message']}")
else:
discounts = result["data"]["discounts"]
if discounts["applied"]:
coupon = discounts["applied"][0]["coupon"]
code = discounts["codes"][0]
expiry = discounts["applied"][0]["end"]
print(f"Discount: {coupon['percent_off']}% off")
print(f"Code: {code}")
print(f"Valid until: {expiry}")
print(f"Coupon name: {coupon['name']}")
# Apply to cart
cart_total = 5000 # $50.00 in cents
discount_amount = cart_total * coupon["percent_off"] // 100
final_total = cart_total - discount_amount
print(f"Cart: ${cart_total/100:.2f} -> ${final_total/100:.2f}")
else:
reason = discounts["rejected"][0]["reason"]
print(f"Not eligible: {reason}")
Step 4: Per-Item Allocations (Optional)
If your agent manages a multi-item cart, pass the items array. The endpoint calculates per-item discount allocations automatically:
resp = requests.post(
f"{BASE}/v1/acp/discount",
headers={"X-API-Key": KEY, "Content-Type": "application/json"},
json={
"merchantId": "demo-coffee-shop",
"wallet": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
"items": [
{"path": "cart/espresso", "amount": 450},
{"path": "cart/croissant", "amount": 350},
],
},
)
The response adds amount and allocations to the applied discount:
"applied": [{
"id": "INSR-A7K3M",
"code": "INSR-A7K3M",
"coupon": {
"id": "insumer-insr-a7k3m",
"name": "Token Holder Discount (15% off)",
"percent_off": 15
},
"amount": 120,
"allocations": [
{"path": "cart/espresso", "amount": 68},
{"path": "cart/croissant", "amount": 52}
],
"automatic": false,
"method": "across",
"priority": 10,
"start": "2026-02-27T12:00:00.000Z",
"end": "2026-02-27T12:30:00.000Z"
}]
The amount field is the total discount in the same unit as item amounts. The allocations array distributes it proportionally across items.
Step 5: Validate the Code at Checkout
When the customer presents the code, your merchant backend validates it with a simple GET request. No API key required:
GET /v1/codes/INSR-A7K3M
Valid code response:
{
"ok": true,
"data": {
"valid": true,
"code": "INSR-A7K3M",
"merchantId": "demo-coffee-shop",
"discountPercent": 15,
"expiresAt": "2026-02-27T12:30:00.000Z",
"createdAt": "2026-02-27T12:00:00.000Z"
}
}
Expired code response:
{
"ok": true,
"data": {
"valid": false,
"code": "INSR-A7K3M",
"reason": "expired"
}
}
The three possible rejection reasons are expired, already_used, and not_found.
Step 6: Verify the Signature (Optional)
For high-value transactions, verify the ECDSA signature to confirm the discount was issued by InsumerAPI and not tampered with. The insumer-verify package handles this:
npm install insumer-verify
import { verifyAttestation } from "insumer-verify";
// Pass the full API response envelope, not apiResponse.data
const result = await verifyAttestation(apiResponse, {
jwksUrl: "https://insumermodel.com/.well-known/jwks.json",
});
console.log(result.valid); // true if sig checks out
console.log(result.checks); // { signature, conditionHash, expiry, freshness }
The public signing key is also available at GET /v1/jwks (RFC 7517 format, 24-hour cache).
Error Handling
All errors follow the same envelope:
{
"ok": false,
"error": { "code": 400, "message": "Invalid EVM wallet address" },
"meta": { "version": "1.0", "timestamp": "..." }
}
Common error codes:
- 400 : Invalid wallet format, missing merchantId
- 401 : Missing or invalid API key
- 402 : Merchant has no credits remaining
- 404 : Merchant not found
- 429 : Daily rate limit exceeded (check
X-RateLimit-Remainingheader)
Full Working Example
Here is the complete flow in one Python script:
import requests
BASE = "https://api.insumermodel.com"
KEY = "insr_live_YOUR_KEY_HERE"
# 1. Check discount eligibility via ACP
acp = requests.post(
f"{BASE}/v1/acp/discount",
headers={"X-API-Key": KEY, "Content-Type": "application/json"},
json={
"merchantId": "demo-coffee-shop",
"wallet": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
"items": [
{"path": "cart/latte", "amount": 550},
{"path": "cart/muffin", "amount": 400},
],
},
).json()
if acp["ok"] and acp["data"]["discounts"]["applied"]:
code = acp["data"]["discounts"]["codes"][0]
pct = acp["data"]["discounts"]["applied"][0]["coupon"]["percent_off"]
print(f"Eligible: {pct}% off, code {code}")
# 2. At checkout, validate the code (no key needed)
check = requests.get(f"{BASE}/v1/codes/{code}").json()
if check["data"]["valid"]:
print(f"Code valid. Apply {check['data']['discountPercent']}% off.")
else:
print(f"Code invalid: {check['data']['reason']}")
else:
print("Wallet does not qualify for a discount.")
A forkable reference repository with all examples is available at acp-ucp-onchain-eligibility-example on GitHub. For the merchant setup side, see how to get token-gated discounts running in 8 minutes. For how on-chain verification powers broader eligibility credentials, see our analysis of the discount verification landscape.
Get your free API key
InsumerAPI includes 10 free verification credits. Start building with ACP today.
Get API Key