# Справочник API

Все методы и объекты API для приёма платежей — на одной странице, подряд. Меню показывает, где вы сейчас, а адрес страницы меняется на ссылку раздела: её можно скопировать и отправить.

Адрес API — `https://api.avantpay.io/v3`.

Примеры берут ID магазина и секретный ключ из переменных окружения `AVANTPAY_SHOP_ID` и `AVANTPAY_SECRET_KEY`. Язык примеров выберите в любом блоке кода — он запомнится на всех страницах.

## Аутентификация

Адрес API — `https://api.avantpay.io/v3`. Пути методов добавляются к нему: `https://api.avantpay.io/v3/payments`. Запросы — только по HTTPS.

Отправляйте запросы только со своего сервера. Не вызывайте API из браузера или мобильного приложения: в их код пришлось бы положить секретный ключ, а там его может прочитать кто угодно. Браузер такой запрос и не выполнит: API не разрешает запросы со страниц сайтов (CORS выключен).

API использует HTTP Basic:

- логин — **ID магазина**, например `33661`;
- пароль — **секретный ключ**.

В cURL это параметр `-u`. Без cURL передайте заголовок `Authorization` со словом `Basic` и строкой `<ID магазина>:<секретный ключ>` в Base64. Почти все HTTP-библиотеки собирают этот заголовок сами, если передать логин и пароль.

Ключи OAuth (`Authorization: Bearer …`) AvantPay не поддерживает: такой запрос получит 401.

### Где взять ID магазина и секретный ключ

