> ## Documentation Index
> Fetch the complete documentation index at: https://docs.grail.oro.finance/llms.txt
> Use this file to discover all available pages before exploring further.

# Quote Redemption

> Quotes a physical-gold redemption. Returns a partially-signed transaction for the user to co-sign.

## Overview

Quotes a redemption of `$GOLD` tokens for a physical-gold denomination and returns the transaction the user must sign to transfer the tokens into GRAIL's escrow.

Unlike trades, a redemption **does** write a row at quote time — with status `quoted` (internal-only, not returned via [Get Redemption](/api-reference/redemptions/get-redemption) until the indexer advances it to `submitted` after the user's transaction confirms on-chain).

Only the **user wallet** needs to co-sign — there is no partner signature on redemptions. The transaction transfers `tokens_required` `$GOLD` from the user's wallet to GRAIL's escrow.

<Warning>
  The partial-signed transaction expires in **\~60 seconds** (Solana `recentBlockhash` TTL). Re-quote if you miss the window.
</Warning>

## Headers

<ParamField header="x-api-key" type="string" required>
  A valid `PARTNER` scope key.
</ParamField>

## Request Body

<ParamField body="grail_user_id" type="string" required>
  GRAIL user ID (prefixed `gu_`). User must belong to the authenticated partner, be `active`, and have `kyc_level: "full"`.
</ParamField>

<ParamField body="denomination_id" type="string" required>
  Denomination ID from [List Denominations](/api-reference/denominations/list-denominations), e.g., `"pk_tola_1"`.
</ParamField>

<ParamField body="city" type="string" required>
  City of pickup. Must match the denomination's registered `city` (case-insensitive).
</ParamField>

## Response

<ResponseField name="redemption_id" type="string">
  Redemption identifier, prefixed `red_`. Use with [Submit Redemption](/api-reference/redemptions/submit-redemption), [Get Redemption](/api-reference/redemptions/get-redemption), and [Cancel Redemption](/api-reference/redemptions/cancel-redemption).
</ResponseField>

<ResponseField name="quote" type="object">
  <Expandable title="properties">
    <ResponseField name="denomination" type="string">
      Denomination label, e.g., `"1 Tola"`.
    </ResponseField>

    <ResponseField name="weight_g" type="number">
      Weight of the denomination in grams.
    </ResponseField>

    <ResponseField name="spot_price_usd" type="number">
      Gold spot price in USD per troy ounce at quote time.
    </ResponseField>

    <ResponseField name="gold_value_usd" type="number">
      USD value of the gold at spot.
    </ResponseField>

    <ResponseField name="fee_usd" type="number">
      Partner redemption fee in USD (partner's `fee_percentage` × `gold_value_usd`).
    </ResponseField>

    <ResponseField name="total_usd" type="number">
      `gold_value_usd + fee_usd`. The USD value of `tokens_required`.
    </ResponseField>

    <ResponseField name="tokens_required" type="string">
      `$GOLD` tokens the user must transfer, formatted to 6 decimal places. **This is a token amount, not USD** — do not confuse with `total_usd`.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="partially_signed_transaction" type="string">
  Base64-encoded Solana transaction, signed by GRAIL. Co-sign with the **user wallet only** (no partner signature on redemptions).
</ResponseField>

## Errors

| HTTP | `error`                  | When                                                    |
| ---- | ------------------------ | ------------------------------------------------------- |
| 400  | `invalid_request`        | Missing `grail_user_id`, `denomination_id`, or `city`   |
| 400  | `invalid_denomination`   | `denomination_id` not found or inactive                 |
| 400  | `invalid_city`           | `city` doesn't match the denomination's registered city |
| 400  | `kyc_level_insufficient` | User's KYC level is not `full`                          |
| 403  | `partner_mismatch`       | User belongs to a different partner                     |
| 403  | `user_suspended`         | User status is `suspended`                              |
| 404  | `user_not_found`         | No user with the given `grail_user_id`                  |
| 503  | `pricing_unavailable`    | Gold price oracle unreachable or returned stale data    |

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST https://grail-stack-dev.onrender.com/v1/redemptions \
    -H "x-api-key: grail_partner_<hex>" \
    -H "Content-Type: application/json" \
    -d '{
      "grail_user_id": "gu_6b60956e-a8ee-4de2-8128-04c7fdf633c3",
      "denomination_id": "pk_tola_1",
      "city": "karachi"
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 201 Created theme={null}
  {
    "redemption_id": "red_a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
    "quote": {
      "denomination": "1 Tola",
      "weight_g": 11.664,
      "spot_price_usd": 4872.84,
      "gold_value_usd": 1827.34,
      "fee_usd": 0,
      "total_usd": 1827.34,
      "tokens_required": "0.375006"
    },
    "partially_signed_transaction": "AQAAAAABAAEC...<base64>..."
  }
  ```
</ResponseExample>
