Справочник 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 магазина и секретный ключ
- Войдите в личный кабинет.
- Откройте Ещё → Разработчикам → API-ключ (открыть сразу). На телефоне вместо «Ещё» — «Меню».
- ID магазина и адрес API — в блоке «Авторизация запросов».
- Нажмите Создать ключ. Ключ показывается целиком только один раз. Скопируйте его сразу.
Если раздела «Разработчикам» нет, попросите владельца магазина добавить вас в разделе «Пользователи» с ролью «Разработчик».
Как хранить ключ
- Храните ключ в переменных окружения или в хранилище секретов сервера.
- Не кладите ключ в код, в репозиторий, в логи и в письма.
- Если ключ мог утечь, нажмите Перевыпустить в том же разделе. Старый ключ сразу перестанет работать. Замените ключ на сервере.
- Тем же ключом AvantPay подписывает уведомления. После перевыпуска уведомления подписываются новым ключом.
Права ключа
В блоке «Права ключа» видно, что можно делать этим ключом. Для создания платежей нужно право «Платежи».
- Права включает поддержка AvantPay. В личном кабинете их можно только посмотреть. Чтобы включить право, напишите на [email protected].
- Без права «Платежи» запрос
POST /v3/paymentsполучит ошибку 403forbidden. - Запросы
GET(получить платёж, список платежей) работают с любым действующим ключом магазина.
Лимит запросов
- Не больше 50 запросов в секунду на магазин. Сверх лимита API ответит 429
too_many_requests. - В ответе 429 есть поле
retry_after— через сколько миллисекунд повторить, и заголовокRetry-After— то же в секундах. - Повторяйте запрос на создание платежа после 429 с тем же
Idempotence-Key.
Проверка ключей: запрос возвращает последний платёж магазина и ничего не меняет.
curl "https://api.avantpay.io/v3/payments?limit=1" \
-u "$AVANTPAY_SHOP_ID:$AVANTPAY_SECRET_KEY"
Ответ 200 — ключи верные. Ответ 401 invalid_credentials — неверный ID магазина или ключ:
{
"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:
Authorization: Basic MzM2NjE6dGVzdF9zZWNyZXRfa2V5
Здесь MzM2NjE6dGVzdF9zZWNyZXRfa2V5 — это Base64 от строки 33661:test_secret_key.
Ответ 429 — больше 50 запросов в секунду:
{
"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
}
Ошибки аутентификации
| HTTP | code | Когда | Что делать |
|---|---|---|---|
| 401 | invalid_credentials | Нет заголовка Authorization, неверный ID магазина или ключ, ключ перевыпущен или удалён, заголовок Bearer. parameter — Authorization. | Проверьте ID магазина и ключ. Если ключ потерян — перевыпустите его. |
| 403 | forbidden | У ключа нет права «Платежи» или магазин не активен. | Напишите в поддержку: [email protected]. |
| 429 | too_many_requests | С вашего IP-адреса за минуту пришло больше 20 запросов с неверными ключами. До конца этой минуты API отвечает 429 на все запросы с этого адреса. | Исправьте ключи и повторите через retry_after миллисекунд. |
Идемпотентность
Ключ идемпотентности — заголовок 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.
Правила
- Для каждой новой попытки оплаты создавайте новый ключ.
- Создайте ключ до первого запроса и сохраните его в заказе. Тогда при повторе, даже после перезапуска сервера, вы возьмёте тот же ключ.
- Повторяйте запрос с тем же ключом и тем же телом, если ответа нет, запрос оборвался по таймауту, пришёл ответ 500, 429 или 202. Повторяйте 1–2 минуты. Потом покажите покупателю «Платёж создаётся» и продолжайте повторять в фоне с тем же ключом, но не дольше 24 часов.
- Никогда не используйте один ключ для двух разных платежей. Тот же ключ с другим телом запроса (например, с другой суммой) — ошибка 400, второй платёж не создастся.
- Повтор с тем же ключом позже чем через 24 часа — ошибка 400. Чтобы узнать, чем кончился тот запрос, запросите платёж по
idиз заказа. Еслиidв заказе нет (ответ так и не пришёл), найдите платёж в списке платежей за время создания: у него в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.
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": "[email protected]",
"order_id": "2"
}
}'
Ответ 202 — запрос с этим ключом ещё выполняется:
{
"type": "processing",
"description": "Request accepted",
"retry_after": 2000
}
Ответ 400 на тот же ключ с другим телом:
{
"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. Все коды — в разделе Ошибки. - Если у поля нет значения, поля нет в ответе. Значения
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/falseAPI сохранит строкой:1042вернётся как"1042". - Ключ со значением
nullAPI не сохраняет. - Массив или вложенный объект в значении — ошибка 400.
metadataвозвращается в объекте платежа и в уведомлениях.- Не храните в
metadataсекреты и данные карт.
Сумма:
{
"value": "100.00",
"currency": "RUB"
}
metadata с email покупателя и номером заказа:
{
"email": "[email protected]",
"order_id": "123",
"customer_id": "1042"
}
Покупатель из Telegram:
{
"email": "[email protected]",
"order_id": "124"
}
Ошибки
Если запрос не выполнен, API отвечает кодом HTTP 400 или выше и объектом ошибки. Объект ошибки приходит на любой ответ 4xx и 5xx, в том числе на неверный адрес (404), неверный метод HTTP (405) и запрос без JSON (415).
Объект ошибки
ID ошибки. Укажите его, если пишете в поддержку.
"6daac9fa-342d-4264-91c5-b5eafd1a0010"Код ошибки из таблицы ниже. По нему решайте, что делать.
"invalid_request"Что не так и как исправить. На английском. Пишите в логи, покупателю не показывайте.
"Invalid request"Какое поле, заголовок или параметр неверны. Например: amount.value, metadata.email, Idempotence-Key, Authorization, payment_id, limit.
"metadata.email"Через сколько миллисекунд повторить запрос. Есть у ответов 429.
1000Ошибка 400 — в запросе нет email покупателя:
{
"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:
{
"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:
{
"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
}
Коды
| 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 не включён для магазина. | Написать в поддержку: [email protected]. |
| 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 часов. |
Не создавайте платёж с новым ключом, пока не знаете, чем кончился прежний запрос. Иначе покупатель может заплатить дважды.
Объект платежа
Объект платежа — это платёж и всё, что о нём известно: сумма, статус, способ оплаты, ссылка на оплату, email покупателя.
API возвращает этот объект:
- в ответе на создание платежа —
POST /v3/payments; - в ответе на запрос платежа —
GET /v3/payments/{payment_id}; - в поле
itemsсписка платежей —GET /v3/payments; - в поле
objectуведомления.
Правила чтения объекта
- Если у поля нет значения, поля нет в объекте. Значения
nullне бывает. Перед чтением необязательного поля проверьте, что оно есть. - В объекте могут появиться новые поля. Код не должен падать на незнакомом поле или незнакомом значении.
- Выполняйте заказ, только если
statusравенsucceeded, аamount.valueиamount.currencyравны сумме и валюте заказа (правила). - Суммы — строки с двумя знаками после точки:
"100.00". Даты — ISO 8601 по UTC с миллисекундами:"2026-10-18T10:15:30.123Z".
Поля
ID платежа, UUID из 36 символов. Сохраните его в заказе: по нему вы получите платёж.
"2f9b6c1e-4d7a-4c3b-9e8f-1a2b3c4d5e6f"Статус платежа: pending, succeeded или canceled. Что делать в каждом — на странице Статусы платежа.
"succeeded"Сумма платежа — ровно та, что вы передали при создании. Покупатель платит эту сумму.
Сколько получит магазин: amount минус комиссия AvantPay. Бывает только у платежей со статусом succeeded. Может не быть и у них, например пока AvantPay проверяет оплату. Не решайте по этому полю, оплачен ли платёж.
Описание, которое вы передали при создании. Есть, только если вы его передали.
"Заказ №123"Получатель платежа — ваш магазин.
Способ оплаты. Появляется, когда способ выбран: сразу, если вы передали payment_method_data, иначе — когда покупатель выберет способ на странице оплаты. Если магазину подключены другие способы, type может быть и другим — на незнакомом значении код не должен падать.
Вложенные параметры
ID способа оплаты. Всегда равен id платежа: способы оплаты не сохраняются.
"2f9b6c1e-4d7a-4c3b-9e8f-1a2b3c4d5e6f"Статус способа оплаты. Всегда inactive: способ не сохранён.
"inactive"ID способа оплаты. Всегда равен id платежа: способы оплаты не сохраняются.
"2f9b6c1e-4d7a-4c3b-9e8f-1a2b3c4d5e6f"Статус способа оплаты. Всегда inactive: способ не сохранён.
"inactive"ID способа оплаты. Всегда равен id платежа: способы оплаты не сохраняются.
"2f9b6c1e-4d7a-4c3b-9e8f-1a2b3c4d5e6f"Статус способа оплаты. Всегда inactive: способ не сохранён.
"inactive"Когда платёж оплачен. Бывает только у платежей со статусом succeeded.
"2026-10-18T10:17:02.418Z"До какого момента покупатель может заплатить: 20 минут после создания платежа. Потом платёж станет canceled, но не в ту же секунду: сначала AvantPay проверит, не прошла ли оплата. Обычно canceled приходит в течение 10 минут после expires_at, в редких случаях — до 2 часов.
"2026-10-18T10:35:30.123Z"Как покупатель платит — сценарий, который вы передали при создании.
Вложенные параметры
Ссылка на страницу оплаты. Отправьте покупателя по ней, только если status равен pending. Может не быть у платежа, который отменён при создании.
"https://avantpay.io/link/Aq91c7d"Адрес возврата покупателя, который вы передали.
"https://example.com/orders/123"Ссылка для QR-кода СБП. Сделайте из неё QR-код, на телефоне ссылку можно просто открыть. Сразу после создания здесь может быть ссылка на страницу оплаты AvantPay (https://avantpay.io/link/…): QR-код из неё откроет страницу оплаты в браузере телефона. Потом значение может смениться на ссылку СБП (https://qr.nspk.ru/…). Показывайте QR-код из последнего полученного объекта.
"https://qr.nspk.ru/AD10006M8KHABCDEFG"Сколько денег вернули покупателю. Есть, только если был возврат. Вернуть деньги можно только в личном кабинете. Статус после возврата остаётся succeeded.
Можно ли вернуть платёж через API. Всегда false: вернуть деньги можно только в личном кабинете.
falseВаши данные из запроса на создание: email покупателя, номер заказа и другие ключи, которые вы передали. Значения — строки.
Вложенные параметры
Кто отменил платёж и почему. Бывает только у платежей со статусом canceled.
Вложенные параметры
Кто отменил: merchant, avantpay или payment_network. Что значит каждое — на странице Статусы платежа.
"avantpay"Причина отмены. Все причины — на странице Статусы платежа.
"expired_on_confirmation"- Оплачен
- Новый
- Отменён
- Возврат
Покупатель оплатил картой:
{
"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": "[email protected]",
"order_id": "123"
}
}
Только что созданный платёж. Способ оплаты не передан, поэтому нет payment_method и recipient.gateway_id:
{
"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": "[email protected]",
"order_id": "127"
}
}
Покупатель не заплатил до expires_at:
{
"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": "[email protected]",
"order_id": "125"
},
"cancellation_details": {
"party": "avantpay",
"reason": "expired_on_confirmation"
}
}
Покупатель заплатил по СБП, часть денег ему вернули в личном кабинете. Статус остался succeeded:
{
"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": "[email protected]",
"order_id": "122"
}
}
Создать платёж
https://api.avantpay.io/v3/paymentsСоздаёт платёж и возвращает объект платежа со статусом pending и ссылкой на оплату confirmation.confirmation_url.
Передайте его в metadata.email. Покупатель из Telegram — <id или username>@telegram.org, например [email protected].
Заголовки
| Заголовок | Обязательно | Значение |
|---|---|---|
Authorization | да | HTTP Basic: ID магазина и секретный ключ. В cURL — -u "$AVANTPAY_SHOP_ID:$AVANTPAY_SECRET_KEY". |
Idempotence-Key | да | Ключ идемпотентности: уникальная строка до 64 символов, лучше UUID. Новый для каждой попытки оплаты, тот же при повторе запроса. Подробнее |
Content-Type | да | application/json |
Параметры запроса
Сумма платежа. Покупатель заплатит ровно её. Комиссию AvantPay платит магазин: она вычитается из этой суммы.
Вложенные параметры
Как покупатель будет платить.
Вложенные параметры
redirect — покупатель переходит на страницу оплаты AvantPay.
"redirect"Куда вернуть покупателя после оплаты или отказа от неё. Адрес http:// или https://, до 2048 символов. AvantPay открывает его как есть, без параметров, поэтому укажите в нём свой заказ.
"https://example.com/orders/123"qr — вы показываете покупателю QR-код СБП. Только вместе с "payment_method_data": {"type": "sbp"} (подробнее).
"qr"Куда вернуть покупателя после оплаты или отказа от неё. Адрес http:// или https://, до 2048 символов. AvantPay открывает его как есть, без параметров, поэтому укажите в нём свой заказ.
"https://example.com/orders/123"Описание платежа, до 128 символов. Его видит покупатель на странице оплаты и вы в личном кабинете.
"Заказ №123"Способ оплаты. Если не передать, покупатель выберет способ на странице оплаты. Способ должен быть включён у магазина.
Вложенные параметры
ID способа оплаты магазина, до 64 символов. Нужен, только если у магазина включено несколько способов одного типа: тогда на sbp или bank_card API ответит 400 и перечислит ID в description.
"sbp-2"Ваши данные к платежу. Обязателен ключ email. Всего до 16 ключей, имя ключа до 32 символов, значение — строка до 512 символов. Вернутся в объекте платежа и в уведомлениях. Подробнее — в разделе metadata.
Вложенные параметры
Email покупателя, до 254 символов. Покупатель из Telegram — <id или username>@telegram.org, например [email protected]. Нет email или адрес неверный — ошибка 400 invalid_request, parameter — metadata.email.
"[email protected]"Ваш номер заказа. Вернётся в объекте платежа и в уведомлениях. API не проверяет, что номер уникален: от двойного платежа защищает ключ идемпотентности.
"123"Варианты
Покупатель выбирает способ сам
Не передавайте payment_method_data. На странице оплаты покупатель увидит все способы, которые включены у магазина. В ответе не будет payment_method и recipient.gateway_id — они появятся, когда покупатель выберет способ.
Сразу СБП или карта
Передайте "payment_method_data": {"type": "sbp"} или "payment_method_data": {"type": "bank_card"}. Покупатель сразу попадёт на оплату этим способом.
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": "[email protected]",
"order_id": "126"
}
}'
Ответ:
{
"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": "[email protected]",
"order_id": "126"
}
}
Здесь покупатель пришёл из Telegram: его email — [email protected].
QR-код СБП
Вы показываете покупателю QR-код, он сканирует его телефоном и платит. Правила:
- сценарий
qrработает только с"payment_method_data": {"type": "sbp"}; return_urlобязателен, как и уredirect;- сценарий включает поддержка AvantPay. Если он не включён, API ответит 403
forbidden,"parameter": "confirmation.type".
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": "[email protected]",
"order_id": "124"
}
}'
Ответ:
{
"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": "[email protected]",
"order_id": "124"
}
}
Сделайте QR-код из строки confirmation.confirmation_data и покажите его покупателю. На телефоне эту ссылку можно просто открыть.
Сразу после создания в confirmation_data может быть ссылка на страницу оплаты AvantPay, как в примере выше: QR-код из неё откроет страницу оплаты в браузере телефона. Потом значение может смениться на ссылку СБП (https://qr.nspk.ru/…). Показывайте QR-код из последнего полученного объекта платежа.
Что сделать после ответа
- Сохраните
idплатежа в заказе. - Если
statusравенpendingи естьconfirmation.confirmation_url, отправьте покупателя по этой ссылке. Если повтор запроса вернулcanceledбез ссылки, платёж не создался до конца: создайте новый с новым ключом идемпотентности (подробнее). - Дождитесь уведомления и проверьте платёж запросом
GET /v3/payments/{payment_id}.
Если запрос оборвался, пришёл ответ 500, 429 или 202, повторите его с тем же Idempotence-Key и тем же телом. Повторяйте 1–2 минуты. Потом покажите покупателю «Платёж создаётся» и продолжайте повторять в фоне с тем же ключом, но не дольше 24 часов. Примеры на Python, Node.js и PHP так и устроены: ключ идемпотентности они получают от вас, а перед отправкой покупателя на оплату проверяют status и ссылку.
- cURL
- Python
- Node.js
- PHP
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": "[email protected]",
"order_id": "123"
}
}'
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"]
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
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 и объект платежа:
{
"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": "[email protected]",
"order_id": "123"
}
}
Ответ 400 — неверный email покупателя:
{
"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"
}
Ошибки
Формат ошибок и общие коды — в разделе Ошибки. Ошибки этого метода:
| 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 | — | У магазина не включён ни один способ оплаты. | Написать в поддержку: [email protected]. |
| 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. |
| 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 | — | У ключа нет права «Платежи» или магазин не активен. | Написать в поддержку: [email protected]. |
| 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", платёж не создался до конца: создайте новый с новым ключом.
Получить платёж
https://api.avantpay.io/v3/payments/{payment_id}Возвращает объект платежа в текущем состоянии. Это главный способ узнать, оплачен ли платёж. Заголовок Idempotence-Key этому методу не нужен. Тела у запроса нет.
Когда запрашивать
- Пришло уведомление. Решение по заказу принимайте по ответу этого запроса.
- Покупатель вернулся на
return_url. Покажите ему результат по статусу из ответа. - Запрос на создание платежа закончился ошибкой 500 или без ответа.
- Для сверки по расписанию: уведомление может не дойти (как сверяться).
Если опрашиваете платёж, пока покупатель на странице оплаты, делайте это не чаще одного раза в 5 секунд и только пока статус pending.
Параметры пути
id платежа из ответа на его создание.
2f9b6c1e-4d7a-4c3b-9e8f-1a2b3c4d5e6fЧто делать по статусу
status | Что делать |
|---|---|
pending | Покупатель ещё не заплатил. Ждите уведомления. Заказ не выполняйте. |
succeeded | Оплачен. Сверьте amount с суммой заказа и выполните заказ, если ещё не выполнили. |
canceled | Не оплачен. Заказ не выполняйте. Для новой попытки оплаты создайте новый платёж с новым ключом идемпотентности. |
Подробнее — на странице Статусы платежа.
- cURL
- Python
- Node.js
- PHP
curl https://api.avantpay.io/v3/payments/2f9b6c1e-4d7a-4c3b-9e8f-1a2b3c4d5e6f \
-u "$AVANTPAY_SHOP_ID:$AVANTPAY_SECRET_KEY"
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()
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
// Платёж из 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 и объект платежа. Здесь покупатель оплатил картой:
{
"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": "[email protected]",
"order_id": "123"
}
}
Ошибки
| HTTP | code | Когда | Что делать |
|---|---|---|---|
| 404 | not_found | Платежа с таким id нет у вашего магазина. Платёж другого магазина тоже даёт 404. parameter — payment_id. | Проверить id. |
| 401 | invalid_credentials | Неверный ID магазина или ключ. | Проверить ключи. |
| 403 | forbidden | Магазин не активен. | Написать в поддержку: [email protected]. |
| 429 | too_many_requests | Больше 50 запросов в секунду. | Повторить через retry_after миллисекунд. |
| 500 | internal_server_error | Сбой у AvantPay. | Повторить запрос позже. |
Список платежей
https://api.avantpay.io/v3/paymentsВозвращает платежи вашего магазина от новых к старым. Можно отфильтровать по дате, статусу и способу оплаты. Список отдаётся страницами. Заголовок Idempotence-Key этому методу не нужен. Тела у запроса нет.
Параметры запроса
Все параметры необязательные. Передавайте их в строке запроса, каждый — не больше одного раза. Незнакомые параметры API не учитывает. Если в дате нет часового пояса, это время по UTC.
Значение next_cursor из предыдущего ответа — чтобы получить следующую страницу. Передавайте как есть.
MjAyNi0xMC0xN1QxODozOTo1NS44NzFaТолько платежи с этим статусом: pending, succeeded или canceled.
succeededСозданы в этот момент или позже. Дата ISO 8601.
2026-10-01T00:00:00.000ZСозданы в этот момент или раньше.
2026-10-31T23:59:59.999ZОплачены в этот момент или позже.
2026-10-01T00:00:00.000ZОплачены в этот момент или раньше.
2026-10-31T23:59:59.999ZФильтра по номеру заказа нет: запрос с order_id получит ошибку 400 not_supported. Номер заказа храните в metadata.order_id, а платёж получайте по id, который сохранили в заказе: GET /v3/payments/{payment_id}.
Ответ
Платежи — объекты платежа, от новых к старым. Если ничего не нашлось — пустой массив [].
Курсор следующей страницы. Нет на последней странице.
"MjAyNi0xMC0xN1QxODozOTo1NS44NzFa"Как получить все страницы
- Отправьте запрос с нужными фильтрами.
- Если в ответе есть
next_cursor, повторите запрос с теми же фильтрами и параметромcursor=<значение next_cursor>. - Повторяйте, пока в ответе не будет
next_cursor.
Новые платежи, созданные во время обхода, не сдвигают страницы: платежи не повторяются и не пропадают. Примеры на Python, Node.js и PHP обходят все страницы сами.
Оплаченные платежи с 1 октября 2026 года, по 2 на странице:
- cURL
- Python
- Node.js
- PHP
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"
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"]}
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
// Платежи по фильтрам со всех страниц: 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 и объект списка:
{
"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": "[email protected]",
"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": "[email protected]",
"order_id": "122"
}
}
],
"next_cursor": "MjAyNi0xMC0xN1QxODozOTo1NS44NzFafGM0YThlMmYxLTliM2QtNGY2YS04ZTFjLTdkMmI1YTlmM2U2MA"
}
Ответ 400 — фильтра по номеру заказа нет:
{
"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"
}
Ошибки
| 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 | Магазин не активен. | Написать в поддержку: [email protected]. |
| 429 | too_many_requests | Больше 50 запросов в секунду. | Повторить через retry_after миллисекунд. |
| 500 | internal_server_error | Сбой у AvantPay. | Повторить запрос позже. |
Объект уведомления
Уведомление — POST-запрос от AvantPay на ваш сервер, когда платёж оплачен или отменён. Адрес и события задаются в личном кабинете: Ещё → Разработчикам → HTTP-уведомления. Как включить, обработать и проверить уведомление — на странице Уведомления.
Запрос приходит с заголовком Content-Type: application/json и телом из трёх полей:
Объект платежа на момент события — такой же, как в ответе на GET /v3/payments/{payment_id}.
События
event | В личном кабинете | Когда приходит |
|---|---|---|
payment.succeeded | Платёж оплачен | Платёж перешёл в статус succeeded. Может прийти и после payment.canceled — это поздняя оплата. |
payment.canceled | Платёж отменён | Платёж перешёл в статус canceled: истёк срок оплаты, банк отказал или сработала проверка. |
Если пришло уведомление с другим event, ответьте 200 и ничего не делайте.
Заголовки
| Заголовок | Что в нём |
|---|---|
Signature-Timestamp | Время отправки, Unix-время в секундах. |
Signature | Подпись: v1= и HMAC-SHA256 строки <Signature-Timestamp>.<тело запроса> секретным ключом API в шестнадцатеричном виде. Как проверить — в разделе Подпись. |
Ответьте кодом 200 не позже чем через 10 секунд. Иначе AvantPay повторит уведомление (расписание повторов).
Платёж отменён: покупатель не заплатил вовремя.
{
"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": "[email protected]",
"order_id": "125"
},
"cancellation_details": {
"party": "avantpay",
"reason": "expired_on_confirmation"
}
}
}
Заголовки запроса:
POST /avantpay/webhook HTTP/1.1
Host: example.com
Content-Type: application/json
Signature-Timestamp: 1792324800
Signature: v1=07181d18b6de6cfe0c882fd02f7e40c8c0e735f19dc67062c39f57c8d75c995b
Пример уведомления payment.succeeded — в быстром старте.