# Stablecoin checkout

A stablecoin checkout with a Triple-A hosted payment page runs from payment creation to a verified webhook that confirms the order. This tutorial builds that flow, and it has these steps.

1. Your backend creates a payment.
2. Your customer is redirected to the Triple-A hosted page, picks a coin and network, and pays.
3. Triple-A sends a signed webhook to your server.
4. Your server verifies the webhook and fulfils the order when the status is `good`.

## Before you start

You need the following.

- [Sandbox credentials](/docs/getting-started/get-your-api-credentials/)
- An [access token](/docs/getting-started/authentication/)
- A testnet wallet with testBTC. See [Sandbox and test mode](/docs/stablecoin-payments/sandbox-and-test-mode/).
- A publicly reachable URL for your webhook endpoint. HTTPS isn't confirmed as a requirement, but it is good practice.

For a quick test, [webhook.site](https://webhook.site) gives you a URL that shows incoming webhooks. To test your own server locally, use a tunnel such as ngrok.

## Choose a coin and network

You don't send a coin or network when you create a payment, because the request has no field for it. Your customer picks a digital currency on the hosted payment page. You set your price in `order_currency`, and Triple-A converts it to the amount in the coin the customer chooses.

You do need to know the codes, because `crypto_currency` in the webhook and in the payment details tells you what was paid. For the full list, see [Coins and networks](/docs/reference/coins-and-networks/).

## Create the payment

Call [Make a payment request](/api/stablecoin-payments/payments/post-payment/) with your webhook settings and redirect URLs. The following request creates a test payment. The highlighted lines are the ones this tutorial depends on. `order_currency` and `order_amount` set the price, and `order_id`, `notify_url`, and `notify_secret` connect the webhook to your order.

```bash title="Request" {8-12}
curl --request POST \
  --url https://api.triple-a.io/api/v2/payment \
  --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
    "type": "triplea",
    "merchant_key": "YOUR_MERCHANT_KEY",
    "order_currency": "USD",
    "order_amount": 10,
    "order_id": "ORDER-1001",
    "notify_url": "https://your-server.example.com/webhook",
    "notify_secret": "a-long-random-secret",
    "success_url": "https://your-shop.example.com/success",
    "cancel_url": "https://your-shop.example.com/cancel",
    "sandbox": true
  }'
```

These fields control the webhook and let you match it to your order.

- `notify_url` is where Triple-A sends the webhook. You can set it per request. If you omit it, Triple-A uses the webhook URL from your account setup. `notify_email` works the same way and falls back to your account email.
- `notify_secret` signs the webhook, up to 64 characters. If you omit it, Triple-A generates one and returns it as `notify_secret` in the response, valid for that payment only. Store it.
- `order_id` is your own reference. Keep it so you can match the webhook to your order.

Save the `payment_reference` and `hosted_url` from the response. For the response fields, see [Your first payment](/docs/stablecoin-payments/your-first-payment/#read-the-response).

## Send the customer to the hosted page

Redirect the customer's browser to `hosted_url`. They choose a coin and network and pay from their wallet. Triple-A then redirects them to your `success_url` or `cancel_url`.

<Callout type="warning" title="The redirect is not proof of payment">
  The `success_url` redirect is a front-end event that fires when a payment is detected. Treat it as `hold`, not as confirmed, and wait for the webhook before you fulfil.
</Callout>

Triple-A uses `cancel_url` when the form expires without a payment, or when the customer paid too little.

In the sandbox, pay by sending testBTC to the `crypto_address` shown on the page. See [Sandbox and test mode](/docs/stablecoin-payments/sandbox-and-test-mode/).

## Receive the webhook

Triple-A sends a webhook to your `notify_url` each time the payment status changes. Your endpoint must verify the signature and respond with a 2xx status. Follow these steps in your handler.

1. Verify the `Triplea-Signature` header against the raw request body. See [Verify the signature](/docs/reference/webhooks/#verify-the-signature).
2. Read `payment_reference`, `status`, and `order_id` from the body. See [Fields](/docs/reference/webhooks/#fields).
3. Respond with a 2xx status.

If you don't respond with a 2xx status, Triple-A retries up to five times. See [Retries](/docs/reference/webhooks/#retries).

## Check payment status

Webhooks are the recommended way to learn about status changes. You can also ask Triple-A directly, for example when a webhook never arrives.

Call [Payment details](/api/stablecoin-payments/payments/get-payment-payment-reference/) to read one payment.

Call [Get list of payments](/api/stablecoin-payments/payments/get-payments/) to list payments for your merchant account. The list is sorted newest first and returns 10 payments per page by default. The table below describes its query parameters.

| Parameter | Description |
|---|---|
| `status` | Filters by payment status. |
| `start_date`, `end_date` | Filter by date, in `YYYY-MM-DD` format. |
| `sort` | `asc` or `desc`. The default is `desc`. |
| `page_size` | The number of records per page. The default is 10 and the maximum is 100. |
| `offset` | Where to start. For example, `offset=0&page_size=10` returns records 1 to 10. |

## Fulfil the order

Act on the payment `status`, and deliver only when it is `good`. For what each status means, see [Payment statuses](/docs/reference/payment-statuses/).

When you receive a `good` webhook, follow these steps.

<Steps>
  <Step>Verify the signature.</Step>
  <Step>Find your order by `payment_reference` or `order_id`.</Step>
  <Step>Check that you haven't already fulfilled it, because retries can repeat a notification.</Step>
  <Step>Mark the order paid and deliver.</Step>
  <Step>Return `200`.</Step>
</Steps>

If a payment request fails, see [Error codes](/docs/reference/error-codes/#payment-errors).

## Next steps

These pages are the best places to go next.

- [Webhooks](/docs/reference/webhooks/) for the full field list and a signature verification example
- [Go live](/docs/getting-started/go-live/) to prepare for production