Prepare redemption

POST /api/v1/mystery/redemption/prepare cards:redeem

Starts a physical redemption: stores the address, locks in the cheapest shipping rate, and returns the transactions the END USER sends from the wallet holding the card — the redemption flag plus the shipping payment (a USDC approve and a payShipping call locked to the quoted amount). The END USER pays shipping on-chain; you are never billed for it. The item ships only once that payment lands. The card isn’t burned until the item ships, so nothing leaves the wallet yet. Only the holder can send these (CardOS can’t do this one for them). Supply purchase_id OR token_id (token_id alone works for cards you distributed yourself). CardOS runs no KYC/AML, so screening your end user is your responsibility.

Try it POST /api/v1/mystery/redemption/prepare money

These inputs are shared across all docs pages, so an id entered here carries over.

request body
object · 2 keys
{
  "shipping_address": {
    "name": "Demo Buyer",
    "street1": "1 Market St",
    "city": "San Francisco",
    "state": "CA",
    "zip": "94105",
    "country": "US"
  },
  "idempotency_key": "demo-redeem-0-single"
}
response

Not run yet. Press Run to make a live call against https://service.rip.fun (through this demo's server-side proxy; the API key never reaches the browser).

tracks the inputs above
curl -X POST 'https://service.rip.fun/api/v1/mystery/redemption/prepare' \
  -H 'X-API-Key: rip_…' \
  -H 'Content-Type: application/json' \
  -d '{"shipping_address":{"name":"Demo Buyer","street1":"1 Market St","city":"San Francisco","state":"CA","zip":"94105","country":"US"},"idempotency_key":"demo-redeem-0-single"}'

Request fields

FieldTypeRequiredDescription
purchase_idnumberThe fulfilled purchase holding the item (supply this OR token_id)
token_idstringOn-chain token id (token-first; supply this OR purchase_id; also disambiguates a multi-item purchase)
item_typestring"CARD" | "GRADED_CARD" | "PACKET" | "SEALED_PRODUCT", to disambiguate a token number that exists as more than one asset (raw Card #N vs GradedCard slab #N)
idempotency_keystringReplay-safe; an Idempotency-Key header is also accepted
shipping_payerstring"end_user" is the only valid value (and the default) — the holder pays the quoted shipping on-chain; partner-billed shipping is not offered
shipping_address.namestringyesRecipient full name
shipping_address.street1stringyesStreet line 1 (`street2` optional)
shipping_address.citystringyesCity
shipping_address.statestringState / region
shipping_address.zipstringyesPostal code
shipping_address.countrystringyesISO country code, e.g. `US` (`phone`, `email` optional)

Response fields (data)

FieldDescription
redemption_id / statusPREPARED, meaning the transaction is ready to send
shipping_quoteSnapshotted cheapest rate (same shape as /quote)
shipping_payer / shipping_paymentalways "end_user" — the holder pays the quoted shipping on-chain (you are never billed). shipping_payment echoes the signed quote: payer, processor, total_usdc/micros, expiration_time, provider_order_id
expires_athow long the returned transactions (and the signed shipping quote) stay valid (default 24 h); EXPIRED is retryable with a new idempotency_key
unsigned.chain_id / unsigned.calls[]the transactions the END USER sends from the wallet holding the card, in order: kind "burn" (flags the card for redemption), "erc20-approve" (USDC → shipping processor; its own userop under account abstraction), "shipping-payment" (payShipping with the signed quote — must run after the burn). The card burns when the item ships

Errors

StatusCodeWhen
400purchase_or_token_requiredneither purchase_id nor token_id supplied
409not_fulfilledpurchase path: purchase not revealed yet
409not_burnabletoken unindexed / burned / not in a redeemable state, or already queued
409not_ownertoken left the holder wallet, and the holder must be the burn signer
404token_not_foundtoken-first: no CardOS item for that token
409ambiguous_tokentoken-first: id is both a raw and a graded card, so pass item_type ("CARD" or "GRADED_CARD") or use purchase_id
409item_type_mismatchitem_type contradicts what the token actually is
409redemption_existsre-preparing after the burn already started
400invalid_addressShippo cannot validate the address
400invalid_shipping_payershipping_payer set to anything other than "end_user"
503shipping_signer_unavailablethe shipping quote signer is temporarily unauthorized on-chain — retry later

See Errors for the response envelope and the full code list.

Flow

  1. Partner: run any KYC/AML you need on the end user. CardOS does not
  2. Partner: POST /redemption/quote at checkout to show shipping cost (optional)
  3. Partner: POST /redemption/prepare with purchase_id or token_id + the address → PREPARED + the transactions to send (burn + USDC approve + shipping payment)
  4. End user: sends those from the wallet holding the card (pays gas + the quoted shipping in USDC) and gives you the tx hash. This flags the card and pays shipping; the card itself doesn't move yet
  5. Partner: POST /redemption/submit with { redemption_id, tx_hash } → BURN_SUBMITTED
  6. CardOS: sees the shipping payment on-chain, ships the item and burns the card when it ships; poll GET /redemption/:id or use redemption.updated webhooks