1. Войдите в [личный кабинет](https://avantpay.io/lk/).
2. Откройте **Ещё → Разработчикам → API-ключ** ([открыть сразу](https://avantpay.io/lk/?path=/api/key)). На телефоне вместо «Ещё» — «Меню».
3. ID магазина и адрес API — в блоке «Авторизация запросов».
4. Нажмите **Создать ключ**. Ключ показывается целиком только один раз. Скопируйте его сразу.

Если раздела «Разработчикам» нет, попросите владельца магазина добавить вас в разделе «Пользователи» с ролью «Разработчик».

### Как хранить ключ

- Храните ключ в переменных окружения или в хранилище секретов сервера.
- Не кладите ключ в код, в репозиторий, в логи и в письма.
- Если ключ мог утечь, нажмите **Перевыпустить** в том же разделе. Старый ключ сразу перестанет работать. Замените ключ на сервере.
- Тем же ключом AvantPay подписывает уведомления. После перевыпуска уведомления подписываются новым ключом.

### Права ключа

В блоке «Права ключа» видно, что можно делать этим ключом. Для создания платежей нужно право «Платежи».

- Права включает поддержка AvantPay. В личном кабинете их можно только посмотреть. Чтобы включить право, напишите на support@avantpay.io.
- Без права «Платежи» запрос `POST /v3/payments` получит ошибку 403 `forbidden`.
- Запросы `GET` (получить платёж, список платежей) работают с любым действующим ключом магазина.

### Лимит запросов

- Не больше 50 запросов в секунду на магазин. Сверх лимита API ответит 429 `too_many_requests`.
- В ответе 429 есть поле `retry_after` — через сколько миллисекунд повторить, и заголовок `Retry-After` — то же в секундах.
- Повторяйте запрос на создание платежа после 429 с тем же `Idempotence-Key`.

### Ошибки аутентификации

| HTTP | `code` | Когда | Что делать |
|---|---|---|---|
| 401 | `invalid_credentials` | Нет заголовка `Authorization`, неверный ID магазина или ключ, ключ перевыпущен или удалён, заголовок `Bearer`. `parameter` — `Authorization`. | Проверьте ID магазина и ключ. Если ключ потерян — перевыпустите его. |
| 403 | `forbidden` | У ключа нет права «Платежи» или магазин не активен. | Напишите в поддержку: support@avantpay.io. |
| 429 | `too_many_requests` | С вашего IP-адреса за минуту пришло больше 20 запросов с неверными ключами. До конца этой минуты API отвечает 429 на все запросы с этого адреса. | Исправьте ключи и повторите через `retry_after` миллисекунд. |

Проверка ключей: запрос возвращает последний платёж магазина и ничего не меняет.

```bash
curl "https://api.avantpay.io/v3/payments?limit=1" \
  -u "$AVANTPAY_SHOP_ID:$AVANTPAY_SECRET_KEY"
```

Ответ 200 — ключи верные. Ответ 401 `invalid_credentials` — неверный ID магазина или ключ:

```json
{
  "type": "error",
  "id": "0d8e4c1a-6b2f-4e3d-9a7c-5f1b2e3d4c5a",
  "code": "invalid_credentials",
  "description": "Invalid credentials: use HTTP Basic authentication with the shop ID as the username and the API secret key as the password",
  "parameter": "Authorization"
}
```

Заголовок `Authorization` без cURL:

```text
Authorization: Basic MzM2NjE6dGVzdF9zZWNyZXRfa2V5
```

Здесь `MzM2NjE6dGVzdF9zZWNyZXRfa2V5` — это Base64 от строки `33661:test_secret_key`.

Ответ 429 — больше 50 запросов в секунду:

```json
{
  "type": "error",
  "id": "5a1c3e2b-7d4f-4a6b-8c9d-0e1f2a3b4c5d",
  "code": "too_many_requests",
  "description": "Too many requests: the shop exceeded the request rate limit. Retry later with the same Idempotence-Key",
  "retry_after": 1000
}
```

## Идемпотентность

Ключ идемпотентности — заголовок `Idempotence-Key` — защищает от двойных платежей. Если запрос на создание платежа не получил ответа, его можно повторить с тем же ключом. AvantPay вернёт уже созданный платёж, а второй не создаст.

| Вопрос | Ответ |
|---|---|
| Где нужен | `POST /v3/payments` — создание платежа. Обязателен. |
| Значение | Любая строка до 64 символов. Лучше всего — UUID версии 4, например `7f1c9a52-3d4b-4e8f-a1b2-c3d4e5f6a7b8`. |
| Без заголовка | Ошибка 400 `invalid_request`, `"parameter": "Idempotence-Key"`. |
| В GET-запросах | Не нужен. Если передать, API его не учтёт. |
| Сколько действует | 24 часа. Повтор с тем же ключом в течение 24 часов вернёт тот же платёж. Позже — ошибка 400. |

API принимает и заголовок `Idempotency-Key` с тем же смыслом. Передавайте только один из двух. Оба заголовка с разными значениями — ошибка 400.

### Правила

1. Для каждой новой попытки оплаты создавайте новый ключ.
2. Создайте ключ до первого запроса и сохраните его в заказе. Тогда при повторе, даже после перезапуска сервера, вы возьмёте тот же ключ.
3. Повторяйте запрос с тем же ключом и тем же телом, если ответа нет, запрос оборвался по таймауту, пришёл ответ 500, 429 или 202. Повторяйте 1–2 минуты. Потом покажите покупателю «Платёж создаётся» и продолжайте повторять в фоне с тем же ключом, но не дольше 24 часов.
4. Никогда не используйте один ключ для двух разных платежей. Тот же ключ с другим телом запроса (например, с другой суммой) — ошибка 400, второй платёж не создастся.
5. Повтор с тем же ключом позже чем через 24 часа — ошибка 400. Чтобы узнать, чем кончился тот запрос, запросите платёж по `id` из заказа. Если `id` в заказе нет (ответ так и не пришёл), найдите платёж в [списке платежей](https://avantpay.io/developers/api/#get_payments_list) за время создания: у него в `metadata.order_id` ваш номер заказа.

### Что ответит API

| Ситуация | Ответ | Что делать |
|---|---|---|
| Новый ключ | 200, новый платёж | Сохранить `id` платежа. |
| Тот же ключ и то же тело, первый запрос выполнен, прошло меньше 24 часов | 200, тот же платёж | Ничего: второго платежа нет. Текущий статус узнавайте запросом `GET /v3/payments/{payment_id}`. |
| Тот же ключ, первый запрос ещё выполняется | API ждёт его до 25 секунд и отвечает 200 с тем же платежом. Если не дождался — 202, тело в примерах. | При 202 подождать `retry_after` миллисекунд и повторить с тем же ключом. |
| Тот же ключ, первый запрос сорвался после того, как платёж был записан | 200, тот же платёж со `"status": "canceled"` и без `confirmation_url`: платёж не создался до конца | Не отправлять покупателя на оплату. Создать новый платёж с новым ключом. |
| Тот же ключ, другое тело | 400 `invalid_request`, `"parameter": "Idempotence-Key"` | Для нового платежа — новый ключ. |
| Тот же ключ, прошло больше 24 часов | 400 `invalid_request`, `"parameter": "Idempotence-Key"` | Найти платёж по `id` из заказа. Для новой попытки оплаты — новый ключ. |
| Нет ключа, ключ длиннее 64 символов или два заголовка с разными значениями | 400 `invalid_request`, `"parameter": "Idempotence-Key"` | Передать один ключ до 64 символов. |

### Если ответа нет

Если запрос на создание платежа закончился таймаутом, обрывом связи или ответом 500, результат неизвестен: платёж мог создаться. Не создавайте платёж с новым ключом. Повторите тот же запрос с тем же ключом: придёт уже созданный платёж или он создастся сейчас.

Проверьте `status` в ответе на повтор. `pending` — отправьте покупателя на `confirmation.confirmation_url`. `canceled` — платёж не создался до конца: создайте новый с новым ключом.

Выполните эту команду дважды. Второй ответ вернёт тот же платёж с тем же `id`.

```bash
curl https://api.avantpay.io/v3/payments \
  -X POST \
  -u "$AVANTPAY_SHOP_ID:$AVANTPAY_SECRET_KEY" \
  -H "Idempotence-Key: 5b8e2f3a-6c1d-4e7f-9a0b-1c2d3e4f5a6b" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": {
      "value": "100.00",
      "currency": "RUB"
    },
    "capture": true,
    "confirmation": {
      "type": "redirect",
      "return_url": "https://example.com/orders/2"
    },
    "description": "Заказ №2",
    "metadata": {
      "email": "buyer@example.com",
      "order_id": "2"
    }
  }'
```

Ответ 202 — запрос с этим ключом ещё выполняется:

```json
{
  "type": "processing",
  "description": "Request accepted",
  "retry_after": 2000
}
```

Ответ 400 на тот же ключ с другим телом:

```json
{
  "type": "error",
  "id": "9c3b7a1e-2f4d-4b6a-8e5c-1d2f3a4b5c6d",
  "code": "invalid_request",
  "description": "Idempotence key duplicated: this key was already used with a different request body. Use a new Idempotence-Key for a new request",
  "parameter": "Idempotence-Key"
}
```

## Формат запросов и ответов

### Запросы

- Тело POST-запроса — JSON с заголовком `Content-Type: application/json`. Без этого заголовка API ответит 415.
- Тело — не больше 5 МБ. Больше — ответ 413. Запрос на создание платежа обычно меньше 1 КБ.
- Поля, которых нет в справочнике, API обычно отбрасывает без ошибки. Поэтому проверяйте имена полей: поле с опечаткой тоже отбросится. Некоторые поля дают ошибку 400: например, `receipt` (чеки AvantPay не отправляет) или `order_id` в корне запроса (номер заказа передавайте в `metadata.order_id`).
- Ставьте таймаут HTTP-клиента не меньше 30 секунд. Если ответа нет, повторите запрос с тем же `Idempotence-Key`.
- Заголовок `X-Request-Id` можно передать свой: латинские буквы, цифры и символы `_`, `.`, `:`, `-`, до 128 символов. Иначе API создаст его сам.

### Ответы

- Ответ — всегда JSON с заголовком `Content-Type: application/json; charset=utf-8`.
- Успешный ответ — сам объект, без обёрток. Например, объект платежа.
- Ошибка — объект с полями `type`, `id`, `code`, `description` и иногда `parameter`. Все коды — в разделе [Ошибки](https://avantpay.io/developers/api/#errors).
- Если у поля нет значения, поля нет в ответе. Значения `null` в ответах не бывает.
- В ответе могут появиться новые поля. Код не должен падать на незнакомом поле.
- В каждом ответе есть заголовок `X-Request-Id`. Пишите его в свои логи: по нему поддержка найдёт запрос.

### Сумма

Сумма — объект из двух строк: `value` и `currency`.

- `value` — строка, рубли и копейки через точку. Не больше двух знаков после точки: `"100.00"`, `"1500.50"`. Без пробелов и разделителей тысяч.
- Число (`100`) API тоже примет, но передавайте строку: с числом легко потерять копейки.
- Не передавайте копейки отдельно и не умножайте сумму на 100.
- Больше двух знаков после точки — ошибка 400.
- `currency` — `"RUB"`.
- В ответах `value` — всегда строка с двумя знаками после точки.

### Дата и время

Даты — в формате ISO 8601, по UTC, с миллисекундами и буквой `Z` на конце: `2026-10-18T10:15:30.123Z`. В запросах передавайте даты в том же формате.

### metadata

`metadata` — ваши данные к платежу: email покупателя, номер заказа, ID покупателя и т. п. В запросе на создание платежа `metadata` обязательна, и в ней обязателен ключ `email` — email покупателя. Покупатель из Telegram — `<id или username>@telegram.org`.

- Не больше 16 ключей.
- Имя ключа — до 32 символов.
- Значение — строка до 512 символов. Число или `true`/`false` API сохранит строкой: `1042` вернётся как `"1042"`.
- Ключ со значением `null` API не сохраняет.
- Массив или вложенный объект в значении — ошибка 400.
- `metadata` возвращается в объекте платежа и в уведомлениях.
- Не храните в `metadata` секреты и данные карт.

Сумма:

```json
{
  "value": "100.00",
  "currency": "RUB"
}
```

`metadata` с email покупателя и номером заказа:

```json
{
  "email": "buyer@example.com",
  "order_id": "123",
  "customer_id": "1042"
}
```

Покупатель из Telegram:

```json
{
  "email": "123456789@telegram.org",
  "order_id": "124"
}
```

## Ошибки

Если запрос не выполнен, API отвечает кодом HTTP 400 или выше и объектом ошибки. Объект ошибки приходит на любой ответ 4xx и 5xx, в том числе на неверный адрес (404), неверный метод HTTP (405) и запрос без JSON (415).

### Объект ошибки

| Поле | Тип | Есть всегда | Описание |
|---|---|---|---|
| `type` | string | да | Всегда `error`. Пример: `"error"`. |
| `id` | string | да | ID ошибки. Укажите его, если пишете в поддержку. Пример: `"6daac9fa-342d-4264-91c5-b5eafd1a0010"`. |
| `code` | string | да | Код ошибки из таблицы ниже. По нему решайте, что делать. Пример: `"invalid_request"`. |
| `description` | string | да | Что не так и как исправить. На английском. Пишите в логи, покупателю не показывайте. Пример: `"Invalid request"`. |
| `parameter` | string | нет | Какое поле, заголовок или параметр неверны. Например: `amount.value`, `metadata.email`, `Idempotence-Key`, `Authorization`, `payment_id`, `limit`. Пример: `"metadata.email"`. |
| `retry_after` | integer | нет | Через сколько миллисекунд повторить запрос. Есть у ответов 429. Пример: `1000`. |

### Коды

| HTTP | `code` | Когда | Что делать |
|---|---|---|---|
| 200 | — | Запрос выполнен. Создание платежа — тоже 200. | — |
| 202 | — | Запрос с этим ключом идемпотентности ещё выполняется. Тело: `{"type": "processing", "description": "Request accepted", "retry_after": 2000}`. | Подождать `retry_after` миллисекунд и повторить с тем же `Idempotence-Key`. |
| 400 | `invalid_request` | Неверный запрос: нет поля или заголовка (например, `metadata.email`), неверный формат, сумма вне лимитов, ключ идемпотентности уже использован с другим телом, тело не JSON. | Исправить запрос по `parameter` и `description`. Без исправления не повторять. |
| 400 | `not_supported` | Передано поле или значение, которого нет в API (например, `receipt` или `"capture": false`), или вызван метод, которого нет. | Убрать поле или не вызывать метод. Без исправления не повторять. |
| 401 | `invalid_credentials` | Нет заголовка `Authorization`, неверный ID магазина или секретный ключ, заголовок `Bearer`. `parameter` — `Authorization`. | Проверить ID магазина и ключ. Без исправления не повторять. |
| 403 | `forbidden` | У ключа нет права «Платежи», магазин не активен или сценарий `qr` не включён для магазина. | Написать в поддержку: support@avantpay.io. |
| 404 | `not_found` | Платежа с таким `id` нет у вашего магазина (`parameter` — `payment_id`). Или такого адреса нет. | Проверить `id` и адрес. |
| 405 | `invalid_request` | Метод HTTP не подходит для этого адреса. Например, `PUT /v3/payments`. Допустимые методы — в заголовке `Allow`. | Исправить метод. |
| 413 | `invalid_request` | Тело запроса больше 5 МБ. | Уменьшить тело. |
| 415 | `invalid_request` | У POST-запроса нет заголовка `Content-Type: application/json`. | Передать JSON с этим заголовком. |
| 429 | `too_many_requests` | Больше 50 запросов в секунду от магазина или много запросов с неверными ключами с одного IP-адреса. | Подождать `retry_after` миллисекунд (заголовок `Retry-After` — в секундах) и повторить с тем же `Idempotence-Key`. |
| 500 | `internal_server_error` | Сбой у AvantPay. Результат запроса неизвестен: платёж мог создаться. | Повторить с тем же `Idempotence-Key` или проверить платёж запросом GET. |

Другой код 5xx или ответ не в JSON обрабатывайте как 500.

### Когда повторять запрос

| Ответ | Повторять? |
|---|---|
| 400, 401, 403, 404, 405, 413, 415 | Нет. Сначала исправьте запрос, ключи или настройки. Исправленный запрос на создание платежа отправляйте с новым ключом идемпотентности. |
| 202, 429 | Да, через `retry_after` миллисекунд, с тем же `Idempotence-Key`. |
| 500, таймаут, обрыв связи | Да, с тем же `Idempotence-Key` и тем же телом. Повторяйте 1–2 минуты, потом покажите покупателю «Платёж создаётся» и продолжайте в фоне с тем же ключом, но не дольше 24 часов. |

Не создавайте платёж с новым ключом, пока не знаете, чем кончился прежний запрос. Иначе покупатель может заплатить дважды.

Ошибка 400 — в запросе нет email покупателя:

```json
{
  "type": "error",
  "id": "6daac9fa-342d-4264-91c5-b5eafd1a0010",
  "code": "invalid_request",
  "description": "metadata.email is required: pass the buyer's email address, for a Telegram buyer use <id or username>@telegram.org",
  "parameter": "metadata.email"
}
```

Ошибка 400 — поле, которого нет в API:

```json
{
  "type": "error",
  "id": "1f4e2a7c-8b3d-4c6e-9a5f-0d1c2b3a4e5f",
  "code": "not_supported",
  "description": "receipt is not supported: AvantPay does not register fiscal receipts (54-FZ), remove receipt from the request",
  "parameter": "receipt"
}
```

Ошибка 429:

```json
{
  "type": "error",
  "id": "5a1c3e2b-7d4f-4a6b-8c9d-0e1f2a3b4c5d",
  "code": "too_many_requests",
  "description": "Too many requests: the shop exceeded the request rate limit. Retry later with the same Idempotence-Key",
  "retry_after": 1000
}
```

## Объект платежа

Объект платежа — это платёж и всё, что о нём известно: сумма, статус, способ оплаты, ссылка на оплату, email покупателя.

API возвращает этот объект:

- в ответе на [создание платежа](https://avantpay.io/developers/api/#create_payment) — `POST /v3/payments`;
- в ответе на [запрос платежа](https://avantpay.io/developers/api/#get_payment) — `GET /v3/payments/{payment_id}`;
- в поле `items` [списка платежей](https://avantpay.io/developers/api/#get_payments_list) — `GET /v3/payments`;
- в поле `object` [уведомления](https://avantpay.io/developers/api/#notification_object).

### Правила чтения объекта

- Если у поля нет значения, поля нет в объекте. Значения `null` не бывает. Перед чтением необязательного поля проверьте, что оно есть.
- В объекте могут появиться новые поля. Код не должен падать на незнакомом поле или незнакомом значении.
- Выполняйте заказ, только если `status` равен `succeeded`, а `amount.value` и `amount.currency` равны сумме и валюте заказа ([правила](https://avantpay.io/developers/statuses/#rules)).
- Суммы — строки с двумя знаками после точки: `"100.00"`. Даты — ISO 8601 по UTC с миллисекундами: `"2026-10-18T10:15:30.123Z"`.

### Поля

| Поле | Тип | Есть всегда | Описание |
|---|---|---|---|
| `id` | string | да | ID платежа, UUID из 36 символов. Сохраните его в заказе: по нему вы получите платёж. Пример: `"2f9b6c1e-4d7a-4c3b-9e8f-1a2b3c4d5e6f"`. |
| `status` | string | да | Статус платежа: `pending`, `succeeded` или `canceled`. Что делать в каждом — на странице [Статусы платежа](https://avantpay.io/developers/statuses/). Пример: `"succeeded"`. |
| `paid` | boolean | да | `true`, если платёж оплачен (`status` равен `succeeded`). Иначе `false`. Пример: `true`. |
| `amount` | object | да | Сумма платежа — ровно та, что вы передали при создании. Покупатель платит эту сумму. |
| `amount.value` | string | да | Сумма строкой с двумя знаками после точки. Пример: `"1000.00"`. |
| `amount.currency` | string | да | Валюта: `RUB`. Пример: `"RUB"`. |
| `income_amount` | object | нет | Сколько получит магазин: `amount` минус комиссия AvantPay. Бывает только у платежей со статусом `succeeded`. Может не быть и у них, например пока AvantPay проверяет оплату. Не решайте по этому полю, оплачен ли платёж. |
| `income_amount.value` | string | да | Сумма строкой с двумя знаками после точки. Пример: `"975.00"`. |
| `income_amount.currency` | string | да | Валюта: `RUB`. Пример: `"RUB"`. |
| `description` | string | нет | Описание, которое вы передали при создании. Есть, только если вы его передали. Пример: `"Заказ №123"`. |
| `recipient` | object | да | Получатель платежа — ваш магазин. |
| `recipient.account_id` | string | да | ID магазина строкой. Пример: `"33661"`. |
| `recipient.gateway_id` | string | нет | ID счёта в AvantPay, на который зачисляются деньги. Появляется, когда выбран способ оплаты. Для интеграции не нужен. Пример: `"6b1f3c0a-58e2-4f7d-9a41-0c2d7e5b8f93"`. |
| `payment_method` | object | нет | Способ оплаты. Появляется, когда способ выбран: сразу, если вы передали `payment_method_data`, иначе — когда покупатель выберет способ на странице оплаты. Если магазину подключены другие способы, `type` может быть и другим — на незнакомом значении код не должен падать. Поля зависят от `payment_method.type`. Варианты: `sbp` — СБП, поля: `type`, `id`, `saved`, `status`, `title`; `bank_card` — банковская карта, поля: `type`, `id`, `saved`, `status`, `title`; `crypto` — криптовалюта, поля: `type`, `id`, `saved`, `status`, `title`. Поля каждого варианта — в строках ниже с пометкой «Вариант». |
| `payment_method.type` | string | да | Вариант `sbp` (СБП): поле есть, когда `payment_method.type` — `sbp`. Значение — `sbp`. Пример: `"sbp"`. |
| `payment_method.id` | string | да | Вариант `sbp` (СБП): поле есть, когда `payment_method.type` — `sbp`. ID способа оплаты. Всегда равен `id` платежа: способы оплаты не сохраняются. Пример: `"2f9b6c1e-4d7a-4c3b-9e8f-1a2b3c4d5e6f"`. |
| `payment_method.saved` | boolean | да | Вариант `sbp` (СБП): поле есть, когда `payment_method.type` — `sbp`. Сохранён ли способ для следующих платежей. Всегда `false`. Пример: `false`. |
| `payment_method.status` | string | да | Вариант `sbp` (СБП): поле есть, когда `payment_method.type` — `sbp`. Статус способа оплаты. Всегда `inactive`: способ не сохранён. Пример: `"inactive"`. |
| `payment_method.title` | string | нет | Вариант `sbp` (СБП): поле есть, когда `payment_method.type` — `sbp`. Название способа для людей. Пример: `"СБП"`. |
| `payment_method.type` | string | да | Вариант `bank_card` (банковская карта): поле есть, когда `payment_method.type` — `bank_card`. Значение — `bank_card`. Пример: `"bank_card"`. |
| `payment_method.id` | string | да | Вариант `bank_card` (банковская карта): поле есть, когда `payment_method.type` — `bank_card`. ID способа оплаты. Всегда равен `id` платежа: способы оплаты не сохраняются. Пример: `"2f9b6c1e-4d7a-4c3b-9e8f-1a2b3c4d5e6f"`. |
| `payment_method.saved` | boolean | да | Вариант `bank_card` (банковская карта): поле есть, когда `payment_method.type` — `bank_card`. Сохранён ли способ для следующих платежей. Всегда `false`. Пример: `false`. |
| `payment_method.status` | string | да | Вариант `bank_card` (банковская карта): поле есть, когда `payment_method.type` — `bank_card`. Статус способа оплаты. Всегда `inactive`: способ не сохранён. Пример: `"inactive"`. |
| `payment_method.title` | string | нет | Вариант `bank_card` (банковская карта): поле есть, когда `payment_method.type` — `bank_card`. Название способа для людей. Пример: `"Банковская карта"`. |
| `payment_method.type` | string | да | Вариант `crypto` (криптовалюта): поле есть, когда `payment_method.type` — `crypto`. Значение — `crypto`. Пример: `"crypto"`. |
| `payment_method.id` | string | да | Вариант `crypto` (криптовалюта): поле есть, когда `payment_method.type` — `crypto`. ID способа оплаты. Всегда равен `id` платежа: способы оплаты не сохраняются. Пример: `"2f9b6c1e-4d7a-4c3b-9e8f-1a2b3c4d5e6f"`. |
| `payment_method.saved` | boolean | да | Вариант `crypto` (криптовалюта): поле есть, когда `payment_method.type` — `crypto`. Сохранён ли способ для следующих платежей. Всегда `false`. Пример: `false`. |
| `payment_method.status` | string | да | Вариант `crypto` (криптовалюта): поле есть, когда `payment_method.type` — `crypto`. Статус способа оплаты. Всегда `inactive`: способ не сохранён. Пример: `"inactive"`. |
| `payment_method.title` | string | нет | Вариант `crypto` (криптовалюта): поле есть, когда `payment_method.type` — `crypto`. Название способа для людей. Пример: `"Криптовалюта"`. |
| `captured_at` | string | нет | Когда платёж оплачен. Бывает только у платежей со статусом `succeeded`. Пример: `"2026-10-18T10:17:02.418Z"`. |
| `created_at` | string | да | Когда платёж создан. Пример: `"2026-10-18T10:15:30.123Z"`. |
| `expires_at` | string | да | До какого момента покупатель может заплатить: 20 минут после создания платежа. Потом платёж станет `canceled`, но не в ту же секунду: сначала AvantPay проверит, не прошла ли оплата. Обычно `canceled` приходит в течение 10 минут после `expires_at`, в редких случаях — до 2 часов. Пример: `"2026-10-18T10:35:30.123Z"`. |
| `confirmation` | object | да | Как покупатель платит — сценарий, который вы передали при создании. Поля зависят от `confirmation.type`. Варианты: `redirect` — страница оплаты, поля: `type`, `confirmation_url`, `return_url`; `qr` — QR-код СБП, поля: `type`, `confirmation_data`. Поля каждого варианта — в строках ниже с пометкой «Вариант». |
| `confirmation.type` | string | да | Вариант `redirect` (страница оплаты): поле есть, когда `confirmation.type` — `redirect`. `redirect` — страница оплаты AvantPay. Пример: `"redirect"`. |
| `confirmation.confirmation_url` | string | нет | Вариант `redirect` (страница оплаты): поле есть, когда `confirmation.type` — `redirect`. Ссылка на страницу оплаты. Отправьте покупателя по ней, только если `status` равен `pending`. Может не быть у платежа, который отменён при создании. Пример: `"https://avantpay.io/link/Aq91c7d"`. |
| `confirmation.return_url` | string | нет | Вариант `redirect` (страница оплаты): поле есть, когда `confirmation.type` — `redirect`. Адрес возврата покупателя, который вы передали. Пример: `"https://example.com/orders/123"`. |
| `confirmation.type` | string | да | Вариант `qr` (QR-код СБП): поле есть, когда `confirmation.type` — `qr`. `qr` — QR-код СБП. Пример: `"qr"`. |
| `confirmation.confirmation_data` | string | нет | Вариант `qr` (QR-код СБП): поле есть, когда `confirmation.type` — `qr`. Ссылка для QR-кода СБП. Сделайте из неё QR-код, на телефоне ссылку можно просто открыть. Сразу после создания здесь может быть ссылка на страницу оплаты AvantPay (`https://avantpay.io/link/…`): QR-код из неё откроет страницу оплаты в браузере телефона. Потом значение может смениться на ссылку СБП (`https://qr.nspk.ru/…`). Показывайте QR-код из последнего полученного объекта. Пример: `"https://qr.nspk.ru/AD10006M8KHABCDEFG"`. |
| `test` | boolean | да | Тестовый ли платёж. Всегда `false`: тестового режима нет. Пример: `false`. |
| `refunded_amount` | object | нет | Сколько денег вернули покупателю. Есть, только если был возврат. Вернуть деньги можно только в личном кабинете. Статус после возврата остаётся `succeeded`. |
| `refunded_amount.value` | string | да | Сумма строкой с двумя знаками после точки. Пример: `"300.00"`. |
| `refunded_amount.currency` | string | да | Валюта: `RUB`. Пример: `"RUB"`. |
| `refundable` | boolean | да | Можно ли вернуть платёж через API. Всегда `false`: вернуть деньги можно только в личном кабинете. Пример: `false`. |
| `metadata` | object | да | Ваши данные из запроса на создание: email покупателя, номер заказа и другие ключи, которые вы передали. Значения — строки. |
| `metadata.email` | string | да | Email покупателя, который вы передали. Пример: `"buyer@example.com"`. |
| `metadata.order_id` | string | нет | Номер заказа, если вы его передали. Пример: `"123"`. |
| `cancellation_details` | object | нет | Кто отменил платёж и почему. Бывает только у платежей со статусом `canceled`. |
| `cancellation_details.party` | string | да | Кто отменил: `merchant`, `avantpay` или `payment_network`. Что значит каждое — на странице [Статусы платежа](https://avantpay.io/developers/statuses/#cancellation). Пример: `"avantpay"`. |
| `cancellation_details.reason` | string | да | Причина отмены. Все причины — на странице [Статусы платежа](https://avantpay.io/developers/statuses/#reasons). Пример: `"expired_on_confirmation"`. |

Оплачен:

Покупатель оплатил картой:

```json
{
  "id": "2f9b6c1e-4d7a-4c3b-9e8f-1a2b3c4d5e6f",
  "status": "succeeded",
  "paid": true,
  "amount": {
    "value": "1000.00",
    "currency": "RUB"
  },
  "income_amount": {
    "value": "975.00",
    "currency": "RUB"
  },
  "description": "Заказ №123",
  "recipient": {
    "account_id": "33661",
    "gateway_id": "6b1f3c0a-58e2-4f7d-9a41-0c2d7e5b8f93"
  },
  "payment_method": {
    "type": "bank_card",
    "id": "2f9b6c1e-4d7a-4c3b-9e8f-1a2b3c4d5e6f",
    "saved": false,
    "status": "inactive",
    "title": "Банковская карта"
  },
  "captured_at": "2026-10-18T10:17:02.418Z",
  "created_at": "2026-10-18T10:15:30.123Z",
  "expires_at": "2026-10-18T10:35:30.123Z",
  "confirmation": {
    "type": "redirect",
    "confirmation_url": "https://avantpay.io/link/Aq91c7d",
    "return_url": "https://example.com/orders/123"
  },
  "test": false,
  "refundable": false,
  "metadata": {
    "email": "buyer@example.com",
    "order_id": "123"
  }
}
```

Новый:

Только что созданный платёж. Способ оплаты не передан, поэтому нет `payment_method` и `recipient.gateway_id`:

```json
{
  "id": "e5b1c9d3-7a2f-4e8b-9c6d-1f0a2b3c4d5e",
  "status": "pending",
  "paid": false,
  "amount": {
    "value": "500.00",
    "currency": "RUB"
  },
  "description": "Заказ №127",
  "recipient": {
    "account_id": "33661"
  },
  "created_at": "2026-10-18T11:02:10.517Z",
  "expires_at": "2026-10-18T11:22:10.517Z",
  "confirmation": {
    "type": "redirect",
    "confirmation_url": "https://avantpay.io/link/Kd73pQe",
    "return_url": "https://example.com/orders/127"
  },
  "test": false,
  "refundable": false,
  "metadata": {
    "email": "123456789@telegram.org",
    "order_id": "127"
  }
}
```

Отменён:

Покупатель не заплатил до `expires_at`:

```json
{
  "id": "8d0e4b52-7c19-4a6e-b3f1-5e2a9c7d1b40",
  "status": "canceled",
  "paid": false,
  "amount": {
    "value": "500.00",
    "currency": "RUB"
  },
  "description": "Заказ №125",
  "recipient": {
    "account_id": "33661"
  },
  "created_at": "2026-10-18T12:00:00.000Z",
  "expires_at": "2026-10-18T12:20:00.000Z",
  "confirmation": {
    "type": "redirect",
    "confirmation_url": "https://avantpay.io/link/Zt5mW2r",
    "return_url": "https://example.com/orders/125"
  },
  "test": false,
  "refundable": false,
  "metadata": {
    "email": "buyer@example.com",
    "order_id": "125"
  },
  "cancellation_details": {
    "party": "avantpay",
    "reason": "expired_on_confirmation"
  }
}
```

Возврат:

Покупатель заплатил по СБП, часть денег ему вернули в личном кабинете. Статус остался `succeeded`:

```json
{
  "id": "c4a8e2f1-9b3d-4f6a-8e1c-7d2b5a9f3e60",
  "status": "succeeded",
  "paid": true,
  "amount": {
    "value": "250.00",
    "currency": "RUB"
  },
  "income_amount": {
    "value": "243.75",
    "currency": "RUB"
  },
  "description": "Заказ №122",
  "recipient": {
    "account_id": "33661",
    "gateway_id": "6b1f3c0a-58e2-4f7d-9a41-0c2d7e5b8f93"
  },
  "payment_method": {
    "type": "sbp",
    "id": "c4a8e2f1-9b3d-4f6a-8e1c-7d2b5a9f3e60",
    "saved": false,
    "status": "inactive",
    "title": "СБП"
  },
  "captured_at": "2026-10-17T18:41:09.004Z",
  "created_at": "2026-10-17T18:39:55.871Z",
  "expires_at": "2026-10-17T18:59:55.871Z",
  "confirmation": {
    "type": "redirect",
    "confirmation_url": "https://avantpay.io/link/Pq28vXn",
    "return_url": "https://example.com/orders/122"
  },
  "test": false,
  "refunded_amount": {
    "value": "50.00",
    "currency": "RUB"
  },
  "refundable": false,
  "metadata": {
    "email": "buyer@example.com",
    "order_id": "122"
  }
}
```

## Создать платёж

```text
POST https://api.avantpay.io/v3/payments
```

Создаёт платёж и возвращает [объект платежа](https://avantpay.io/developers/api/#payment_object) со статусом `pending` и ссылкой на оплату `confirmation.confirmation_url`.

> **Email покупателя обязателен.**
>
> Передайте его в `metadata.email`. Покупатель из Telegram — `<id или username>@telegram.org`, например `123456789@telegram.org`.

### Заголовки

| Заголовок | Обязательно | Значение |
|---|---|---|
| `Authorization` | да | HTTP Basic: ID магазина и секретный ключ. В cURL — `-u "$AVANTPAY_SHOP_ID:$AVANTPAY_SECRET_KEY"`. |
| `Idempotence-Key` | да | Ключ идемпотентности: уникальная строка до 64 символов, лучше UUID. Новый для каждой попытки оплаты, тот же при повторе запроса. [Подробнее](https://avantpay.io/developers/api/#idempotence) |
| `Content-Type` | да | `application/json` |

### Параметры запроса

| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
| `amount` | object | да | Сумма платежа. Покупатель заплатит ровно её. Комиссию AvantPay платит магазин: она вычитается из этой суммы. |
| `amount.value` | string | да | Сумма строкой, рубли и копейки через точку. Больше нуля, не больше двух знаков после точки. Должна укладываться в лимиты способов оплаты — они есть в личном кабинете: **Ещё → Способы оплаты**. Пример: `"1000.00"`. |
| `amount.currency` | string | да | Валюта: `RUB`. Пример: `"RUB"`. |
| `capture` | boolean | да | Указывается `true`. Пример: `true`. |
| `confirmation` | object | да | Как покупатель будет платить. Поля зависят от `confirmation.type`. Варианты: `redirect` — страница оплаты, поля: `type`, `return_url`; `qr` — QR-код СБП, поля: `type`, `return_url`. Поля каждого варианта — в строках ниже с пометкой «Вариант». |
| `confirmation.type` | string | да | Вариант `redirect` (страница оплаты): поле есть, когда `confirmation.type` — `redirect`. `redirect` — покупатель переходит на страницу оплаты AvantPay. Пример: `"redirect"`. |
| `confirmation.return_url` | string | да | Вариант `redirect` (страница оплаты): поле есть, когда `confirmation.type` — `redirect`. Куда вернуть покупателя после оплаты или отказа от неё. Адрес `http://` или `https://`, до 2048 символов. AvantPay открывает его как есть, без параметров, поэтому укажите в нём свой заказ. Пример: `"https://example.com/orders/123"`. |
| `confirmation.type` | string | да | Вариант `qr` (QR-код СБП): поле есть, когда `confirmation.type` — `qr`. `qr` — вы показываете покупателю QR-код СБП. Только вместе с `"payment_method_data": {"type": "sbp"}` ([подробнее](https://avantpay.io/developers/api/#create_payment-qr)). Пример: `"qr"`. |
| `confirmation.return_url` | string | да | Вариант `qr` (QR-код СБП): поле есть, когда `confirmation.type` — `qr`. Куда вернуть покупателя после оплаты или отказа от неё. Адрес `http://` или `https://`, до 2048 символов. AvantPay открывает его как есть, без параметров, поэтому укажите в нём свой заказ. Пример: `"https://example.com/orders/123"`. |
| `description` | string | нет | Описание платежа, до 128 символов. Его видит покупатель на странице оплаты и вы в личном кабинете. Пример: `"Заказ №123"`. |
| `payment_method_data` | object | нет | Способ оплаты. Если не передать, покупатель выберет способ на странице оплаты. Способ должен быть включён у магазина. Поля зависят от `payment_method_data.type`. Варианты: `sbp` — СБП, поля: `type`; `bank_card` — банковская карта, поля: `type`; конкретный способ (`type` — ID), поля: `type`. Поля каждого варианта — в строках ниже с пометкой «Вариант». |
| `payment_method_data.type` | string | да | Вариант `sbp` (СБП): поле есть, когда `payment_method_data.type` — `sbp`. Значение — `sbp`. Пример: `"sbp"`. |
| `payment_method_data.type` | string | да | Вариант `bank_card` (банковская карта): поле есть, когда `payment_method_data.type` — `bank_card`. Значение — `bank_card`. Пример: `"bank_card"`. |
| `payment_method_data.type` | string | да | Вариант «конкретный способ»: ID способа оплаты магазина, до 64 символов. Нужен, только если у магазина включено несколько способов одного типа: тогда на `sbp` или `bank_card` API ответит 400 и перечислит ID в `description`. Пример: `"sbp-2"`. |
| `metadata` | object | да | Ваши данные к платежу. Обязателен ключ `email`. Всего до 16 ключей, имя ключа до 32 символов, значение — строка до 512 символов. Вернутся в объекте платежа и в уведомлениях. Подробнее — в разделе [metadata](https://avantpay.io/developers/api/#format-metadata). |
| `metadata.email` | string | да | Email покупателя, до 254 символов. Покупатель из Telegram — `<id или username>@telegram.org`, например `123456789@telegram.org`. Нет email или адрес неверный — ошибка 400 `invalid_request`, `parameter` — `metadata.email`. Пример: `"buyer@example.com"`. |
| `metadata.order_id` | string | нет | Ваш номер заказа. Вернётся в объекте платежа и в уведомлениях. API не проверяет, что номер уникален: от двойного платежа защищает ключ идемпотентности. Пример: `"123"`. |

### Варианты

#### Покупатель выбирает способ сам

Не передавайте `payment_method_data`. На странице оплаты покупатель увидит все способы, которые включены у магазина. В ответе не будет `payment_method` и `recipient.gateway_id` — они появятся, когда покупатель выберет способ.

#### Сразу СБП или карта

Передайте `"payment_method_data": {"type": "sbp"}` или `"payment_method_data": {"type": "bank_card"}`. Покупатель сразу попадёт на оплату этим способом.

```bash
curl https://api.avantpay.io/v3/payments \
  -X POST \
  -u "$AVANTPAY_SHOP_ID:$AVANTPAY_SECRET_KEY" \
  -H "Idempotence-Key: 9e8d7c6b-5a4f-4e3d-8c2b-1a0f9e8d7c6b" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": {
      "value": "1500.00",
      "currency": "RUB"
    },
    "capture": true,
    "confirmation": {
      "type": "redirect",
      "return_url": "https://example.com/orders/126"
    },
    "description": "Заказ №126",
    "payment_method_data": {
      "type": "sbp"
    },
    "metadata": {
      "email": "123456789@telegram.org",
      "order_id": "126"
    }
  }'
```

Ответ:

```json
{
  "id": "c7e2a9f4-1b3d-4c5e-8f6a-9b0c1d2e3f4a",
  "status": "pending",
  "paid": false,
  "amount": {
    "value": "1500.00",
    "currency": "RUB"
  },
  "description": "Заказ №126",
  "recipient": {
    "account_id": "33661",
    "gateway_id": "6b1f3c0a-58e2-4f7d-9a41-0c2d7e5b8f93"
  },
  "payment_method": {
    "type": "sbp",
    "id": "c7e2a9f4-1b3d-4c5e-8f6a-9b0c1d2e3f4a",
    "saved": false,
    "status": "inactive",
    "title": "СБП"
  },
  "created_at": "2026-10-18T11:30:00.000Z",
  "expires_at": "2026-10-18T11:50:00.000Z",
  "confirmation": {
    "type": "redirect",
    "confirmation_url": "https://avantpay.io/link/Wm4tR8b",
    "return_url": "https://example.com/orders/126"
  },
  "test": false,
  "refundable": false,
  "metadata": {
    "email": "123456789@telegram.org",
    "order_id": "126"
  }
}
```

Здесь покупатель пришёл из Telegram: его email — `123456789@telegram.org`.

#### QR-код СБП

Вы показываете покупателю QR-код, он сканирует его телефоном и платит. Правила:

- сценарий `qr` работает только с `"payment_method_data": {"type": "sbp"}`;
- `return_url` обязателен, как и у `redirect`;
- сценарий включает поддержка AvantPay. Если он не включён, API ответит 403 `forbidden`, `"parameter": "confirmation.type"`.

```bash
curl https://api.avantpay.io/v3/payments \
  -X POST \
  -u "$AVANTPAY_SHOP_ID:$AVANTPAY_SECRET_KEY" \
  -H "Idempotence-Key: 3c2b1a09-8f7e-4d6c-9b5a-4e3d2c1b0a99" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": {
      "value": "500.00",
      "currency": "RUB"
    },
    "capture": true,
    "confirmation": {
      "type": "qr",
      "return_url": "https://example.com/orders/124"
    },
    "description": "Заказ №124",
    "payment_method_data": {
      "type": "sbp"
    },
    "metadata": {
      "email": "buyer@example.com",
      "order_id": "124"
    }
  }'
```

Ответ:

```json
{
  "id": "450d5a05-e377-4946-9e58-2627cae999b4",
  "status": "pending",
  "paid": false,
  "amount": {
    "value": "500.00",
    "currency": "RUB"
  },
  "description": "Заказ №124",
  "recipient": {
    "account_id": "33661",
    "gateway_id": "6b1f3c0a-58e2-4f7d-9a41-0c2d7e5b8f93"
  },
  "payment_method": {
    "type": "sbp",
    "id": "450d5a05-e377-4946-9e58-2627cae999b4",
    "saved": false,
    "status": "inactive",
    "title": "СБП"
  },
  "created_at": "2026-10-18T11:02:10.517Z",
  "expires_at": "2026-10-18T11:22:10.517Z",
  "confirmation": {
    "type": "qr",
    "confirmation_data": "https://avantpay.io/link/Vb5nE2k"
  },
  "test": false,
  "refundable": false,
  "metadata": {
    "email": "buyer@example.com",
    "order_id": "124"
  }
}
```

Сделайте QR-код из строки `confirmation.confirmation_data` и покажите его покупателю. На телефоне эту ссылку можно просто открыть.

Сразу после создания в `confirmation_data` может быть ссылка на страницу оплаты AvantPay, как в примере выше: QR-код из неё откроет страницу оплаты в браузере телефона. Потом значение может смениться на ссылку СБП (`https://qr.nspk.ru/…`). Показывайте QR-код из последнего полученного объекта платежа.

### Что сделать после ответа

1. Сохраните `id` платежа в заказе.
2. Если `status` равен `pending` и есть `confirmation.confirmation_url`, отправьте покупателя по этой ссылке. Если повтор запроса вернул `canceled` без ссылки, платёж не создался до конца: создайте новый с новым ключом идемпотентности ([подробнее](https://avantpay.io/developers/api/#idempotence-responses)).
3. Дождитесь [уведомления](https://avantpay.io/developers/webhooks/) и проверьте платёж запросом [`GET /v3/payments/{payment_id}`](https://avantpay.io/developers/api/#get_payment).

Если запрос оборвался, пришёл ответ 500, 429 или 202, повторите его с тем же `Idempotence-Key` и тем же телом. Повторяйте 1–2 минуты. Потом покажите покупателю «Платёж создаётся» и продолжайте повторять в фоне с тем же ключом, но не дольше 24 часов. Примеры на Python, Node.js и PHP так и устроены: ключ идемпотентности они получают от вас, а перед отправкой покупателя на оплату проверяют `status` и ссылку.

### Ошибки

Формат ошибок и общие коды — в разделе [Ошибки](https://avantpay.io/developers/api/#errors). Ошибки этого метода:

| HTTP | `code` | `parameter` | Когда | Что делать |
|---|---|---|---|---|
| 400 | `invalid_request` | `metadata.email` | Нет `metadata`, нет ключа `email`, он пустой или это не email (больше 254 символов, неверный адрес `…@telegram.org`). | Передать email покупателя. Покупатель из Telegram — `<id или username>@telegram.org`. |
| 400 | `invalid_request` | `Idempotence-Key` | Нет ключа, ключ длиннее 64 символов, переданы `Idempotence-Key` и `Idempotency-Key` с разными значениями, тот же ключ уже использован с другим телом запроса или больше 24 часов назад. | Передать один ключ до 64 символов. Для нового платежа — новый ключ. |
| 400 | `invalid_request` | `capture` | Нет `capture` или это не `true`/`false` (например, строка `"true"`). | Передать `"capture": true`. |
| 400 | `not_supported` | `capture` | `"capture": false`. | Передать `"capture": true`. |
| 400 | `invalid_request` | `amount`, `amount.value` | Нет суммы, сумма не число, больше двух знаков после точки, не больше нуля или вне лимитов способов оплаты. | Исправить сумму. Лимиты — в личном кабинете, **Ещё → Способы оплаты**. |
| 400 | `invalid_request` | `amount.currency` | Валюта не `RUB` или у магазина нет способов оплаты в этой валюте. | Передать `"RUB"`. |
| 400 | `invalid_request` | — | У магазина не включён ни один способ оплаты. | Написать в поддержку: support@avantpay.io. |
| 400 | `invalid_request` | `confirmation`, `confirmation.type`, `confirmation.return_url` | Нет `confirmation`, неизвестный тип, нет `return_url`, `return_url` — не адрес `http://` или `https://` либо длиннее 2048 символов, `qr` без `"payment_method_data": {"type": "sbp"}`. | Передать `return_url`. Для `qr` — ещё способ `sbp`. |
| 400 | `not_supported` | `confirmation.type` | Тип, кроме `redirect` и `qr`. | Передать `redirect` или `qr`. |
| 400 | `invalid_request` | `payment_method_data.type` | Такого способа нет у магазина, он не работает в рублях, или включено несколько способов этого типа. | Передать `sbp` или `bank_card`, идентификатор способа из `description` либо не передавать `payment_method_data`. |
| 400 | `invalid_request` | `description` | Длиннее 128 символов. | Сократить описание. |
| 400 | `invalid_request` | `metadata` | `metadata` — не объект, больше 16 ключей, длинное имя ключа или значение, значение — массив или объект. | Привести к правилам из раздела [metadata](https://avantpay.io/developers/api/#format-metadata). |
| 400 | `invalid_request` | `metadata.<ключ>` | Для магазина по договору с AvantPay обязательны ещё некоторые ключи `metadata`, а их нет. | Передать ключ, названный в `parameter`. |
| 400 | `invalid_request` | `order_id`, `webhook_url`, `expires_at`, `avantpay` | Передано поле, которого в запросе нет. | Номер заказа передать в `metadata.order_id`. Адрес уведомлений указать в личном кабинете. Срок оплаты не передавать: он 20 минут. |
| 400 | `not_supported` | имя поля | Передано поле, которого нет в API: `receipt`, `save_payment_method` со значением `true`, `payment_method_id`, `payment_method_data.card` и другие. | Убрать поле из запроса. |
| 400 | `invalid_request` | — | Тело запроса — не JSON. | Передать правильный JSON. |
| 401 | `invalid_credentials` | `Authorization` | Неверный ID магазина или ключ. | Проверить ключи. |
| 403 | `forbidden` | — | У ключа нет права «Платежи» или магазин не активен. | Написать в поддержку: support@avantpay.io. |
| 403 | `forbidden` | `confirmation.type` | Сценарий (обычно `qr`) не включён для магазина. | Использовать `redirect` или написать в поддержку. |
| 413 | `invalid_request` | — | Тело запроса больше 5 МБ. | Уменьшить тело. |
| 415 | `invalid_request` | — | Нет заголовка `Content-Type: application/json`. | Передать заголовок. |
| 429 | `too_many_requests` | — | Больше 50 запросов в секунду. | Подождать `retry_after` миллисекунд и повторить с тем же ключом. |
| 202 | — | — | Запрос с этим ключом ещё выполняется. Тело: `{"type": "processing", ...}`. | Подождать `retry_after` миллисекунд и повторить с тем же ключом. |
| 500 | `internal_server_error` | — | Сбой у AvantPay. Платёж мог создаться. | Повторить с тем же ключом. |

Если ответа нет совсем (таймаут, обрыв связи), поступите так же, как при ответе 500: повторите запрос с тем же `Idempotence-Key` и тем же телом. Если повтор вернул `"status": "canceled"`, платёж не создался до конца: создайте новый с новым ключом.

cURL:

```bash
curl https://api.avantpay.io/v3/payments \
  -X POST \
  -u "$AVANTPAY_SHOP_ID:$AVANTPAY_SECRET_KEY" \
  -H "Idempotence-Key: e1d2c3b4-a5f6-4789-8abc-def012345678" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": {
      "value": "1000.00",
      "currency": "RUB"
    },
    "capture": true,
    "confirmation": {
      "type": "redirect",
      "return_url": "https://example.com/orders/123"
    },
    "description": "Заказ №123",
    "metadata": {
      "email": "buyer@example.com",
      "order_id": "123"
    }
  }'
```

Python:

```python
import os

import requests

SHOP_ID = os.environ["AVANTPAY_SHOP_ID"]
SECRET_KEY = os.environ["AVANTPAY_SECRET_KEY"]


def create_payment(order_id: str, email: str, amount: str, return_url: str, idempotence_key: str) -> dict:
    response = requests.post(
        "https://api.avantpay.io/v3/payments",
        auth=(SHOP_ID, SECRET_KEY),
        headers={"Idempotence-Key": idempotence_key},
        json={
            "amount": {"value": amount, "currency": "RUB"},
            "capture": True,
            "confirmation": {"type": "redirect", "return_url": return_url},
            "description": f"Заказ №{order_id}",
            # email покупателя обязателен; покупатель из Telegram — f"{telegram_id}@telegram.org"
            "metadata": {"email": email, "order_id": order_id},
        },
        timeout=30,
    )
    if response.status_code != 200:
        raise RuntimeError(f"AvantPay: HTTP {response.status_code}: {response.text}")
    payment = response.json()
    # Повтор с тем же ключом может вернуть платёж, который не создался до конца (canceled, без ссылки):
    # тогда создайте новый платёж с новым ключом идемпотентности
    if payment["status"] != "pending" or "confirmation_url" not in payment.get("confirmation", {}):
        raise RuntimeError(f"AvantPay: платёж {payment['id']} в статусе {payment['status']}, ссылки на оплату нет")
    return payment  # покупателя — на ["confirmation"]["confirmation_url"]
```

Node.js:

```js
const AUTH =
  "Basic " +
  Buffer.from(`${process.env.AVANTPAY_SHOP_ID}:${process.env.AVANTPAY_SECRET_KEY}`).toString("base64");

export async function createPayment({ orderId, email, amount, returnUrl, idempotenceKey }) {
  const response = await fetch("https://api.avantpay.io/v3/payments", {
    method: "POST",
    headers: {
      Authorization: AUTH,
      "Idempotence-Key": idempotenceKey,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      amount: { value: amount, currency: "RUB" },
      capture: true,
      confirmation: { type: "redirect", return_url: returnUrl },
      description: `Заказ №${orderId}`,
      // email покупателя обязателен; покупатель из Telegram — `${telegramId}@telegram.org`
      metadata: { email, order_id: orderId },
    }),
    signal: AbortSignal.timeout(30000),
  });
  const text = await response.text();
  if (response.status !== 200) {
    throw new Error(`AvantPay: HTTP ${response.status}: ${text}`);
  }
  const payment = JSON.parse(text);
  // Повтор с тем же ключом может вернуть платёж, который не создался до конца (canceled, без ссылки):
  // тогда создайте новый платёж с новым ключом идемпотентности
  if (payment.status !== "pending" || !payment.confirmation?.confirmation_url) {
    throw new Error(`AvantPay: платёж ${payment.id} в статусе ${payment.status}, ссылки на оплату нет`);
  }
  return payment; // покупателя — на .confirmation.confirmation_url
}
```

PHP:

```php
<?php
function createPayment(string $orderId, string $email, string $amount, string $returnUrl, string $idempotenceKey): array
{
    $ch = curl_init('https://api.avantpay.io/v3/payments');
    curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_USERPWD => getenv('AVANTPAY_SHOP_ID') . ':' . getenv('AVANTPAY_SECRET_KEY'),
        CURLOPT_HTTPHEADER => [
            'Idempotence-Key: ' . $idempotenceKey,
            'Content-Type: application/json',
        ],
        CURLOPT_POSTFIELDS => json_encode([
            'amount' => ['value' => $amount, 'currency' => 'RUB'],
            'capture' => true,
            'confirmation' => ['type' => 'redirect', 'return_url' => $returnUrl],
            'description' => 'Заказ №' . $orderId,
            // email покупателя обязателен; покупатель из Telegram — $telegramId . '@telegram.org'
            'metadata' => ['email' => $email, 'order_id' => $orderId],
        ], JSON_UNESCAPED_UNICODE),
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 30,
    ]);
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($response === false || $httpCode !== 200) {
        throw new RuntimeException('AvantPay: HTTP ' . $httpCode . ': ' . $response);
    }
    $payment = json_decode($response, true);
    // Повтор с тем же ключом может вернуть платёж, который не создался до конца (canceled, без ссылки):
    // тогда создайте новый платёж с новым ключом идемпотентности
    if ($payment['status'] !== 'pending' || empty($payment['confirmation']['confirmation_url'])) {
        throw new RuntimeException('AvantPay: платёж ' . $payment['id'] . ' в статусе ' . $payment['status'] . ', ссылки на оплату нет');
    }
    return $payment; // покупателя — на ['confirmation']['confirmation_url']
}
```

Ответ — HTTP 200 и объект платежа:

```json
{
  "id": "3d6f0a8e-5b2c-4e1f-9a7d-2c4b6e8f0a1b",
  "status": "pending",
  "paid": false,
  "amount": {
    "value": "1000.00",
    "currency": "RUB"
  },
  "description": "Заказ №123",
  "recipient": {
    "account_id": "33661"
  },
  "created_at": "2026-10-18T10:15:30.123Z",
  "expires_at": "2026-10-18T10:35:30.123Z",
  "confirmation": {
    "type": "redirect",
    "confirmation_url": "https://avantpay.io/link/Aq91c7d",
    "return_url": "https://example.com/orders/123"
  },
  "test": false,
  "refundable": false,
  "metadata": {
    "email": "buyer@example.com",
    "order_id": "123"
  }
}
```

Ответ 400 — неверный email покупателя:

```json
{
  "type": "error",
  "id": "2b7d4e9a-1c3f-4a5b-8d6e-7f0a1b2c3d4e",
  "code": "invalid_request",
  "description": "metadata.email must be the buyer's email address (up to 254 characters), for a Telegram buyer use <id or username>@telegram.org",
  "parameter": "metadata.email"
}
```

## Получить платёж

```text
GET https://api.avantpay.io/v3/payments/{payment_id}
```

Возвращает [объект платежа](https://avantpay.io/developers/api/#payment_object) в текущем состоянии. Это главный способ узнать, оплачен ли платёж. Заголовок `Idempotence-Key` этому методу не нужен. Тела у запроса нет.

### Когда запрашивать

- Пришло [уведомление](https://avantpay.io/developers/webhooks/). Решение по заказу принимайте по ответу этого запроса.
- Покупатель вернулся на `return_url`. Покажите ему результат по статусу из ответа.
- Запрос на создание платежа закончился ошибкой 500 или без ответа.
- Для сверки по расписанию: уведомление может не дойти ([как сверяться](https://avantpay.io/developers/webhooks/#reconciliation)).

Если опрашиваете платёж, пока покупатель на странице оплаты, делайте это не чаще одного раза в 5 секунд и только пока статус `pending`.

### Параметры пути

| Параметр | Тип | Обязательно | Описание |
|---|---|---|---|
| `payment_id` | string | да | `id` платежа из ответа на его создание. Пример: `2f9b6c1e-4d7a-4c3b-9e8f-1a2b3c4d5e6f`. |

### Что делать по статусу

| `status` | Что делать |
|---|---|
| `pending` | Покупатель ещё не заплатил. Ждите уведомления. Заказ не выполняйте. |
| `succeeded` | Оплачен. Сверьте `amount` с суммой заказа и выполните заказ, если ещё не выполнили. |
| `canceled` | Не оплачен. Заказ не выполняйте. Для новой попытки оплаты создайте новый платёж с новым ключом идемпотентности. |

Подробнее — на странице [Статусы платежа](https://avantpay.io/developers/statuses/).

### Ошибки

| HTTP | `code` | Когда | Что делать |
|---|---|---|---|
| 404 | `not_found` | Платежа с таким `id` нет у вашего магазина. Платёж другого магазина тоже даёт 404. `parameter` — `payment_id`. | Проверить `id`. |
| 401 | `invalid_credentials` | Неверный ID магазина или ключ. | Проверить ключи. |
| 403 | `forbidden` | Магазин не активен. | Написать в поддержку: support@avantpay.io. |
| 429 | `too_many_requests` | Больше 50 запросов в секунду. | Повторить через `retry_after` миллисекунд. |
| 500 | `internal_server_error` | Сбой у AvantPay. | Повторить запрос позже. |

cURL:

```bash
curl https://api.avantpay.io/v3/payments/2f9b6c1e-4d7a-4c3b-9e8f-1a2b3c4d5e6f \
  -u "$AVANTPAY_SHOP_ID:$AVANTPAY_SECRET_KEY"
```

Python:

```python
import os
from typing import Optional

import requests

SHOP_ID = os.environ["AVANTPAY_SHOP_ID"]
SECRET_KEY = os.environ["AVANTPAY_SECRET_KEY"]


def get_payment(payment_id: str) -> Optional[dict]:
    """Платёж из API; None — у магазина нет такого платежа (404)"""
    response = requests.get(
        f"https://api.avantpay.io/v3/payments/{payment_id}",
        auth=(SHOP_ID, SECRET_KEY),
        timeout=30,
    )
    if response.status_code == 404:
        return None
    if response.status_code != 200:
        raise RuntimeError(f"AvantPay: HTTP {response.status_code}: {response.text}")
    return response.json()
```

Node.js:

```js
const AUTH =
  "Basic " +
  Buffer.from(`${process.env.AVANTPAY_SHOP_ID}:${process.env.AVANTPAY_SECRET_KEY}`).toString("base64");

// Платёж из API; null — у магазина нет такого платежа (404)
export async function getPayment(paymentId) {
  const response = await fetch(`https://api.avantpay.io/v3/payments/${encodeURIComponent(paymentId)}`, {
    headers: { Authorization: AUTH },
    signal: AbortSignal.timeout(30000),
  });
  if (response.status === 404) return null;
  const text = await response.text();
  if (response.status !== 200) {
    throw new Error(`AvantPay: HTTP ${response.status}: ${text}`);
  }
  return JSON.parse(text);
}
```

PHP:

```php
<?php
// Платёж из API; null — у магазина нет такого платежа (404)
function getPayment(string $paymentId): ?array
{
    $ch = curl_init('https://api.avantpay.io/v3/payments/' . rawurlencode($paymentId));
    curl_setopt_array($ch, [
        CURLOPT_USERPWD => getenv('AVANTPAY_SHOP_ID') . ':' . getenv('AVANTPAY_SECRET_KEY'),
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 30,
    ]);
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($httpCode === 404) {
        return null;
    }
    if ($response === false || $httpCode !== 200) {
        throw new RuntimeException('AvantPay: HTTP ' . $httpCode . ': ' . $response);
    }
    return json_decode($response, true);
}
```

Ответ — HTTP 200 и объект платежа. Здесь покупатель оплатил картой:

```json
{
  "id": "2f9b6c1e-4d7a-4c3b-9e8f-1a2b3c4d5e6f",
  "status": "succeeded",
  "paid": true,
  "amount": {
    "value": "1000.00",
    "currency": "RUB"
  },
  "income_amount": {
    "value": "975.00",
    "currency": "RUB"
  },
  "description": "Заказ №123",
  "recipient": {
    "account_id": "33661",
    "gateway_id": "6b1f3c0a-58e2-4f7d-9a41-0c2d7e5b8f93"
  },
  "payment_method": {
    "type": "bank_card",
    "id": "2f9b6c1e-4d7a-4c3b-9e8f-1a2b3c4d5e6f",
    "saved": false,
    "status": "inactive",
    "title": "Банковская карта"
  },
  "captured_at": "2026-10-18T10:17:02.418Z",
  "created_at": "2026-10-18T10:15:30.123Z",
  "expires_at": "2026-10-18T10:35:30.123Z",
  "confirmation": {
    "type": "redirect",
    "confirmation_url": "https://avantpay.io/link/Aq91c7d",
    "return_url": "https://example.com/orders/123"
  },
  "test": false,
  "refundable": false,
  "metadata": {
    "email": "buyer@example.com",
    "order_id": "123"
  }
}
```

## Список платежей

```text
GET https://api.avantpay.io/v3/payments
```

Возвращает платежи вашего магазина от новых к старым. Можно отфильтровать по дате, статусу и способу оплаты. Список отдаётся страницами. Заголовок `Idempotence-Key` этому методу не нужен. Тела у запроса нет.

### Параметры запроса

Все параметры необязательные. Передавайте их в строке запроса, каждый — не больше одного раза. Незнакомые параметры API не учитывает. Если в дате нет часового пояса, это время по UTC.

| Параметр | Тип | Обязательно | Описание |
|---|---|---|---|
| `limit` | integer | нет | Сколько платежей на странице: от 1 до 100. По умолчанию 10. Пример: `10`. |
| `cursor` | string | нет | Значение `next_cursor` из предыдущего ответа — чтобы получить следующую страницу. Передавайте как есть. Пример: `MjAyNi0xMC0xN1QxODozOTo1NS44NzFa`. |
| `status` | string | нет | Только платежи с этим статусом: `pending`, `succeeded` или `canceled`. Пример: `succeeded`. |
| `payment_method` | string | нет | Только платежи этим способом: `sbp` или `bank_card`. Пример: `sbp`. |
| `created_at.gte` | string | нет | Созданы в этот момент или позже. Дата ISO 8601. Пример: `2026-10-01T00:00:00.000Z`. |
| `created_at.gt` | string | нет | Созданы позже этого момента. Пример: `2026-10-01T00:00:00.000Z`. |
| `created_at.lte` | string | нет | Созданы в этот момент или раньше. Пример: `2026-10-31T23:59:59.999Z`. |
| `created_at.lt` | string | нет | Созданы раньше этого момента. Пример: `2026-11-01T00:00:00.000Z`. |
| `captured_at.gte` | string | нет | Оплачены в этот момент или позже. Пример: `2026-10-01T00:00:00.000Z`. |
| `captured_at.gt` | string | нет | Оплачены позже этого момента. Пример: `2026-10-01T00:00:00.000Z`. |
| `captured_at.lte` | string | нет | Оплачены в этот момент или раньше. Пример: `2026-10-31T23:59:59.999Z`. |
| `captured_at.lt` | string | нет | Оплачены раньше этого момента. Пример: `2026-11-01T00:00:00.000Z`. |

Фильтра по номеру заказа нет: запрос с `order_id` получит ошибку 400 `not_supported`. Номер заказа храните в `metadata.order_id`, а платёж получайте по `id`, который сохранили в заказе: [`GET /v3/payments/{payment_id}`](https://avantpay.io/developers/api/#get_payment).

### Ответ

| Поле | Тип | Есть всегда | Описание |
|---|---|---|---|
| `type` | string | да | Всегда `list`. Пример: `"list"`. |
| `items` | array | да | Платежи — [объекты платежа](https://avantpay.io/developers/api/#payment_object), от новых к старым. Если ничего не нашлось — пустой массив `[]`. |
| `next_cursor` | string | нет | Курсор следующей страницы. Нет на последней странице. Пример: `"MjAyNi0xMC0xN1QxODozOTo1NS44NzFa"`. |

### Как получить все страницы

1. Отправьте запрос с нужными фильтрами.
2. Если в ответе есть `next_cursor`, повторите запрос с теми же фильтрами и параметром `cursor=<значение next_cursor>`.
3. Повторяйте, пока в ответе не будет `next_cursor`.

Новые платежи, созданные во время обхода, не сдвигают страницы: платежи не повторяются и не пропадают. Примеры на Python, Node.js и PHP обходят все страницы сами.

### Ошибки

| HTTP | `code` | Когда | Что делать |
|---|---|---|---|
| 400 | `invalid_request` | `limit` — не целое число от 1 до 100, `cursor` — не из `next_cursor`, дата не в формате ISO 8601, `status` — незнакомое значение, параметр передан дважды. Имя параметра — в `parameter`. | Исправить параметр. |
| 400 | `not_supported` | Передан `order_id`. `parameter` — `order_id`. | Убрать параметр. Получать платёж по `id` из заказа. |
| 401 | `invalid_credentials` | Неверный ID магазина или ключ. | Проверить ключи. |
| 403 | `forbidden` | Магазин не активен. | Написать в поддержку: support@avantpay.io. |
| 429 | `too_many_requests` | Больше 50 запросов в секунду. | Повторить через `retry_after` миллисекунд. |
| 500 | `internal_server_error` | Сбой у AvantPay. | Повторить запрос позже. |

Оплаченные платежи с 1 октября 2026 года, по 2 на странице:

cURL:

```bash
curl "https://api.avantpay.io/v3/payments?status=succeeded&created_at.gte=2026-10-01T00:00:00.000Z&limit=2" \
  -u "$AVANTPAY_SHOP_ID:$AVANTPAY_SECRET_KEY"
```

Python:

```python
import os
from typing import Iterator

import requests

SHOP_ID = os.environ["AVANTPAY_SHOP_ID"]
SECRET_KEY = os.environ["AVANTPAY_SECRET_KEY"]


def list_payments(filters: dict) -> Iterator[dict]:
    """Платежи по фильтрам со всех страниц: list_payments({"status": "succeeded", "created_at.gte": "…"})"""
    params = {**filters, "limit": 100}
    while True:
        response = requests.get(
            "https://api.avantpay.io/v3/payments",
            auth=(SHOP_ID, SECRET_KEY),
            params=params,
            timeout=30,
        )
        if response.status_code != 200:
            raise RuntimeError(f"AvantPay: HTTP {response.status_code}: {response.text}")
        page = response.json()
        yield from page["items"]
        if "next_cursor" not in page:
            return
        params = {**filters, "limit": 100, "cursor": page["next_cursor"]}
```

Node.js:

```js
const AUTH =
  "Basic " +
  Buffer.from(`${process.env.AVANTPAY_SHOP_ID}:${process.env.AVANTPAY_SECRET_KEY}`).toString("base64");

// Платежи по фильтрам со всех страниц: for await (const p of listPayments({ status: "succeeded" })) { … }
export async function* listPayments(filters = {}) {
  let cursor;
  do {
    const params = new URLSearchParams({ ...filters, limit: "100", ...(cursor && { cursor }) });
    const response = await fetch(`https://api.avantpay.io/v3/payments?${params}`, {
      headers: { Authorization: AUTH },
      signal: AbortSignal.timeout(30000),
    });
    const text = await response.text();
    if (response.status !== 200) {
      throw new Error(`AvantPay: HTTP ${response.status}: ${text}`);
    }
    const page = JSON.parse(text);
    yield* page.items;
    cursor = page.next_cursor;
  } while (cursor);
}
```

PHP:

```php
<?php
// Платежи по фильтрам со всех страниц: foreach (listPayments(['status' => 'succeeded']) as $payment) { … }
function listPayments(array $filters): Generator
{
    $cursor = null;
    do {
        $params = $filters + ['limit' => 100] + ($cursor !== null ? ['cursor' => $cursor] : []);
        $ch = curl_init('https://api.avantpay.io/v3/payments?' . http_build_query($params));
        curl_setopt_array($ch, [
            CURLOPT_USERPWD => getenv('AVANTPAY_SHOP_ID') . ':' . getenv('AVANTPAY_SECRET_KEY'),
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT => 30,
        ]);
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($response === false || $httpCode !== 200) {
            throw new RuntimeException('AvantPay: HTTP ' . $httpCode . ': ' . $response);
        }
        $page = json_decode($response, true);
        foreach ($page['items'] as $payment) {
            yield $payment;
        }
        $cursor = $page['next_cursor'] ?? null;
    } while ($cursor !== null);
}
```

Ответ — HTTP 200 и объект списка:

```json
{
  "type": "list",
  "items": [
    {
      "id": "2f9b6c1e-4d7a-4c3b-9e8f-1a2b3c4d5e6f",
      "status": "succeeded",
      "paid": true,
      "amount": {
        "value": "1000.00",
        "currency": "RUB"
      },
      "income_amount": {
        "value": "975.00",
        "currency": "RUB"
      },
      "description": "Заказ №123",
      "recipient": {
        "account_id": "33661",
        "gateway_id": "6b1f3c0a-58e2-4f7d-9a41-0c2d7e5b8f93"
      },
      "payment_method": {
        "type": "bank_card",
        "id": "2f9b6c1e-4d7a-4c3b-9e8f-1a2b3c4d5e6f",
        "saved": false,
        "status": "inactive",
        "title": "Банковская карта"
      },
      "captured_at": "2026-10-18T10:17:02.418Z",
      "created_at": "2026-10-18T10:15:30.123Z",
      "expires_at": "2026-10-18T10:35:30.123Z",
      "confirmation": {
        "type": "redirect",
        "confirmation_url": "https://avantpay.io/link/Aq91c7d",
        "return_url": "https://example.com/orders/123"
      },
      "test": false,
      "refundable": false,
      "metadata": {
        "email": "buyer@example.com",
        "order_id": "123"
      }
    },
    {
      "id": "c4a8e2f1-9b3d-4f6a-8e1c-7d2b5a9f3e60",
      "status": "succeeded",
      "paid": true,
      "amount": {
        "value": "250.00",
        "currency": "RUB"
      },
      "income_amount": {
        "value": "243.75",
        "currency": "RUB"
      },
      "description": "Заказ №122",
      "recipient": {
        "account_id": "33661",
        "gateway_id": "6b1f3c0a-58e2-4f7d-9a41-0c2d7e5b8f93"
      },
      "payment_method": {
        "type": "sbp",
        "id": "c4a8e2f1-9b3d-4f6a-8e1c-7d2b5a9f3e60",
        "saved": false,
        "status": "inactive",
        "title": "СБП"
      },
      "captured_at": "2026-10-17T18:41:09.004Z",
      "created_at": "2026-10-17T18:39:55.871Z",
      "expires_at": "2026-10-17T18:59:55.871Z",
      "confirmation": {
        "type": "redirect",
        "confirmation_url": "https://avantpay.io/link/Pq28vXn",
        "return_url": "https://example.com/orders/122"
      },
      "test": false,
      "refunded_amount": {
        "value": "50.00",
        "currency": "RUB"
      },
      "refundable": false,
      "metadata": {
        "email": "buyer@example.com",
        "order_id": "122"
      }
    }
  ],
  "next_cursor": "MjAyNi0xMC0xN1QxODozOTo1NS44NzFafGM0YThlMmYxLTliM2QtNGY2YS04ZTFjLTdkMmI1YTlmM2U2MA"
}
```

Ответ 400 — фильтра по номеру заказа нет:

```json
{
  "type": "error",
  "id": "4c2e8a1f-6b3d-4f5a-9e7c-0b1d2e3f4a5b",
  "code": "not_supported",
  "description": "order_id is not supported: save the payment id in your order and get the payment with GET /v3/payments/{payment_id}",
  "parameter": "order_id"
}
```

## Объект уведомления

Уведомление — POST-запрос от AvantPay на ваш сервер, когда платёж оплачен или отменён. Адрес и события задаются в личном кабинете: **Ещё → Разработчикам → HTTP-уведомления**. Как включить, обработать и проверить уведомление — на странице [Уведомления](https://avantpay.io/developers/webhooks/).

Запрос приходит с заголовком `Content-Type: application/json` и телом из трёх полей:

| Поле | Тип | Есть всегда | Описание |
|---|---|---|---|
| `type` | string | да | Всегда `notification`. Пример: `"notification"`. |
| `event` | string | да | Событие: `payment.succeeded` или `payment.canceled`. Пример: `"payment.succeeded"`. |
| `object` | object | да | [Объект платежа](https://avantpay.io/developers/api/#payment_object) на момент события — такой же, как в ответе на `GET /v3/payments/{payment_id}`. |

### События

| `event` | В личном кабинете | Когда приходит |
|---|---|---|
| `payment.succeeded` | Платёж оплачен | Платёж перешёл в статус `succeeded`. Может прийти и после `payment.canceled` — это [поздняя оплата](https://avantpay.io/developers/statuses/#late-payment). |
| `payment.canceled` | Платёж отменён | Платёж перешёл в статус `canceled`: истёк срок оплаты, банк отказал или сработала проверка. |

Если пришло уведомление с другим `event`, ответьте 200 и ничего не делайте.

### Заголовки

| Заголовок | Что в нём |
|---|---|
| `Signature-Timestamp` | Время отправки, Unix-время в секундах. |
| `Signature` | Подпись: `v1=` и HMAC-SHA256 строки `<Signature-Timestamp>.<тело запроса>` секретным ключом API в шестнадцатеричном виде. Как проверить — в разделе [Подпись](https://avantpay.io/developers/webhooks/#signature). |

Ответьте кодом 200 не позже чем через 10 секунд. Иначе AvantPay повторит уведомление ([расписание повторов](https://avantpay.io/developers/webhooks/#retries)).

Платёж отменён: покупатель не заплатил вовремя.

```json
{
  "type": "notification",
  "event": "payment.canceled",
  "object": {
    "id": "8d0e4b52-7c19-4a6e-b3f1-5e2a9c7d1b40",
    "status": "canceled",
    "paid": false,
    "amount": {
      "value": "500.00",
      "currency": "RUB"
    },
    "description": "Заказ №125",
    "recipient": {
      "account_id": "33661"
    },
    "created_at": "2026-10-18T12:00:00.000Z",
    "expires_at": "2026-10-18T12:20:00.000Z",
    "confirmation": {
      "type": "redirect",
      "confirmation_url": "https://avantpay.io/link/Zt5mW2r",
      "return_url": "https://example.com/orders/125"
    },
    "test": false,
    "refundable": false,
    "metadata": {
      "email": "buyer@example.com",
      "order_id": "125"
    },
    "cancellation_details": {
      "party": "avantpay",
      "reason": "expired_on_confirmation"
    }
  }
}
```

Заголовки запроса:

```http
POST /avantpay/webhook HTTP/1.1
Host: example.com
Content-Type: application/json
Signature-Timestamp: 1792324800
Signature: v1=07181d18b6de6cfe0c882fd02f7e40c8c0e735f19dc67062c39f57c8d75c995b
```

Пример уведомления `payment.succeeded` — в [быстром старте](https://avantpay.io/developers/quick-start/).

---

Страница на сайте: https://avantpay.io/developers/api/
Вся документация одним файлом: https://avantpay.io/developers/llms-full.txt
