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

# How to Accept Crypto Payments Using the Blockra API

> Learn how to create a payment, display a deposit address to your customer, and track the payment status through to completion using the Blockra API.

This guide walks you through the full flow for accepting a crypto payment using the Blockra API: creating a charge, presenting the deposit details to your customer, and handling the result via a webhook or polling.

## Prerequisites

* A Blockra account ([app.blockra.io](https://app.blockra.io))
* An API key with the `payments:write` and `payments:read` scopes — see [Authentication](/authentication)

## Step-by-step

<Steps>
  <Step title="Create a payment">
    Call `POST /payments` with the fiat amount, the currency, and the crypto asset the customer will pay in. Blockra locks the live exchange rate and returns a deposit address.

    <CodeGroup>
      ```bash cURL theme={null}
      curl https://api.blockra.io/payments \
        -X POST \
        -H "X-API-Key: bk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
        -H "Content-Type: application/json" \
        -d '{
          "asset": "LTC",
          "fiat_amount": 9.99,
          "fiat_currency": "USD",
          "reference": "order_1234"
        }'
      ```

      ```ts Node.js theme={null}
      const res = await fetch("https://api.blockra.io/payments", {
        method: "POST",
        headers: {
          "X-API-Key": process.env.BLOCKRA_API_KEY!,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          asset: "LTC",
          fiat_amount: 9.99,
          fiat_currency: "USD",
          reference: "order_1234",
        }),
      });
      const { data, error } = await res.json();
      ```

      ```python Python theme={null}
      import requests, os

      res = requests.post(
          "https://api.blockra.io/payments",
          headers={"X-API-Key": os.environ["BLOCKRA_API_KEY"]},
          json={
              "asset": "LTC",
              "fiat_amount": 9.99,
              "fiat_currency": "USD",
              "reference": "order_1234",
          },
      )
      data = res.json()["data"]
      ```
    </CodeGroup>

    Blockra returns a payment object. The key fields are in `deposit`:

    ```json Response theme={null}
    {
      "data": {
        "id": "pay_a1b2c3d4e5f6g7h8i9j0k1l2",
        "status": "pending",
        "expires_at": "2026-07-08T13:09:00.000Z",
        "deposit": {
          "address": "ltc1q0u0dnysyzuyua7tg2fu05ztgssazx0j5fqfhun",
          "asset": "LTC",
          "expected_amount": "0.1183",
          "expected_amount_atoms": "11830000",
          "qr_data": "litecoin:ltc1q0u0dnysyzuyua7tg2fu05ztgssazx0j5fqfhun?amount=0.1183",
          "required_confirmations": 4,
          "expires_at": "2026-07-08T13:09:00.000Z"
        }
      },
      "error": null
    }
    ```
  </Step>

  <Step title="Show deposit details to the customer">
    Present `deposit.address` and `deposit.expected_amount` clearly. Use `deposit.qr_data` to render a QR code for mobile wallets.

    <Warning>
      The customer must send **exactly** `expected_amount` (the value in `deposit.expected_amount_atoms` for precision). Sending a different amount results in an `underpaid` or `overpaid` status.
    </Warning>

    The deposit quote is valid for **30 minutes** (see `expires_at`). If the timer elapses with no payment, the status moves to `expired` and a new payment must be created.
  </Step>

  <Step title="Detect confirmation via webhook">
    Register a webhook endpoint in **Developers → Webhooks** to receive real-time status updates. Listen for `payment.completed` to confirm the payment:

    ```json payment.completed event theme={null}
    {
      "type": "payment.completed",
      "created": "2026-07-08T12:52:00.000Z",
      "data": {
        "id": "pay_a1b2c3d4e5f6g7h8i9j0k1l2",
        "status": "completed",
        "net_fiat": 9.77,
        "reference": "order_1234"
      }
    }
    ```

    Use the `reference` field to match the event back to your order. See [Webhooks](/webhooks) for signature verification.
  </Step>

  <Step title="Poll the payment status (alternative)">
    If webhooks are not available, poll `GET /payments/{id}` until `status` is `completed`, `expired`, or `failed`:

    ```ts Node.js theme={null}
    async function waitForPayment(id: string) {
      while (true) {
        const res = await fetch(`https://api.blockra.io/payments/${id}`, {
          headers: { "X-API-Key": process.env.BLOCKRA_API_KEY! },
        });
        const { data } = await res.json();
        if (["completed", "expired", "failed", "cancelled"].includes(data.status)) {
          return data;
        }
        await new Promise((r) => setTimeout(r, 5000)); // poll every 5s
      }
    }
    ```

    <Tip>
      Prefer webhooks over polling — they are faster and use fewer API requests.
    </Tip>
  </Step>
</Steps>

## Handling edge cases

<Accordion title="What happens if a payment expires?">
  If the buyer does not send funds within the 30-minute quote window, the payment status changes to `expired` and you receive a `payment.expired` webhook. Create a new payment if the buyer still wants to complete the purchase — the exchange rate will be re-locked.
</Accordion>

<Accordion title="What if the buyer sends too little or too much?">
  Blockra marks the payment `underpaid` or `overpaid` respectively. Check your dashboard or webhook payload for details. You can contact Blockra support for resolution of over/underpayments.
</Accordion>

<Accordion title="How do I associate a payment with a customer?">
  Pass `customer_email` in the create-payment request. Blockra will create a customer record (or match an existing one) and link the payment to it. You can retrieve the associated customer from `GET /payments/{id}` in the `customers` field.
</Accordion>
