Справочник 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-библиотеки собирают этот заголовок сами, если передать логин и пароль.
Где взять ID магазина и секретный ключ
- Войдите в личный кабинет.
- Откройте Ещё → Разработчикам → API-ключ (открыть сразу).
- ID магазина и адрес API — в блоке «Авторизация запросов».
- Нажмите Создать ключ. Ключ показывается целиком только один раз. Скопируйте его сразу.
Если раздела «Разработчикам» нет, попросите владельца магазина добавить вас в разделе «Пользователи» с ролью «Разработчик».
Как хранить ключ
- Храните ключ в переменных окружения или в хранилище секретов сервера.
- Не кладите ключ в код, в репозиторий, в логи и в письма.
- Если ключ мог утечь, нажмите Перевыпустить в том же разделе. Старый ключ сразу перестанет работать. Замените ключ на сервере. Если у ключа включено право «Возвраты», перевыпустить или удалить его может только владелец магазина.
- Тем же ключом AvantPay подписывает уведомления. После перевыпуска уведомления подписываются новым ключом.
Права ключа
В блоке «Права ключа» видно, что можно делать этим ключом. Для создания платежей нужно право «Платежи», для возвратов — право «Возвраты».
- Права включает поддержка AvantPay. В личном кабинете их можно только посмотреть. Чтобы включить право, напишите на support@avantpay.io.
- Без права «Платежи» запрос
POST /v3/paymentsполучит ошибку 403forbidden. Без права «Возвраты» — запросPOST /v3/refunds. - Право «Возвраты» по умолчанию выключено. Поддержка может разрешить возвраты только с IP-адресов ваших серверов: тогда запрос
POST /v3/refundsс другого адреса получит 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 магазина или ключ, ключ перевыпущен или удалён. parameter — Authorization. | Проверьте ID магазина и ключ. Если ключ потерян — перевыпустите его. |
| 403 | forbidden | У ключа нет права «Платежи» или «Возвраты», магазин не активен или возврат отправлен с IP-адреса, которого нет в списке ключа. | Напишите в поддержку: support@avantpay.io. |
| 429 | too_many_requests | С вашего IP-адреса за минуту пришло больше 20 запросов с неверными ключами. До конца этой минуты API отвечает 429 на все запросы с этого адреса. | Исправьте ключи и повторите через retry_after миллисекунд. |
Идемпотентность
Идемпотентность означает, что повторный запрос обрабатывается так же, как первый: получив повтор с теми же данными, AvantPay вернёт результат исходного запроса и второй платёж или возврат не создаст. Если соединение прервалось, запрос можно безопасно повторить.
Для этого передавайте заголовок Idempotence-Key — любое значение, уникальное для операции на вашей стороне, до 64 символов. Рекомендуется UUID версии 4. Ключ обязателен для всех POST-запросов. GET-запросам он не нужен.
Повтор с тем же ключом и теми же данными вернёт результат первого запроса. Тот же ключ с другими данными — ошибка 400 invalid_request, "parameter": "Idempotence-Key". Если первый запрос ещё выполняется, API ответит 202 с полем retry_after — через сколько миллисекунд повторить запрос с тем же ключом.
AvantPay обеспечивает идемпотентность в течение 24 часов после первого запроса. Позже запрос с тем же ключом обрабатывается как новый.
Выполните эту команду дважды. Второй ответ вернёт тот же платёж с тем же 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": "buyer@example.com",
"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"
}
Формат запросов и ответов
Запросы
API поддерживает POST- и GET-запросы. POST-запросы передают параметры в теле в формате JSON с заголовком Content-Type: application/json, GET-запросы — в строке запроса. Тело запроса — не больше 5 МБ. Параметры, которых нет в справочнике, API отбрасывает без ошибки.
Ответы
Ответ содержит код HTTP, стандартные заголовки и тело в формате JSON. При успехе (HTTP 200) в теле — созданный или запрошенный объект или список объектов. При ошибке — объект ошибки (Ошибки). В каждом ответе есть заголовок X-Request-Id: укажите его, если обращаетесь в поддержку.
Сумма
Сумма — объект с полями value и currency. value — строка, рубли и копейки через точку, не больше двух знаков после точки: "100.00". currency — код валюты по ISO-4217, "RUB".
Дата и время
Даты — в формате ISO 8601 по UTC: 2026-10-18T10:15:30.123Z.
metadata
metadata — ваши данные к платежу или возврату: до 16 ключей, имя ключа — до 32 символов, значение — строка до 512 символов. В запросе на создание платежа обязателен ключ email — email покупателя (покупатель из Telegram — <telegram_id>@telegram.org). metadata возвращается в объекте платежа или возврата и в уведомлениях.
Сумма:
{
"value": "100.00",
"currency": "RUB"
}
metadata с email покупателя и номером заказа:
{
"email": "buyer@example.com",
"order_id": "123",
"customer_id": "1042"
}
Покупатель из Telegram:
{
"email": "123456789@telegram.org",
"order_id": "124"
}
Ошибки
Если запрос не выполнен, API отвечает кодом HTTP 400 или выше и объектом ошибки. Объект ошибки приходит на любой ответ 4xx и 5xx, в том числе на неверный адрес (404), неверный метод HTTP (405) и запрос без JSON (415).
Объект ошибки
typeВсегда error.
idID ошибки. Укажите его, если пишете в поддержку.
codeКод ошибки из таблицы ниже. По нему решайте, что делать.
descriptionЧто не так и как исправить. На английском. Пишите в логи, покупателю не показывайте.
parameterКакое поле, заголовок или параметр неверны. Например: amount.value, metadata.email, Idempotence-Key, Authorization, payment_id, refund_id, limit.
retry_afterЧерез сколько миллисекунд повторить запрос. Есть у ответов 429.
Ошибка 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 | — | Запрос на создание платежа с этим ключом идемпотентности ещё выполняется, у сценария qr — банк ещё выдаёт QR-код. Тело: {"type": "processing", "description": "Request accepted", "retry_after": 2000}. | Подождать retry_after миллисекунд и повторить с тем же Idempotence-Key. |
| 400 | invalid_request | Неверный запрос: нет поля или заголовка (например, metadata.email), неверный формат, сумма вне лимитов, ключ идемпотентности уже использован с другим телом, тело не JSON. Для возврата — ещё платёж, который нельзя вернуть сейчас (parameter — payment_id). | Исправить запрос по parameter и description. Без исправления не повторять. |
| 400 | not_supported | Передано поле или значение, которого нет в API (например, receipt или "capture": false), или вызван метод, которого нет. | Убрать поле или не вызывать метод. Без исправления не повторять. |
| 401 | invalid_credentials | Нет заголовка Authorization, неверный ID магазина или секретный ключ, заголовок Bearer. parameter — Authorization. | Проверить ID магазина и ключ. Без исправления не повторять. |
| 403 | forbidden | У ключа нет права «Платежи» или «Возвраты», магазин не активен, сценарий qr не включён для магазина или возврат отправлен с IP-адреса, которого нет в списке ключа. | Написать в поддержку: support@avantpay.io. |
| 404 | not_found | Платежа или возврата с таким id нет у вашего магазина (parameter — payment_id или refund_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-адреса, в эту же секунду создаются другие платежи того же покупателя или у магазина уже 20 возвратов в статусе pending. | Подождать retry_after миллисекунд (заголовок Retry-After — в секундах) и повторить с тем же Idempotence-Key. |
| 500 | internal_server_error | Сбой у AvantPay. Результат запроса неизвестен: платёж или возврат мог создаться. | Повторить с тем же Idempotence-Key и тем же телом. Платёж можно проверить и запросом GET. |
Другой код 5xx или ответ не в JSON обрабатывайте как 500.
Когда повторять запрос
| Ответ | Повторять? |
|---|---|
| 400, 401, 403, 404, 405, 413, 415 | Нет. Сначала исправьте запрос, ключи или настройки. Новый ключ идемпотентности — только для нового запроса на создание, который вы раньше не отправляли. |
| 400, 401 или 403 на повтор создания возврата после таймаута или ответа 500 | Да, после исправления — с тем же Idempotence-Key. Возврат мог создаться первым запросом: повтор вернёт его или создаст сейчас. Новый ключ здесь может вернуть деньги дважды. Подробнее |
| 202, 429 | Да, через retry_after миллисекунд, с тем же Idempotence-Key. |
| 500, таймаут, обрыв связи | Да, с тем же Idempotence-Key и тем же телом. Повторяйте 1–2 минуты, потом покажите покупателю «Платёж создаётся» и продолжайте в фоне с тем же ключом, но не дольше 24 часов. |
Запрос на создание возврата после 500, таймаута или обрыва повторяйте так же: с тем же ключом и тем же телом, не дольше 24 часов.
Не создавайте платёж или возврат с новым ключом, пока не знаете, чем кончился прежний запрос. Иначе покупатель может заплатить дважды или получить деньги дважды.
Объект платежа
Объект платежа (Payment) содержит всю информацию о платеже, актуальную на текущий момент времени. Он формируется при создании платежа и приходит в ответ на любой запрос, связанный с платежами.
Объект может содержать параметры и значения, не описанные в этом Справочнике API. Их следует игнорировать.
Поля
idID платежа, UUID из 36 символов. Сохраните его в заказе: по нему вы получите платёж.
statusСтатус платежа: pending, succeeded или canceled. Что делать в каждом — на странице Статусы платежа.
paidtrue, если платёж оплачен (status равен succeeded). Иначе false.
amountСумма платежа — ровно та, что вы передали при создании. Покупатель платит эту сумму.
income_amountСколько получит магазин: amount минус комиссия AvantPay. Бывает только у платежей со статусом succeeded. Может не быть и у них, например пока AvantPay проверяет оплату. Не решайте по этому полю, оплачен ли платёж.
descriptionОписание, которое вы передали при создании. Есть, только если вы его передали.
recipientПолучатель платежа — ваш магазин.
Вложенные параметры
account_idID магазина строкой.
gateway_idID счёта в AvantPay, на который зачисляются деньги. Появляется, когда выбран способ оплаты. Для интеграции не нужен.
payment_methodСпособ оплаты. Появляется, когда способ выбран: сразу, если вы передали payment_method_data, иначе — когда покупатель выберет способ на странице оплаты. Если магазину подключены другие способы, type может быть и другим — на незнакомом значении код не должен падать.
Вложенные параметры
typeЗначение — sbp.
idID способа оплаты. У сохранённого способа — его ID: передавайте его в payment_method_id для автоплатежей (способы оплаты). У несохранённого равен id платежа.
savedtrue — способ сохранён для автоплатежей.
statusСтатус сохранения: pending — платёж с save_payment_method ждёт оплаты, active — способ сохранён, inactive — не сохранён.
titleНазвание способа.
typeЗначение — bank_card.
idID способа оплаты. У сохранённого способа — его ID: передавайте его в payment_method_id для автоплатежей (способы оплаты). У несохранённого равен id платежа.
savedtrue — способ сохранён для автоплатежей.
statusСтатус сохранения: pending — платёж с save_payment_method ждёт оплаты, active — способ сохранён, inactive — не сохранён.
titleНазвание способа.
cardДанные карты. Есть у сохранённого способа.
Вложенные параметры
first6Первые 6 цифр номера карты (BIN).
last4Последние 4 цифры номера карты.
expiry_monthМесяц окончания срока действия, MM.
expiry_yearГод окончания срока действия, YYYY.
card_typeПлатёжная система: Mir, Visa, MasterCard, UnionPay или Unknown.
issuer_countryСтрана банка-эмитента, код ISO 3166-1 alpha-2.
issuer_nameБанк-эмитент.
typeЗначение — crypto.
idID способа оплаты. У сохранённого способа — его ID: передавайте его в payment_method_id для автоплатежей (способы оплаты). У несохранённого равен id платежа.
savedtrue — способ сохранён для автоплатежей.
statusСтатус сохранения: pending — платёж с save_payment_method ждёт оплаты, active — способ сохранён, inactive — не сохранён.
titleНазвание способа.
captured_atcreated_atexpires_atconfirmationКак покупатель платит — сценарий, который вы передали при создании. Нет у платежа со сценарием qr, у которого нет QR-кода: AvantPay отклонил платёж при создании (canceled, причина fraud_suspected), банк не выдал QR-код (canceled) или QR-код ещё выдаётся (pending после ответа 202 на создание: повторите запрос создания с тем же Idempotence-Key).
Вложенные параметры
typeredirect — страница оплаты AvantPay.
confirmation_urlСсылка на страницу оплаты. Отправьте покупателя по ней, только если status равен pending. Может не быть у платежа, который отменён при создании.
return_urlАдрес возврата покупателя, который вы передали.
typeqr — QR-код СБП.
confirmation_dataСсылка СБП от банка — содержимое QR-кода, обычно https://qr.nspk.ru/…. Есть уже в ответе на создание платежа и не меняется: QR-код у платежа один и действует до expires_at, нового AvantPay не выдаёт. Сделайте из ссылки QR-код и покажите покупателю, на телефоне ссылку можно просто открыть. Страницы оплаты AvantPay здесь не бывает.
testТестовый ли платёж. Всегда false: тестового режима нет.
refunded_amountСколько денег уже вернули покупателю: сумма выполненных возвратов (статус succeeded) — через API и в личном кабинете. Есть, только если был выполненный возврат. Статус платежа после возврата остаётся succeeded.
refundableМожно ли сейчас вернуть платёж запросом POST /v3/refunds. true — запрос пройдёт проверки. false — нельзя: платёж не оплачен, уже возвращён полностью, по нему идёт другой возврат или вернуть его можно только через поддержку. Право ключа «Возвраты» и деньги на счёте магазина здесь не учитываются.
metadataВаши данные из запроса на создание: email покупателя, номер заказа и другие ключи, которые вы передали. Значения — строки.
cancellation_detailsКто отменил платёж и почему. Бывает только у платежей со статусом canceled.
Вложенные параметры
partyКто отменил: merchant, avantpay или payment_network. Что значит каждое — на странице Статусы платежа.
reasonПричина отмены. Все причины — на странице Статусы платежа.
- Оплачен
- Новый
- Отменён
- Возврат
Покупатель оплатил картой:
{
"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/checkout?paymentId=2f9b6c1e-4d7a-4c3b-9e8f-1a2b3c4d5e6f",
"return_url": "https://example.com/orders/123"
},
"test": false,
"refundable": true,
"metadata": {
"email": "buyer@example.com",
"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/checkout?paymentId=e5b1c9d3-7a2f-4e8b-9c6d-1f0a2b3c4d5e",
"return_url": "https://example.com/orders/127"
},
"test": false,
"refundable": false,
"metadata": {
"email": "123456789@telegram.org",
"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/checkout?paymentId=8d0e4b52-7c19-4a6e-b3f1-5e2a9c7d1b40",
"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"
}
}
Покупатель заплатил по СБП, 50 ₽ из 250 ₽ ему уже вернули. Статус остался succeeded. Остаток тоже можно вернуть, поэтому refundable равен true:
{
"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/checkout?paymentId=c4a8e2f1-9b3d-4f6a-8e1c-7d2b5a9f3e60",
"return_url": "https://example.com/orders/122"
},
"test": false,
"refunded_amount": {
"value": "50.00",
"currency": "RUB"
},
"refundable": true,
"metadata": {
"email": "buyer@example.com",
"order_id": "122"
}
}
Создать платёж
Создаёт платёж и возвращает объект платежа со статусом pending и ссылкой на оплату confirmation.confirmation_url.
Email покупателя обязателен: передайте его в metadata.email. Покупатель из Telegram — <telegram_id>@telegram.org, например 123456789@telegram.org.
Заголовки
Все три заголовка обязательны.
| Заголовок | Значение |
|---|---|
Authorization | HTTP Basic: ID магазина и секретный ключ. В cURL — параметр -u со значением "$AVANTPAY_SHOP_ID:$AVANTPAY_SECRET_KEY" |
Idempotence-Key | Ключ идемпотентности: уникальная строка до 64 символов, лучше UUID. Новый для каждой попытки оплаты, тот же при повторе запроса. Подробнее |
Content-Type | application/json |
Параметры запроса
amountСумма платежа. Покупатель заплатит ровно её. Комиссию AvantPay платит магазин: она вычитается из этой суммы.
captureУказывается true.
payment_method_idconfirmationКак покупатель будет платить.
Вложенные параметры
typeredirect — покупатель переходит на страницу оплаты AvantPay.
return_urlКуда вернуть покупателя после оплаты или отказа от неё. Адрес http:// или https://, до 2048 символов. AvantPay открывает его как есть, без параметров, поэтому укажите в нём свой заказ.
typeqr — вы показываете покупателю QR-код СБП. Только вместе с "payment_method_data": {"type": "sbp"}. Ссылка для QR-кода — confirmation.confirmation_data в ответе на создание. Если банк выдаёт QR-код дольше 10 секунд, API ответит 202: повторите запрос с тем же Idempotence-Key. QR-код не выдан — платёж canceled без confirmation.
return_urlКуда вернуть покупателя после оплаты или отказа от неё. Адрес http:// или https://, до 2048 символов. AvantPay открывает его как есть, без параметров, поэтому укажите в нём свой заказ.
descriptionОписание платежа, до 128 символов. Его видит покупатель на странице оплаты и вы в личном кабинете.
payment_method_dataСпособ оплаты. Если не передать, покупатель выберет способ на странице оплаты. Способ должен быть включён у магазина.
client_ipIP-адрес покупателя, IPv4 или IPv6.
save_payment_methodtrue — сохранить способ оплаты для автоплатежей. ID сохранённого способа — payment_method.id в ответе (подробнее).
payment_method_idID сохранённого способа оплаты, до 64 символов: списание без участия покупателя. confirmation и metadata.email не нужны (подробнее).
metadataВаши данные к платежу. Обязателен ключ email. Всего до 16 ключей, имя ключа до 32 символов, значение — строка до 512 символов. Вернутся в объекте платежа и в уведомлениях. Подробнее — в разделе metadata.
Вложенные параметры
emailEmail покупателя, до 254 символов. Покупатель из Telegram — <telegram_id>@telegram.org, например 123456789@telegram.org. Нет email или адрес неверный — ошибка 400 invalid_request, parameter — metadata.email.
order_idВаш номер заказа. Вернётся в объекте платежа и в уведомлениях. API не проверяет, что номер уникален: от двойного платежа защищает ключ идемпотентности.
Ответ
В ответ на запрос придёт объект платежа в актуальном статусе.
Пример запроса
- 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": "buyer@example.com",
"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']
}
Пример ответа
Объект платежа со ссылкой на оплату
{
"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/checkout?paymentId=3d6f0a8e-5b2c-4e1f-9a7d-2c4b6e8f0a1b",
"return_url": "https://example.com/orders/123"
},
"test": false,
"refundable": false,
"metadata": {
"email": "buyer@example.com",
"order_id": "123"
}
}
Неверный 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 — <telegram_id>@telegram.org. |
| 400 | invalid_request | Idempotence-Key | Нет ключа, ключ длиннее 64 символов, переданы Idempotence-Key и Idempotency-Key с разными значениями, тот же ключ уже использован с другим телом запроса. | Передать один ключ до 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 | client_ip | Сценарий qr, а client_ip — не IPv4 и не IPv6. У redirect неверный адрес ошибки не даёт, но и не сохраняется. | Передать IP покупателя или не передавать поле. |
| 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, 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 миллисекунд и повторить с тем же ключом. |
| 429 | too_many_requests | — | В эту же секунду создаются другие платежи этого покупателя. Платёж не создан. | Подождать retry_after миллисекунд и повторить с тем же ключом. |
| 202 | — | — | Запрос с этим ключом ещё выполняется, у сценария qr — банк ещё выдаёт QR-код. Тело: {"type": "processing", ...}. | Подождать retry_after миллисекунд и повторить с тем же ключом. |
| 500 | internal_server_error | — | Сбой у AvantPay. Платёж мог создаться. | Повторить с тем же ключом. |
Если ответа нет совсем (таймаут, обрыв связи), поступите так же, как при ответе 500: повторите запрос с тем же Idempotence-Key и тем же телом. Если повтор вернул "status": "canceled", платёж не создался до конца: создайте новый с новым ключом.
Получить платёж
Возвращает объект платежа в текущем состоянии.
Параметры пути
payment_idid платежа из ответа на его создание.
Ответ
В ответ на запрос придёт объект платежа в актуальном статусе.
Пример запроса
- 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);
}
Пример ответа
{
"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/checkout?paymentId=2f9b6c1e-4d7a-4c3b-9e8f-1a2b3c4d5e6f",
"return_url": "https://example.com/orders/123"
},
"test": false,
"refundable": true,
"metadata": {
"email": "buyer@example.com",
"order_id": "123"
}
}
Ошибки
| 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. | Повторить запрос позже. |
Список платежей
Возвращает платежи вашего магазина от новых к старым. Можно отфильтровать по дате, статусу и способу оплаты. Список отдаётся страницами. Заголовок Idempotence-Key этому методу не нужен. Тела у запроса нет.
Параметры запроса
Все параметры необязательные. Передавайте их в строке запроса, каждый — не больше одного раза. Незнакомые параметры API не учитывает.
limitСколько платежей на странице: от 1 до 100. По умолчанию 10.
cursorЗначение next_cursor из предыдущего ответа — чтобы получить следующую страницу. Передавайте как есть.
statusТолько платежи с этим статусом: pending, succeeded или canceled.
payment_methodТолько платежи этим способом: sbp или bank_card.
created_at.gtecreated_at.gtcreated_at.ltecreated_at.ltcaptured_at.gtecaptured_at.gtcaptured_at.ltecaptured_at.ltФильтра по номеру заказа нет: запрос с order_id получит ошибку 400 not_supported. Номер заказа храните в metadata.order_id, а платёж получайте по id, который сохранили в заказе: GET /v3/payments/{payment_id}.
Ответ
В ответ на запрос придёт объект списка: платежи в items — объекты платежа в актуальном статусе.
typeВсегда list.
itemsПлатежи — объекты платежа, от новых к старым. Если ничего не нашлось — пустой массив [].
next_cursorКурсор следующей страницы. Нет на последней странице.
Как получить все страницы
- Отправьте запрос с нужными фильтрами.
- Если в ответе есть
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);
}
Пример ответа
Объект списка, первая страница
{
"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/checkout?paymentId=2f9b6c1e-4d7a-4c3b-9e8f-1a2b3c4d5e6f",
"return_url": "https://example.com/orders/123"
},
"test": false,
"refundable": true,
"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/checkout?paymentId=c4a8e2f1-9b3d-4f6a-8e1c-7d2b5a9f3e60",
"return_url": "https://example.com/orders/122"
},
"test": false,
"refunded_amount": {
"value": "50.00",
"currency": "RUB"
},
"refundable": true,
"metadata": {
"email": "buyer@example.com",
"order_id": "122"
}
}
],
"next_cursor": "MjAyNi0xMC0xN1QxODozOTo1NS44NzFafGM0YThlMmYxLTliM2QtNGY2YS04ZTFjLTdkMmI1YTlmM2U2MA"
}
Фильтр по номеру заказа не поддерживается
{
"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 | Магазин не активен. | Написать в поддержку: support@avantpay.io. |
| 429 | too_many_requests | Больше 50 запросов в секунду. | Повторить через retry_after миллисекунд. |
| 500 | internal_server_error | Сбой у AvantPay. | Повторить запрос позже. |
Объект способа оплаты
Объект способа оплаты (PaymentMethod) содержит информацию о способе оплаты, сохранённом для автоплатежей: тип, статус и данные карты или банка. Способ сохраняется платежом с save_payment_method: true или запросом на создание. Как проводить автоплатежи — на странице Автоплатежи.
Объект может содержать параметры и значения, не описанные в этом Справочнике API. Их следует игнорировать.
Поля
typeТип способа оплаты: bank_card или sbp.
idID способа оплаты. Передавайте его в payment_method_id при создании платежа для автоплатежа.
savedtrue — способ сохранён: по нему можно проводить автоплатежи.
statusСтатус способа оплаты: pending — ждёт действий покупателя, active — сохранён, inactive — не сохранён (ошибка, истёк срок привязки) или покупатель отключил автоплатежи.
titleНазвание способа оплаты.
cardДанные карты. Есть у сохранённой карты (bank_card).
Вложенные параметры
first6Первые 6 цифр номера карты (BIN).
last4Последние 4 цифры номера карты.
expiry_monthМесяц окончания срока действия, MM.
expiry_yearГод окончания срока действия, YYYY.
card_typeПлатёжная система: Mir, Visa, MasterCard, UnionPay или Unknown.
issuer_countryСтрана банка-эмитента, код ISO 3166-1 alpha-2.
issuer_nameБанк-эмитент.
holderМагазин, для которого сохранён способ оплаты.
Вложенные параметры
account_idID магазина.
payer_bank_detailsБанк покупателя. Есть у СБП (sbp), если банк известен.
Вложенные параметры
bank_idID банка в СБП.
metadataВаши данные из запроса на создание способа оплаты. Есть, только если вы их передали.
confirmationПодтверждение способа оплаты покупателем. Есть у способа в статусе pending, созданного запросом.
Вложенные параметры
typeЗначение — redirect.
confirmation_urlСсылка, по которой покупатель подтверждает сохранение карты. Перенаправьте его по ней.
return_urlКуда вернётся покупатель — из запроса на создание.
- Карта
- СБП
- Ждёт покупателя
Карта сохранена:
{
"type": "bank_card",
"id": "9d4c2b1a-6e5f-4a3b-8c7d-1e2f3a4b5c6d",
"saved": true,
"status": "active",
"title": "Bank card *4444",
"card": {
"first6": "220220",
"last4": "4444",
"expiry_month": "07",
"expiry_year": "2030",
"card_type": "Mir",
"issuer_country": "RU",
"issuer_name": "Sberbank"
},
"holder": {
"account_id": "33661"
},
"metadata": {
"customer_id": "1042"
}
}
СБП сохранена платежом:
{
"type": "sbp",
"id": "4f8a2c6e-1b3d-4e5f-9a7b-2c4d6e8f0a1b",
"saved": true,
"status": "active",
"title": "СБП",
"holder": {
"account_id": "33661"
},
"payer_bank_details": {
"bank_id": "100000000111"
}
}
Карта ждёт подтверждения покупателем:
{
"type": "bank_card",
"id": "9d4c2b1a-6e5f-4a3b-8c7d-1e2f3a4b5c6d",
"saved": false,
"status": "pending",
"holder": {
"account_id": "33661"
},
"metadata": {
"customer_id": "1042"
},
"confirmation": {
"type": "redirect",
"confirmation_url": "https://avantpay.io/checkout/bind?paymentMethodId=9d4c2b1a-6e5f-4a3b-8c7d-1e2f3a4b5c6d",
"return_url": "https://example.com/account/cards"
}
}
Создать способ оплаты
Создаёт способ оплаты — банковскую карту — без платежа и возвращает объект способа оплаты в статусе pending со ссылкой confirmation.confirmation_url. Перенаправьте покупателя по ссылке: он подтвердит карту, на ней заблокируется и сразу вернётся 1 ₽. Когда карта сохранится, статус станет active и придёт уведомление payment_method.active. Ссылка действует 1 час.
Автоплатежи и сохранение карты без платежа включает поддержка AvantPay по письму на support@avantpay.io. Без этого API ответит 403 forbidden.
Заголовки
Все три заголовка обязательны.
| Заголовок | Значение |
|---|---|
Authorization | HTTP Basic: ID магазина и секретный ключ. В cURL — параметр -u со значением "$AVANTPAY_SHOP_ID:$AVANTPAY_SECRET_KEY" |
Idempotence-Key | Ключ идемпотентности: уникальная строка до 64 символов. Подробнее |
Content-Type | application/json |
Параметры запроса
typeЗначение — bank_card. СБП без платежа не сохраняется: создайте платёж с save_payment_method: true.
confirmationСценарий подтверждения: покупатель переходит по ссылке и подтверждает карту, на ней блокируется и сразу возвращается 1 ₽.
Вложенные параметры
typeЗначение — redirect.
return_urlКуда вернуть покупателя после подтверждения. Адрес http:// или https://, до 2048 символов.
metadataВаши данные к способу оплаты: до 16 ключей, имя ключа до 32 символов, значение — строка до 512 символов. Вернутся в объекте способа оплаты.
Ответ
В ответ на запрос придёт объект способа оплаты в статусе pending.
Пример запроса
- cURL
- Python
- Node.js
- PHP
curl https://api.avantpay.io/v3/payment_methods \
-X POST \
-u "$AVANTPAY_SHOP_ID: $AVANTPAY_SECRET_KEY" \
-H "Idempotence-Key: 3c6e9a1f-2b4d-4f8a-9c7e-5d1b3a2f4e6c" \
-H "Content-Type: application/json" \
-d '{
"type": "bank_card",
"confirmation": {
"type": "redirect",
"return_url": "https://example.com/account/cards"
},
"metadata": {
"customer_id": "1042"
}
}'
import os
import requests
SHOP_ID = os.environ["AVANTPAY_SHOP_ID"]
SECRET_KEY = os.environ["AVANTPAY_SECRET_KEY"]
def create_payment_method(customer_id: str, return_url: str, idempotence_key: str) -> dict:
response = requests.post(
"https://api.avantpay.io/v3/payment_methods",
auth=(SHOP_ID, SECRET_KEY),
headers={"Idempotence-Key": idempotence_key},
json={
"type": "bank_card",
"confirmation": {"type": "redirect", "return_url": return_url},
"metadata": {"customer_id": customer_id},
},
timeout=30,
)
if response.status_code != 200:
raise RuntimeError(f"AvantPay: HTTP {response.status_code}: {response.text}")
# Перенаправьте покупателя на method["confirmation"]["confirmation_url"]
return response.json()
const AUTH =
"Basic " +
Buffer.from(`${ process.env.AVANTPAY_SHOP_ID}: ${process.env.AVANTPAY_SECRET_KEY}`).toString("base64");
export async function createPaymentMethod({ customerId, returnUrl, idempotenceKey }) {
const response = await fetch("https://api.avantpay.io/v3/payment_methods", {
method: "POST",
headers: {
Authorization: AUTH,
"Idempotence-Key": idempotenceKey,
"Content-Type": "application/json",
},
body: JSON.stringify({
type: "bank_card",
confirmation: { type: "redirect", return_url: returnUrl },
metadata: { customer_id: customerId },
}),
signal: AbortSignal.timeout(30000),
});
const text = await response.text();
if (response.status !== 200) {
throw new Error(`AvantPay: HTTP ${response.status}: ${text}`);
}
// Перенаправьте покупателя на method.confirmation.confirmation_url
return JSON.parse(text);
}
<?php
function createPaymentMethod(string $customerId, string $returnUrl, string $idempotenceKey): array
{
$ch = curl_init('https://api.avantpay.io/v3/payment_methods');
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([
'type' => 'bank_card',
'confirmation' => ['type' => 'redirect', 'return_url' => $returnUrl],
'metadata' => ['customer_id' => $customerId],
]),
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);
}
// Перенаправьте покупателя на $method['confirmation']['confirmation_url']
return json_decode($response, true);
}
Пример ответа
Способ оплаты ждёт подтверждения покупателем
{
"type": "bank_card",
"id": "9d4c2b1a-6e5f-4a3b-8c7d-1e2f3a4b5c6d",
"saved": false,
"status": "pending",
"holder": {
"account_id": "33661"
},
"metadata": {
"customer_id": "1042"
},
"confirmation": {
"type": "redirect",
"confirmation_url": "https://avantpay.io/checkout/bind?paymentMethodId=9d4c2b1a-6e5f-4a3b-8c7d-1e2f3a4b5c6d",
"return_url": "https://example.com/account/cards"
}
}
Сохранить СБП без платежа нельзя
{
"type": "error",
"id": "4b2d6f8a-1c3e-4a5b-9d7f-0e2a4c6b8d1f",
"code": "not_supported",
"description": "type sbp is not supported for saving without a payment: create a payment with save_payment_method: true",
"parameter": "type"
}
Ошибки
Формат ошибок и общие коды — в разделе Ошибки. Ошибки этого метода:
| HTTP | code | parameter | Когда | Что делать |
|---|---|---|---|---|
| 400 | invalid_request | Idempotence-Key | Нет ключа, ключ длиннее 64 символов или уже использован с другим телом запроса. | Передать новый ключ до 64 символов. |
| 400 | invalid_request | type | Нет type, значение не bank_card или у магазина нет карты, которую можно сохранить. | Передать bank_card. Если ошибка повторяется — написать в поддержку: support@avantpay.io. |
| 400 | not_supported | type | type равен sbp. | Сохранить СБП платежом с save_payment_method: true. |
| 400 | not_supported | card | Переданы данные карты. | Убрать card: покупатель вводит карту на странице по confirmation_url. |
| 400 | invalid_request | confirmation, confirmation.type, confirmation.return_url | Нет confirmation, type не redirect или return_url — не адрес http:// или https://. | Передать confirmation с type redirect и адресом возврата. |
| 400 | invalid_request | metadata | metadata — не объект, больше 16 ключей, длинное имя ключа или значение. | Привести к правилам из раздела metadata. |
| 401 | invalid_credentials | Authorization | Неверный ID магазина или ключ. | Проверить ключи. |
| 403 | forbidden | — | Автоплатежи или сохранение карты без платежа не включены, у ключа нет права «Платежи» или магазин не активен. | Написать в поддержку: support@avantpay.io. |
| 429 | too_many_requests | — | Больше 50 запросов в секунду. | Повторить через retry_after миллисекунд с тем же ключом. |
| 500 | internal_server_error | — | Сбой у AvantPay. | Повторить с тем же ключом и тем же телом. |
Получить способ оплаты
Возвращает объект способа оплаты в текущем состоянии.
Параметры пути
payment_method_idID способа оплаты: payment_method.id из платежа или id из ответа на создание способа.
Ответ
В ответ на запрос придёт объект способа оплаты в актуальном статусе.
Пример запроса
- cURL
- Python
- Node.js
- PHP
curl https://api.avantpay.io/v3/payment_methods/9d4c2b1a-6e5f-4a3b-8c7d-1e2f3a4b5c6d \
-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_method(payment_method_id: str) -> Optional[dict]:
"""Способ оплаты из API; None — у магазина нет такого способа (404)"""
response = requests.get(
f"https://api.avantpay.io/v3/payment_methods/{payment_method_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 getPaymentMethod(paymentMethodId) {
const response = await fetch(
`https://api.avantpay.io/v3/payment_methods/${ encodeURIComponent(paymentMethodId)}`,
{ 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 getPaymentMethod(string $paymentMethodId): ?array
{
$ch = curl_init('https://api.avantpay.io/v3/payment_methods/' . rawurlencode($paymentMethodId));
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);
}
Пример ответа
Карта сохранена
{
"type": "bank_card",
"id": "9d4c2b1a-6e5f-4a3b-8c7d-1e2f3a4b5c6d",
"saved": true,
"status": "active",
"title": "Bank card *4444",
"card": {
"first6": "220220",
"last4": "4444",
"expiry_month": "07",
"expiry_year": "2030",
"card_type": "Mir",
"issuer_country": "RU",
"issuer_name": "Sberbank"
},
"holder": {
"account_id": "33661"
},
"metadata": {
"customer_id": "1042"
}
}
Способа оплаты нет у магазина
{
"type": "error",
"id": "7e3a5c1b-9d2f-4b6a-8c4e-2f1d3b5a7c9e",
"code": "not_found",
"description": "Payment method with the specified id was not found",
"parameter": "payment_method_id"
}
Ошибки
| HTTP | code | Когда | Что делать |
|---|---|---|---|
| 404 | not_found | Способа оплаты с таким id нет у вашего магазина. parameter — payment_method_id. | Проверить id. |
| 401 | invalid_credentials | Неверный ID магазина или ключ. | Проверить ключи. |
| 403 | forbidden | Магазин не активен. | Написать в поддержку: support@avantpay.io. |
| 429 | too_many_requests | Больше 50 запросов в секунду. | Повторить через retry_after миллисекунд. |
| 500 | internal_server_error | Сбой у AvantPay. | Повторить запрос позже. |
Объект возврата
Объект возврата (Refund) содержит всю информацию о возврате, актуальную на текущий момент времени. Он формируется при создании возврата и приходит в ответ на любой запрос, связанный с возвратами. Как сделать возврат — на странице Возвраты.
Объект может содержать параметры и значения, не описанные в этом Справочнике API. Их следует игнорировать.
Поля
idID возврата, UUID из 36 символов. Сохраните его: по нему вы узнаете, чем кончился возврат.
payment_idID платежа, по которому сделан возврат.
statusСтатус возврата: pending, succeeded или canceled. Что значит каждый — в разделе Статусы возврата.
cancellation_detailsКто отменил возврат и почему. Бывает только у возвратов со статусом canceled.
Вложенные параметры
partyКто отменил: avantpay или refund_network. Что значит каждое — в разделе Кто отменил возврат.
reasonПричина отмены: insufficient_funds или general_decline. Что делать — в разделе Кто отменил возврат.
created_atamountСумма возврата — та, что вы передали при создании. В валюте платежа.
descriptionКомментарий, который вы передали при создании. Есть, только если вы его передали.
metadataВаши произвольные данные из запроса на создание возврата. Значения — строки. Если вы их не передали или возврат сделан в личном кабинете — пустой объект {}.
Статусы возврата
status | Что значит | Что делать магазину |
|---|---|---|
pending | Возврат создан и выполняется. Покупатель ещё не получил деньги. | Ждать уведомления refund.succeeded или запросить возврат позже. |
succeeded | Возврат выполнен: деньги отправлены покупателю. Статус больше не меняется. | Отметить в заказе, что деньги вернули. |
canceled | Возврат не выполнен: покупатель денег не получил, сумма возврата осталась на счёте магазина или вернулась на него. Статус больше не меняется. Причина — в cancellation_details. | Смотреть по причине — в разделе Кто отменил возврат. |
Обычно возврат становится succeeded или canceled через несколько секунд или минут. Уведомление приходит только о выполненном возврате — refund.succeeded. Уведомления об отмене нет: отмену видно в ответе на GET /v3/refunds/{refund_id}.
Если возврат в pending дольше часа, напишите в поддержку: support@avantpay.io, укажите id возврата. Не считайте его отменённым и не создавайте новый: API не примет новый возврат по этому платежу, пока этот не завершится.
Кто отменил возврат
У возврата со статусом canceled есть поле cancellation_details с полями party и reason.
party | Кто |
|---|---|
avantpay | AvantPay: на счёте магазина не хватило денег, возврат остановила проверка или его не удалось отправить. |
refund_network | Банк или платёжная система, через которые идёт возврат: они отклонили возврат. Сумма вернётся на счёт магазина, но до 3 дней может быть в резерве. |
reason | Что случилось | Что делать |
|---|---|---|
insufficient_funds | У avantpay — на счёте магазина не хватило денег на возврат. У refund_network — так ответил банк или платёжная система. | У avantpay — дождаться, когда на счёте будет нужная сумма, и создать новый возврат с новым ключом идемпотентности. Остаток счёта виден в личном кабинете на странице «Обзор», через API его не узнать. У refund_network — написать в поддержку. |
general_decline | Причина не уточняется. | Написать в поддержку: support@avantpay.io, указать id возврата. |
Если придёт значение, которого нет в таблице, обработайте его как general_decline.
- Выполнен
- Создан
- Отменён
Покупателю вернули 300 ₽ из 1000 ₽:
{
"id": "5e1d7c3a-9b2f-4a6e-8d4c-0f3b2a1e9c87",
"payment_id": "2f9b6c1e-4d7a-4c3b-9e8f-1a2b3c4d5e6f",
"status": "succeeded",
"created_at": "2026-10-19T09:40:12.305Z",
"amount": {
"value": "300.00",
"currency": "RUB"
},
"description": "Возврат по заказу №123",
"metadata": {
"order_id": "123"
}
}
Только что созданный возврат — так выглядит ответ на POST /v3/refunds:
{
"id": "5e1d7c3a-9b2f-4a6e-8d4c-0f3b2a1e9c87",
"payment_id": "2f9b6c1e-4d7a-4c3b-9e8f-1a2b3c4d5e6f",
"status": "pending",
"created_at": "2026-10-19T09:40:12.305Z",
"amount": {
"value": "300.00",
"currency": "RUB"
},
"description": "Возврат по заказу №123",
"metadata": {
"order_id": "123"
}
}
На счёте магазина не хватило денег. Возврат сделан в личном кабинете, поэтому metadata пустая:
{
"id": "a3c9e7b1-2d4f-4e6a-9b8c-1f0e2d3c4b5a",
"payment_id": "c4a8e2f1-9b3d-4f6a-8e1c-7d2b5a9f3e60",
"status": "canceled",
"cancellation_details": {
"party": "avantpay",
"reason": "insufficient_funds"
},
"created_at": "2026-10-18T08:12:44.019Z",
"amount": {
"value": "100.00",
"currency": "RUB"
},
"metadata": {}
}
Создать возврат
Создаёт возврат по оплаченному платежу и возвращает объект возврата. У нового возврата статус pending. Можно вернуть всю сумму платежа или часть. Деньги вернутся покупателю тем же способом, которым он платил.
Для возвратов у ключа должно быть включено право «Возвраты». По умолчанию оно выключено: его включает поддержка AvantPay по письму на support@avantpay.io. Без права API ответит 403 forbidden.
Заголовки
Все три заголовка обязательны.
| Заголовок | Значение |
|---|---|
Authorization | HTTP Basic: ID магазина и секретный ключ. В cURL — параметр -u со значением "$AVANTPAY_SHOP_ID:$AVANTPAY_SECRET_KEY" |
Idempotence-Key | Ключ идемпотентности: уникальная строка до 64 символов. Один ключ — один возврат: новый для каждого возврата, тот же при повторе запроса. Подробнее |
Content-Type | application/json |
Параметры запроса
payment_idid платежа, который нужно вернуть, — 36 символов. Платёж вашего магазина в статусе succeeded: проверьте, что у него refundable равен true.
amountСумма возврата: вся сумма платежа или часть. Со счёта магазина спишется вся эта сумма.
descriptionКомментарий к возврату, до 250 символов. Вернётся в объекте возврата.
Правила возврата
- Вернуть можно только оплаченный платёж — в статусе
succeeded. Проверьте заранее, что у платежаrefundableравенtrue. - Деньги вернутся тем же способом, которым платил покупатель. Выбрать другой способ нельзя.
- Частичных возвратов по одному платежу может быть несколько, пока не вернули всю сумму. Всего — не больше 10 возвратов на платёж, отменённые не считаются.
- Минимальная сумма возврата — 1 ₽. Меньше можно вернуть, только если это весь остаток платежа.
- По платежу одновременно выполняется только один возврат. Следующий создавайте, когда прежний стал
succeededилиcanceled. Пока прежний в статусеpending, API ответит 400. - Со счёта магазина спишется вся сумма возврата. Комиссия AvantPay за платёж не возвращается.
- Если на счёте магазина не хватит денег, API всё равно ответит 200 и создаст возврат. Потом возврат перейдёт в
canceledс причинойinsufficient_funds.
Ответ
В ответ на запрос придёт объект возврата в актуальном статусе.
Пример запроса
- cURL
- Python
- Node.js
- PHP
curl https://api.avantpay.io/v3/refunds \
-X POST \
-u "$AVANTPAY_SHOP_ID: $AVANTPAY_SECRET_KEY" \
-H "Idempotence-Key: refund-123-1" \
-H "Content-Type: application/json" \
-d '{
"payment_id": "2f9b6c1e-4d7a-4c3b-9e8f-1a2b3c4d5e6f",
"amount": {
"value": "300.00",
"currency": "RUB"
},
"description": "Возврат по заказу №123",
"metadata": {
"order_id": "123"
}
}'
import os
import requests
SHOP_ID = os.environ["AVANTPAY_SHOP_ID"]
SECRET_KEY = os.environ["AVANTPAY_SECRET_KEY"]
def create_refund(payment_id: str, amount: str, order_id: str, idempotence_key: str) -> dict:
# idempotence_key — ключ этого возврата: сохраните его до запроса и повторяйте запрос с ним же
response = requests.post(
"https://api.avantpay.io/v3/refunds",
auth=(SHOP_ID, SECRET_KEY),
headers={"Idempotence-Key": idempotence_key},
json={
"payment_id": payment_id,
"amount": {"value": amount, "currency": "RUB"},
"description": f"Возврат по заказу №{order_id}",
"metadata": {"order_id": order_id},
},
timeout=40, # создание возврата может занять до 30 секунд
)
if response.status_code != 200:
raise RuntimeError(f"AvantPay: HTTP {response.status_code}: {response.text}")
# У нового возврата статус pending, у повтора он может быть уже итоговым.
# Итог — в уведомлении refund.succeeded или в ответе GET /v3/refunds/{id}
return response.json()
const AUTH =
"Basic " +
Buffer.from(`${ process.env.AVANTPAY_SHOP_ID}: ${process.env.AVANTPAY_SECRET_KEY}`).toString("base64");
// idempotenceKey — ключ этого возврата: сохраните его до запроса и повторяйте запрос с ним же
export async function createRefund({ paymentId, amount, orderId, idempotenceKey }) {
const response = await fetch("https://api.avantpay.io/v3/refunds", {
method: "POST",
headers: {
Authorization: AUTH,
"Idempotence-Key": idempotenceKey,
"Content-Type": "application/json",
},
body: JSON.stringify({
payment_id: paymentId,
amount: { value: amount, currency: "RUB" },
description: `Возврат по заказу №${ orderId}`,
metadata: { order_id: orderId },
}),
signal: AbortSignal.timeout(40000), // создание возврата может занять до 30 секунд
});
const text = await response.text();
if (response.status !== 200) {
throw new Error(`AvantPay: HTTP ${response.status}: ${text}`);
}
// У нового возврата статус pending, у повтора он может быть уже итоговым.
// Итог — в уведомлении refund.succeeded или в ответе GET /v3/refunds/{id}
return JSON.parse(text);
}
<?php
// $idempotenceKey — ключ этого возврата: сохраните его до запроса и повторяйте запрос с ним же
function createRefund(string $paymentId, string $amount, string $orderId, string $idempotenceKey): array
{
$ch = curl_init('https://api.avantpay.io/v3/refunds');
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([
'payment_id' => $paymentId,
'amount' => ['value' => $amount, 'currency' => 'RUB'],
'description' => 'Возврат по заказу №' . $orderId,
'metadata' => ['order_id' => $orderId],
], JSON_UNESCAPED_UNICODE),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 40, // создание возврата может занять до 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);
}
// У нового возврата статус pending, у повтора он может быть уже итоговым.
// Итог — в уведомлении refund.succeeded или в ответе GET /v3/refunds/{id}
return json_decode($response, true);
}
Пример ответа
Новый возврат в статусе pending
{
"id": "5e1d7c3a-9b2f-4a6e-8d4c-0f3b2a1e9c87",
"payment_id": "2f9b6c1e-4d7a-4c3b-9e8f-1a2b3c4d5e6f",
"status": "pending",
"created_at": "2026-10-19T09:40:12.305Z",
"amount": {
"value": "300.00",
"currency": "RUB"
},
"description": "Возврат по заказу №123",
"metadata": {
"order_id": "123"
}
}
По платежу уже выполняется возврат
{
"type": "error",
"id": "8f2a6d1c-3e5b-4c7a-9d0e-1b2c3d4e5f60",
"code": "invalid_request",
"description": "Another refund of this payment is in progress: wait until it is succeeded or canceled, then retry with a new Idempotence-Key",
"parameter": "payment_id"
}
У ключа не включено право «Возвраты»
{
"type": "error",
"id": "3c7e1a9b-5d2f-4b8e-a6c4-9e0f1d2c3b4a",
"code": "forbidden",
"description": "Refunds via the API are disabled for this API key: contact AvantPay support"
}
Ошибки
Формат ошибок и общие коды — в разделе Ошибки. Ошибки этого метода:
| HTTP | code | parameter | Когда | Что делать |
|---|---|---|---|---|
| 400 | invalid_request | Idempotence-Key | Нет ключа, ключ длиннее 64 символов или переданы Idempotence-Key и Idempotency-Key с разными значениями. | Передать один ключ до 64 символов. |
| 400 | invalid_request | Idempotence-Key | Ключ уже использован с другим телом запроса. Значит, возврат с этим ключом уже создан. | Не создавать новый возврат, пока не найдёте этот в списке возвратов по payment_id. Новый ключ — только если вы по ошибке взяли этот ключ для другого возврата. |
| 400 | invalid_request | payment_id | Нет payment_id или в нём не 36 символов. | Передать id платежа. |
| 400 | invalid_request | payment_id | Платёж не оплачен: его статус pending или canceled. | Вернуть можно только платёж в статусе succeeded. |
| 400 | invalid_request | payment_id | По платежу уже выполняется возврат. | Дождаться, когда он станет succeeded или canceled, и создать следующий возврат с новым ключом. |
| 400 | invalid_request | payment_id | Платёж уже возвращён полностью. | Ничего: возвращать больше нечего. |
| 400 | invalid_request | payment_id | По платежу уже 10 возвратов. | Написать в поддержку: support@avantpay.io. |
| 400 | invalid_request | payment_id | Платёж нельзя вернуть через API: способ оплаты не поддерживает возвраты, платёж проверяет AvantPay или он не зачислен на счёт магазина. | Написать в поддержку: support@avantpay.io. |
| 400 | invalid_request | amount, amount.value | Нет суммы, сумма не число, больше двух знаков после точки, не больше нуля, больше остатка платежа (остаток — в description) или меньше 1 ₽, но не весь остаток. | Исправить сумму. |
| 400 | invalid_request | amount.currency | Нет валюты, это не код валюты или она не совпадает с валютой платежа. | Передать "RUB". |
| 400 | invalid_request | description | Длиннее 250 символов или не строка. | Сократить комментарий. |
| 400 | invalid_request | metadata | metadata — не объект, больше 16 ключей, длинное имя ключа или значение, значение — массив или объект. | Привести к правилам из раздела metadata. |
| 400 | not_supported | имя поля | Передано поле receipt, sources, deal или refund_method_data с непустым значением. | Убрать поле: деньги возвращаются тем же способом оплаты, чеки AvantPay не отправляет. |
| 400 | invalid_request | — | Тело запроса — не JSON. | Передать правильный JSON. |
| 401 | invalid_credentials | Authorization | Неверный ID магазина или ключ. | Проверить ключи. |
| 403 | forbidden | — | У ключа нет права «Возвраты». | Написать в поддержку: support@avantpay.io. |
| 403 | forbidden | — | Возвраты разрешены только с IP-адресов из списка ключа, а запрос пришёл с другого. | Отправлять запрос с сервера, IP-адрес которого есть в списке, или попросить поддержку добавить адрес. |
| 403 | forbidden | — | Магазин не активен. | Написать в поддержку: support@avantpay.io. |
| 404 | not_found | payment_id | Платежа с таким id нет у вашего магазина. | Проверить id платежа. |
| 413 | invalid_request | — | Тело запроса больше 5 МБ. | Уменьшить тело. |
| 415 | invalid_request | — | Нет заголовка Content-Type: application/json. | Передать заголовок. |
| 429 | too_many_requests | — | Больше 50 запросов в секунду или у магазина уже 20 возвратов в статусе pending. | Подождать retry_after миллисекунд и повторить с тем же ключом. |
| 500 | internal_server_error | — | Сбой у AvantPay. Возврат мог создаться. | Повторить с тем же ключом и тем же телом. |
Если ответа нет совсем (таймаут, обрыв связи), поступите так же, как при ответе 500: повторите запрос с тем же Idempotence-Key и тем же телом.
Если это повтор после таймаута или ответа 500 и пришла ошибка 400, 401 или 403, ключ не меняйте: возврат мог создаться первым запросом. Исправьте причину и повторите с тем же ключом (подробнее).
Отказы по платежу — ошибки 400 с "parameter": "payment_id" — отличаются только текстом description. Не разбирайте этот текст в коде: покажите его сотруднику или запишите в лог. Чтобы понять причину в коде, запросите платёж GET /v3/payments/{payment_id}:
statusнеsucceeded— платёж не оплачен;refunded_amount.valueравенamount.value— платёж возвращён полностью;- запрос
GET /v3/refunds?payment_id=<id платежа>&status=pendingвернул возврат — по платежу идёт возврат: дождитесь его итога; - иначе, если
refundableравенfalse, — вернуть платёж можно только через поддержку: support@avantpay.io.
Получить возврат
Возвращает объект возврата в текущем состоянии.
Параметры пути
refund_idid возврата из ответа на его создание или из списка возвратов.
Ответ
В ответ на запрос придёт объект возврата в актуальном статусе.
Пример запроса
- cURL
- Python
- Node.js
- PHP
curl https://api.avantpay.io/v3/refunds/5e1d7c3a-9b2f-4a6e-8d4c-0f3b2a1e9c87 \
-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_refund(refund_id: str) -> Optional[dict]:
"""Возврат из API; None — у магазина нет такого возврата (404)"""
response = requests.get(
f"https://api.avantpay.io/v3/refunds/{refund_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 getRefund(refundId) {
const response = await fetch(`https://api.avantpay.io/v3/refunds/${ encodeURIComponent(refundId)}`, {
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 getRefund(string $refundId): ?array
{
$ch = curl_init('https://api.avantpay.io/v3/refunds/' . rawurlencode($refundId));
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);
}
Пример ответа
{
"id": "5e1d7c3a-9b2f-4a6e-8d4c-0f3b2a1e9c87",
"payment_id": "2f9b6c1e-4d7a-4c3b-9e8f-1a2b3c4d5e6f",
"status": "succeeded",
"created_at": "2026-10-19T09:40:12.305Z",
"amount": {
"value": "300.00",
"currency": "RUB"
},
"description": "Возврат по заказу №123",
"metadata": {
"order_id": "123"
}
}
Ошибки
| HTTP | code | Когда | Что делать |
|---|---|---|---|
| 404 | not_found | Возврата с таким id нет у вашего магазина. Возврат другого магазина тоже даёт 404. parameter — refund_id. | Проверить id. |
| 401 | invalid_credentials | Неверный ID магазина или ключ. | Проверить ключи. |
| 403 | forbidden | Магазин не активен. | Написать в поддержку: support@avantpay.io. |
| 429 | too_many_requests | Больше 50 запросов в секунду. | Повторить через retry_after миллисекунд. |
| 500 | internal_server_error | Сбой у AvantPay. | Повторить запрос позже. |
Список возвратов
Возвращает возвраты вашего магазина от новых к старым: и созданные через API, и сделанные в личном кабинете. Можно отфильтровать по платежу, статусу и дате создания. Список отдаётся страницами. Заголовок Idempotence-Key этому методу не нужен. Тела у запроса нет.
Параметры запроса
Все параметры необязательные. Передавайте их в строке запроса, каждый — не больше одного раза. Незнакомые параметры API не учитывает.
limitСколько возвратов на странице: от 1 до 100. По умолчанию 10.
cursorЗначение next_cursor из предыдущего ответа — чтобы получить следующую страницу. Передавайте как есть.
payment_idТолько возвраты этого платежа: его id.
statusТолько возвраты с этим статусом: pending, succeeded или canceled.
created_at.gtecreated_at.gtcreated_at.ltecreated_at.ltОтвет
В ответ на запрос придёт объект списка: возвраты в items — объекты возврата в актуальном статусе.
typeВсегда list.
itemsВозвраты — объекты возврата, от новых к старым. Если ничего не нашлось — пустой массив [].
next_cursorКурсор следующей страницы. Нет на последней странице.
Как получить все страницы
- Отправьте запрос с нужными фильтрами.
- Если в ответе есть
next_cursor, повторите запрос с теми же фильтрами и параметромcursor=<значение next_cursor>. - Повторяйте, пока в ответе не будет
next_cursor.
Новые возвраты, пока вы получаете страницы, порядок не сдвигают. Примеры на Python, Node.js и PHP получают все страницы сами.
Пример запроса
Все возвраты по платежу
- cURL
- Python
- Node.js
- PHP
curl "https://api.avantpay.io/v3/refunds?payment_id=c4a8e2f1-9b3d-4f6a-8e1c-7d2b5a9f3e60&limit=10" \
-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_refunds(filters: dict) -> Iterator[dict]:
"""Возвраты по фильтрам со всех страниц: list_refunds({"payment_id": "…"})"""
params = {**filters, "limit": 100}
while True:
response = requests.get(
"https://api.avantpay.io/v3/refunds",
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 r of listRefunds({ payment_id: "…" })) { … }
export async function* listRefunds(filters = {}) {
let cursor;
do {
const params = new URLSearchParams({ ...filters, limit: "100", ...(cursor && { cursor }) });
const response = await fetch(`https://api.avantpay.io/v3/refunds?${ 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 (listRefunds(['payment_id' => '…']) as $refund) { … }
function listRefunds(array $filters): Generator
{
$cursor = null;
do {
$params = $filters + ['limit' => 100] + ($cursor !== null ? ['cursor' => $cursor] : []);
$ch = curl_init('https://api.avantpay.io/v3/refunds?' . 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 $refund) {
yield $refund;
}
$cursor = $page['next_cursor'] ?? null;
} while ($cursor !== null);
}
Пример ответа
{
"type": "list",
"items": [
{
"id": "a3c9e7b1-2d4f-4e6a-9b8c-1f0e2d3c4b5a",
"payment_id": "c4a8e2f1-9b3d-4f6a-8e1c-7d2b5a9f3e60",
"status": "canceled",
"cancellation_details": {
"party": "avantpay",
"reason": "insufficient_funds"
},
"created_at": "2026-10-18T08:12:44.019Z",
"amount": {
"value": "100.00",
"currency": "RUB"
},
"metadata": {}
},
{
"id": "9d4b2e6f-1a3c-4d5e-8f7a-6b5c4d3e2f10",
"payment_id": "c4a8e2f1-9b3d-4f6a-8e1c-7d2b5a9f3e60",
"status": "succeeded",
"created_at": "2026-10-17T19:05:31.642Z",
"amount": {
"value": "50.00",
"currency": "RUB"
},
"description": "Возврат по заказу №122",
"metadata": {
"order_id": "122"
}
}
]
}
Ошибки
| HTTP | code | Когда | Что делать |
|---|---|---|---|
| 400 | invalid_request | limit — не целое число от 1 до 100, cursor — не из next_cursor, дата не в формате ISO 8601, status — незнакомое значение, параметр передан дважды. Имя параметра — в parameter. | Исправить параметр. |
| 401 | invalid_credentials | Неверный ID магазина или ключ. | Проверить ключи. |
| 403 | forbidden | Магазин не активен. | Написать в поддержку: support@avantpay.io. |
| 429 | too_many_requests | Больше 50 запросов в секунду. | Повторить через retry_after миллисекунд. |
| 500 | internal_server_error | Сбой у AvantPay. | Повторить запрос позже. |
Объект уведомления
Уведомление — POST-запрос от AvantPay на ваш сервер о событии (Уведомления).
Запрос приходит с заголовком Content-Type: application/json и телом из трёх полей:
typeВсегда notification.
eventСобытие: payment.succeeded, payment.canceled или refund.succeeded.
objectОбъект на момент события. У payment.succeeded и payment.canceled — объект платежа, как в ответе на GET /v3/payments/{payment_id}. У refund.succeeded — объект возврата, как в ответе на GET /v3/refunds/{refund_id}.
События
payment.succeeded, payment.canceled, refund.succeeded, payment_method.active — когда приходит каждое, на странице Уведомления. Уведомления об отмене возврата нет.
Заголовки
| Заголовок | Что в нём |
|---|---|
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/checkout?paymentId=8d0e4b52-7c19-4a6e-b3f1-5e2a9c7d1b40",
"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"
}
}
}
Заголовки запроса:
POST /avantpay/webhook HTTP/1.1
Host: example.com
Content-Type: application/json
Signature-Timestamp: 1792324800
Signature: v1=07181d18b6de6cfe0c882fd02f7e40c8c0e735f19dc67062c39f57c8d75c995b
Возврат выполнен:
{
"type": "notification",
"event": "refund.succeeded",
"object": {
"id": "5e1d7c3a-9b2f-4a6e-8d4c-0f3b2a1e9c87",
"payment_id": "2f9b6c1e-4d7a-4c3b-9e8f-1a2b3c4d5e6f",
"status": "succeeded",
"created_at": "2026-10-19T09:40:12.305Z",
"amount": {
"value": "300.00",
"currency": "RUB"
},
"description": "Возврат по заказу №123",
"metadata": {
"order_id": "123"
}
}
}
Пример уведомления payment.succeeded — в быстром старте.