---
title: "Create signed discount code"
method: POST
path: "/v1/verify"
tags: ["Discounts & Codes"]
---

# Create signed discount code

`POST /v1/verify`

## Request

- Base URL: `https://api.insumermodel.com`
- URL: `https://api.insumermodel.com/v1/verify`
- Auth: API key in header `X-API-Key`

Creates a signed discount verification code (INSR-XXXXX) valid for 30 minutes. A code that carries a discount costs 1 regular credit from the API key that owns the store (the key that created it); a 0% result is free. A caller using another key is not charged; when the caller is the owner key, the caller's key pays. Stores run through a licensed platform such as Skye Meta are covered by that platform's license. If merchant has Stripe Connect, a coupon is auto-created. The order is fixed: the result is signed first, then the credit is taken and the code is stored together, and a coupon is created only after the code exists. A result that cannot be signed, or a code that cannot be stored, is a 503 in the standard error envelope with no credit used and no code created. A retry after a timeout on the caller's side is a new verification: if the first request completed, it used a credit and created a code, and the retry does both again. A coupon that cannot be created leaves a valid code with stripeCodeCreated false.

## Request body

- object: At least one of `wallet` (EVM), `solanaWallet` or `xrplWallet` is required; a request with none is a 400.
  - `merchantId` string, required
  - `wallet` string: EVM wallet address
  - `solanaWallet` string: Solana wallet address
  - `xrplWallet` string: XRPL wallet address (classic r-address). The base58 checksum is verified; an address that fails it returns 400.
  - `walletProof` WalletProof: Optional proof that the caller controls the EVM wallet named in `wallet`: an EIP-4361 (Sign-In with Ethereum) message signed by that wallet (EIP-191; smart-contract wallets are not accepted yet). The message must use domain `api.insumermodel.com` or the merchant's own website (a wallet asked to sign in the store's page expects the page's own site), the wallet as its address, URI `https://api.insumermodel.com/v1/merchants/{merchantId}`, an Issued At within the last 5 minutes, and a nonce not used before. A proven wallet gets the full discount its holdings earn (under the store's tiers and cap), without the daily limit for unproven wallets. A proof object without a string `message` and `signature` is a 400; a proof that does not verify is a 401, never a quiet fallback to the unproven terms. Neither uses a credit. Send it with `wallet` only: a request with a proof and `solanaWallet` or `xrplWallet` is a 400.
    - `message` string, required: The EIP-4361 message, exactly as signed.
    - `signature` string, required: The wallet's signature over the message (0x hex).

## Response `200`

Verification code created

- object
  - `ok` true
  - `data` object
    - `verified` boolean
    - `totalDiscount` integer
    - `code` string: Format: INSR-XXXXX
    - `expiresAt` string, date-time
    - `breakdown` DiscountBreakdown[]
      - `symbol` string
      - `tier` string
      - `discount` integer
      - `chain` string: Chain name (present only in GET /v1/discount/check responses, omitted in /v1/verify, /v1/acp/discount, /v1/ucp/discount). A token configured with alsoOn and held on more than one of its networks lists them, comma-separated ("Ethereum, Arbitrum").
    - `stripeCodeCreated` boolean
    - `cloverDiscountName` string, nullable
    - `merchantName` string
    - `sig` string: ECDSA P-256 signature
    - `walletProven` boolean: True when the request carried a valid walletProof. Not part of the signed result.
    - `discountIfProven` integer: Present only when the store limits unproven wallets and this wallet would get more with a walletProof: the discount it would get.
    - `usdcPayment` object, nullable: Present when merchant has USDC payments enabled
      - `evmAddress` string
      - `preferredChainId` integer
      - `preferredChainName` string
      - `usdcContract` string
      - `solanaAddress` string, nullable
      - `supportedChains` object[]
        - `chainId` integer
        - `name` string
        - `usdcContract` string
  - `meta` Meta
    - `version` string
    - `timestamp` string, date-time

## Other responses

- `400`: Validation error
- `401`: Invalid or missing API key, or a walletProof that fails (wrong wallet, store, domain, expired, or nonce already used). No credit is used.
- `402`: The API key that owns this store has no credits remaining. Its owner can buy more via POST /v1/credits/buy. Returned only when the result carries a discount. No credit is used and no code is created.
- `403`: Merchant has not enabled API access, or the store has no active owner API key ("This store has no active owner API key, so it cannot issue codes or record scans and taps.")
- `404`: Merchant not found
- `409`: The store's recognition is paused by its owner: "This store's recognition is paused." No credit is used and no code is created.
- `429`: Too many requests. Either the key's daily limit (the response carries Retry-After and the X-RateLimit headers), or this wallet, sent without a walletProof, has reached the store's own limit on discount codes per day (maxDiscountsPerWalletPerDay in merchant settings; no credit used, no code created; resets at 00:00 UTC). The limit does not apply to a proven wallet. Paid discount codes requested with a key other than the store's owner are subject to an hourly limit (429; the message says when to try again): "The hourly limit on discount codes has been reached. Try again in N minutes." No credit is used and no code is created.
- `500`: Unexpected server error. Safe to retry; no credits are charged on a 500. Router endpoints return the standard error envelope; standalone endpoints (the ones whose 200 is a flat object) return a flat {"error": "..."} object.
- `503`: Data source unavailable after retries. No discount code signed, no credits charged. Retryable after a short delay. A verification that could not be signed or stored is also a 503, in the standard error envelope ("The verification could not be completed. No credit was used."): no credit used, no code created, equally retryable.

---

[API](https://skmtc.dev/insumermodel/apis/insumerapi.md) · [All operations](https://skmtc.dev/insumermodel/apis/insumerapi/llms.txt) · [OpenAPI document](https://skmtc.dev/insumermodel/apis/insumerapi/revisions/91f56fe9e3d8?raw)
