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

# Crypto Payments

> How to accept USDC payments with hosted checkout

## Overview

Crypto payments accept **USDC** through **hosted checkout**. After creating a payment via API, redirect the customer to `payment_url`. The checkout page shows a unique deposit address (with a QR code); the customer sends USDC to it, and the payment completes automatically once the deposit is confirmed on-chain.

<Info>
  Each payment gets its own single-use deposit address. Amounts are priced in the settlement currency (e.g. USD) and paid by the customer in the equivalent amount of USDC.
</Info>

## Payment Flow

<Steps>
  <Step title="Create Payment">
    Call `POST /v1/payments` to create a payment and obtain `payment_url`
  </Step>

  <Step title="Redirect Customer">
    Redirect customer to `payment_url`
  </Step>

  <Step title="Customer Sends USDC">
    The customer sends USDC to the deposit address shown on the checkout page
  </Step>

  <Step title="On-chain Confirmation">
    The deposit is detected and confirmed on-chain (usually within a minute)
  </Step>

  <Step title="Completion">
    The payment status becomes `succeeded` and a webhook is delivered
  </Step>
</Steps>

## Implementation Example

```javascript theme={null}
// 1. Create payment via API
const response = await fetch('https://api.sandbox.zafapay.com/v1/payments', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    amount: 100,
    currency: 'usd',
    external_id: 'order_12345'
  })
});

const payment = await response.json();

// 2. Redirect customer to the hosted checkout page (deposit address + QR)
window.location.href = payment.payment_url;
```

### Routing to the crypto flow

Crypto is served through a payment flow assigned to your account. If crypto is your default flow, no extra parameter is needed. If you accept multiple payment methods, pass `flow_id` for your crypto flow to route the payment to crypto:

```json theme={null}
{
  "amount": 100,
  "currency": "usd",
  "flow_id": "flow_xxxxxxxx"
}
```

## Webhook Integration

Because the customer pays on-chain, the payment completes asynchronously. Use webhooks to confirm the result reliably:

```javascript theme={null}
// Webhook handler
app.post('/webhooks/zafapay', async (req, res) => {
  const { event, external_id } = req.body;

  if (event === 'payment.succeeded') {
    // Update order status
    await updateOrder(external_id, 'paid');
  }

  res.json({ received: true });
});
```

<Note>
  If a customer sends less than the requested amount, the payment is not completed as `succeeded`. Handling of underpayments follows your account settings — contact support if you need to reconcile a partial deposit.
</Note>

<Info>
  For complete API parameters and response details, see the [Create Payment](/api-reference/payments/create-payment) API reference.
</Info>
