/api/v1/mystery/purchase packs:purchase The custodial alternative to prepare/submit: the pack is paid from the end-user's CardOS wallet balance (see Custodial wallet), so there is no transaction for anyone to sign and no chain awareness in your stack at all. Returns 202 — the purchase is reserved and revealed asynchronously; poll GET /purchase/:id or take the purchase.fulfilled webhook. Which model your key uses is your architectural fork in the road: custodial needs funded wallets but no signing UX, prepare/submit needs neither balance nor deposit flow but every purchase is signed by the end-user. GET /api/v1/info tells you how your key is provisioned.
Exactly ONE pack per call: quantity is fixed at 1 and anything else is rejected with unsupported_quantity. A multi-pull is N sequential calls, each with its OWN Idempotency-Key.
An Idempotency-Key is bound to its first (user, tier) pair — reusing a key with a different tier_id is a 409 idempotency_mismatch, so mint keys per (user, tier, intent), e.g. a UUID minted when the user taps buy.
POST /api/v1/mystery/purchase money These inputs are shared across all docs pages, so an id entered here carries over.
{
"external_user_id": "demo-explorer",
"tier_id": 1
}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).
curl -X POST 'https://service.rip.fun/api/v1/mystery/purchase' \
-H 'X-API-Key: rip_…' \
-H 'Idempotency-Key: de1424ca-1fa7-4b8a-95c2-32c7403eb532' \
-H 'Content-Type: application/json' \
-d '{"external_user_id":"demo-explorer","tier_id":1}' | Field | Type | Required | Description |
|---|---|---|---|
Idempotency-Key | header | yes | Your unique id for this purchase intent — replays return the original 202 instead of double-charging |
external_user_id / wallet_address | string | yes | Whose wallet balance pays (one of the two) |
tier_id | number | yes | Tier to purchase |
max_price_usdc | string | — | Price cap; defaults to the current tier price |
data)| Field | Description |
|---|---|
id / memo / status / custody | Purchase id, "{partner-slug}-{id}" tag, RESERVED→SUBMITTED→FULFILLED, and custody — uppercase, "CUSTODIAL" here (the prepare/submit path records "NON_CUSTODIAL"). memo is absent entirely when your key has no slug |
price / price_usdc | What was reserved from the wallet (micros + decimal) |
onchain_request_id / transaction_hash / purchaser_address | On-chain linkage, filled in as the reveal progresses |
reserved_at / submitted_at / fulfilled_at / created_at | Lifecycle timestamps |
| Status | Code | When |
|---|---|---|
| 400 | missing_idempotency_key | no Idempotency-Key header (or idempotency_key body field) |
| 400 | invalid_tier | tier_id missing or unknown |
| 400 | unsupported_quantity | quantity other than 1 — send N calls for N packs |
| 409 | idempotency_mismatch | the Idempotency-Key was already used for a different tier |
| 402 | insufficient_funds | the end-user's wallet balance cannot cover the tier price |
| 503 | relayer_disabled | custodial purchasing is temporarily paused |
See Errors for the response envelope and the full code list.