Skip to main content

Overview

A redemption converts a user’s $GOLD tokens into a physical-gold denomination (e.g., 1 Tola) that ORO fulfills off-chain in a specific city. The token flow is on-chain — the user transfers tokens into GRAIL’s escrow. Fulfillment (physical pickup) is managed by ORO and progresses through a status lifecycle that the partner can observe but not drive. Redemptions differ from trades in three important ways:
  1. Only two signers — GRAIL + user. The partner does not sign.
  2. Row written at quote time — a redemption row is created at status quoted as soon as you call POST /v1/redemptions (unlike trades, which are stateless at quote time).
  3. quoted is never surfacedGET /v1/redemptions/:id returns 404 until the user’s transfer has been confirmed on-chain and the indexer advances status to submitted.

Status lifecycle

  • Indexer writes quoted → submitted (or quoted → failed if the on-chain transfer reverts)
  • ORO admin drives submitted → preparing → ready → collected
  • Partner can request cancel only while status is submitted — once ORO advances to preparing, physical prep has begun and cancellation is a coordination question, not an automated one

Step 1 — Look up available denominations

Response:
Pick the id for Step 2 and note the city — you must pass the same city in the quote body (case-insensitive).

Step 2 — Quote a redemption

Response:
tokens_required is the amount of $GOLD tokens (per troy ounce, 6 decimals) the user must transfer. In the example above: 0.375006 tokens for 1 Tola. This is not the same as total_usd (1827.34) — that’s the USD value of those tokens. Mixing them up is the most common redemption mistake.

Step 3 — Co-sign with the user wallet ONLY

Unlike trades, the partner does not sign. Only the user needs to add their signature.

Step 4 — Submit

Response:
Same passthrough semantics as trade submit — no DB write. The indexer writes the status transition after on-chain confirmation.

Step 5 — Wait, then fetch

Once the indexer has advanced the row:
While the redemption is still at quoted, this endpoint returns 404 redemption_not_found — treat that as “indexer hasn’t confirmed yet”, not as an error.

Tracking fulfillment

The partner cannot drive lifecycle transitions from submitted onward. ORO does that in the admin interface. As a partner, poll GET /v1/redemptions/:id (or use List Redemptions with a status filter) to see when the row advances. Typical transitions:
  • submittedpreparing when ORO begins physical handling
  • preparingready when gold is at the pickup location
  • readycollected after the user collects

Cancelling

Only valid at submitted:
Response:
If the redemption has moved past submitted, you get 400 cancellation_not_allowed. From cancellation_requested, ORO advances to cancelled (final) after confirming no physical prep has started.
The user’s $GOLD has already been transferred to escrow at submitted. Cancellation flags the record — it does NOT automatically return the tokens to the user. Any refund is a coordination question with ORO, not an automated flow.

Listing

Optional filters: grail_user_id, status, city. quoted is always excluded.

Common errors

End-to-end script