# Accept a payment

> Markdown version of the public documentation of the Bifrost Crypto API v1, for AI agents and code generators. Same content as the HTML pages, generated from the same source, without navigation or styling.
>
> HTML version: https://bifrostcrypto.com/en/docs/guide-payin
> Related files: [ai.md](https://bifrostcrypto.com/ai.md) · [Postman](https://bifrostcrypto.com/postman-collection.json) · [OpenAPI](https://bifrostcrypto.com/openapi.json) · [llms.txt](https://bifrostcrypto.com/llms.txt)
> Other languages: [Português](https://bifrostcrypto.com/ai/pt-BR/guide-payin.md) · [Español](https://bifrostcrypto.com/ai/es/guide-payin.md) · [Français](https://bifrostcrypto.com/ai/fr/guide-payin.md)
> API v1 · contract last changed on 2026-10-10

From choosing the token to delivering the order, using payins created through the API.

## 1. Choose the token and network

GET /v1/summary/tokens lists the tokens of the platform per network, with min_receipt and max_receipt. The list is not filtered by your account: the payin request confirms whether the token accepts deposits for you on that network.

```bash
curl "https://bridge.bifrostcrypto.com/v1/summary/tokens" \
  -H "X-Bifrost-Invoke: YOUR_API_KEY"
```

## 2. Create the payin

POST /v1/payin with a reference_id that is unique in your system, the amount (process_by crypto_amount or fiat_amount), webhook_url and, if you want, expires_at in seconds (default 4 hours). Keep the internal_reference from the answer and show the customer the wallet, and the memo when the token needs one.

```bash
curl -X POST "https://bridge.bifrostcrypto.com/v1/payin" \
  -H "X-Bifrost-Invoke: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"reference_id":"order_1001","crypto_currency":"USDT","network":"BinanceSmartChain","process_by":"crypto_amount","crypto_amount":"50","webhook_url":"https://your-site.com/webhook","customer_info":"customer_42"}'
```

## 3. Receive the webhook

Verify X-Bifrost-Signature over the raw body, answer 2xx within 30 seconds and process afterwards. The same notice can arrive more than once: deduplicate on data.internal_reference together with event.

## 4. Check the amount before delivering

The payin is completed once received_amount reaches minimum_payment percent of crypto_amount, which can be less than the full amount. Compare data.received_amount with data.crypto_amount and decide what to do with any difference.

## 5. Choose when to deliver

payment_detected means the transfer was seen (funds_available false): delivering now is your decision and carries the risk of a reversal. payment_confirmed means it is final (funds_available true).

## 6. Handle the exceptions

payment_reversed: the network undid the payment and the credit was removed; check-payin now returns status reversed. is_duplicated true: an extra payment or a payment on another network created a new payin with its own references; link it to the order with customer_info.

## 7. Reconcile

GET /v1/check-payin/{internal_reference} returns the payin at any time. GET /v1/statements lists the balance movements: DEPOSIT for the credit, RATE and FEE for the charges.

## What to do when something fails

POST /v1/payin has no Idempotency-Key. The reference_id is what prevents a second payin.

| Situation | What to do |
| --- | --- |
| Timeout or no answer on POST /v1/payin | Resend with the same reference_id. If the answer is duplicate_reference_id, the first request worked: fetch it with GET /v1/list-payin?reference_id=… |
| 400 | Fix the request. Sending it again unchanged gives the same answer. |
| 500, 502 or 503 | Nothing was created. Retry later with the same reference_id. |
| 429 | Wait the seconds in Retry-After. |
| Webhook did not arrive | Deliveries are retried up to 10 times, about 5 minutes apart. Meanwhile, read the payin with GET /v1/check-payin/{internal_reference}. |

> Payins created in the panel are not returned by the API.
