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

# Start a card purchase

> POST /card/purchase - begin a card payment, or find out identity checks are still pending.

Starts a card payment for a buyer who has already been quoted. Returns either a
purchase to redirect into, or a signal that identity verification is not finished
yet - handle **both** shapes.

<Note>
  Identity verification happens in the on-ramp's own flow, not ours. Get an access
  token from [`/card/kyc-token`](/api-reference/card-kyc-token) and mount their
  widget; we never see the buyer's documents.
</Note>

## Request

<ParamField body="email" type="string" required>
  The buyer's email. This is the key the on-ramp uses to identify them across the
  purchase and its verification.
</ParamField>

<ParamField body="address" type="string" required>
  The EVM address the crypto is delivered to. In the non-custodial flow this is the
  buyer's own wallet.
</ParamField>

<ParamField body="fiatCurrency" type="string" required>
  ISO 4217 code of the currency being charged (e.g. `"EUR"`).
</ParamField>

<ParamField body="fiatAmount" type="string" required>
  Total to charge, as a decimal string, matching what was quoted.
</ParamField>

<ParamField body="billingAddress" type="object" required>
  Card billing address. Required by the on-ramp before a purchase can proceed.

  <Expandable title="billingAddress">
    <ParamField body="countryCode" type="string" required>
      ISO 3166-1 alpha-2 country code.
    </ParamField>

    <ParamField body="streetLine1" type="string" required />

    <ParamField body="streetLine2" type="string" />

    <ParamField body="city" type="string" required />

    <ParamField body="zipCode" type="string" required />

    <ParamField body="stateCode" type="string" />
  </Expandable>
</ParamField>

<ParamField body="birthday" type="string" required>
  Buyer's date of birth, as required by the on-ramp's compliance checks.
</ParamField>

## Response

Two shapes. Branch on `status`.

### Verification still pending

<ResponseField name="status" type="string">
  `"pending"` - the buyer must finish identity verification before a purchase can
  start.
</ResponseField>

<ResponseField name="kycStatus" type="string">
  `incomplete`, `pending` (submitted, under review) or `unknown`. Keep polling on
  `pending`; it is not terminal.
</ResponseField>

### Ready to pay

<ResponseField name="transactionId" type="string">
  Your reference for this purchase. Pass it to
  [`/card/status`](/api-reference/card-status).
</ResponseField>

<ResponseField name="redirectUrl" type="string">
  The hosted card page. Send the buyer here to enter card details, Apple Pay, and
  pass 3DS. Payment never touches your page or ours.
</ResponseField>

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST "$RHEON_API/card/purchase" \
    -H "Content-Type: application/json" \
    -d '{
      "email": "buyer@example.com",
      "address": "0x2222222222222222222222222222222222222222",
      "fiatCurrency": "EUR",
      "fiatAmount": "100.00",
      "billingAddress": {
        "countryCode": "PL",
        "streetLine1": "Main Street 1",
        "city": "Warsaw",
        "zipCode": "00-001"
      },
      "birthday": "1990-01-01"
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 200 ready theme={null}
  {
    "transactionId": "1022fe1d470484769",
    "redirectUrl": "https://exchange.mercuryo.io/?widget_id=..."
  }
  ```

  ```json 200 pending theme={null}
  {
    "status": "pending",
    "kycStatus": "pending"
  }
  ```
</ResponseExample>

## Errors

| HTTP | `code`            | When                                                                      |
| ---- | ----------------- | ------------------------------------------------------------------------- |
| 400  | `invalid_request` | Missing or malformed email, address, amount, billing address or birthday. |
| 429  | `rate_limited`    | Over the rate limit (5 requests / 10s / IP).                              |
| 502  | `upstream_error`  | The on-ramp is unavailable.                                               |
| 500  | `internal`        | Unexpected server error.                                                  |
