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

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:

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:

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