Документация Merchant API
Руководство для мерчантов AvaPay: приём платежей (pay-in), выплаты (pay-out), статусы операций, callback-уведомления и апелляции. Все примеры используют тестовые данные.
Обзор
Merchant API позволяет:
- Создавать заявки на входящие платежи и получать реквизиты для оплаты
- Создавать заявки на исходящие выплаты
- Получать callback при смене статуса операции
- Управлять API-ключами и IP whitelist
- Подавать апелляции по спорным pay-in транзакциям
H2H — реквизиты сразу в ответе API;
Invoice — ссылка на платёжную страницу (redirect_url).
Базовый URL
Все эндпоинты payments API:
https://api.avapay.net/api/v1/payments/
Ключи, валюты и платёжные системы доступны в личном кабинете мерчанта (раздел API Keys).
Аутентификация
Каждый запрос к API должен содержать заголовок:
Authorization: Token <ваш_api_token>
| Параметр | Описание |
|---|---|
Token | API token, выдаётся при создании пары ключей (см. ниже) |
private_key | UUID для подписи запросов и проверки callback. Храните только на сервере. |
private_key во frontend, мобильные приложения
и публичную документацию. В примерах ниже используются вымышленные значения.
Подпись запросов
Для всех POST-запросов с телом (pay-in, pay-out, whitelist) обязателен заголовок
Signature.
Алгоритм
- Сериализуйте JSON-тело запроса с сортировкой ключей, без пробелов
- Добавьте к строке ваш
private_key(как текст) - Вычислите SHA-256 hex-дайджест
Signature = SHA256( JSON_sorted(body) + private_key )
Пример (Python)
import hashlib
import json
PRIVATE_KEY = "00000000-0000-4000-8000-000000000001" # пример, не боевой ключ
request_data = {
"amount": "2000.00",
"currency": "KZT",
"payment_system": "C2CKZT",
"merchant_order_id": "order-demo-10001",
"callback_url": "https://merchant.example.com/callbacks/avapay",
"ftd": False,
"client": {
"client_id": "user-demo-42",
"email": "client@example.com",
"phone": "+77000000000",
"name": "Demo Client"
}
}
sorted_json = json.dumps(request_data, sort_keys=True, separators=(",", ":"))
signature = hashlib.sha256((sorted_json + PRIVATE_KEY).encode()).hexdigest()
headers = {
"Authorization": "Token 0000000000000000000000000000000000000000",
"Content-Type": "application/json",
"Signature": signature,
}
Callback-уведомления
При смене статуса pay-in / pay-out AvaPay отправляет POST на callback_url,
указанный при создании заявки.
Тело callback (пример)
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"order_id": "order-demo-10001",
"amount": 2000.0,
"currency": "KZT",
"payment_system": "C2CKZT",
"status": "Success",
"recalculated": false,
"timestamp": 1718123456
}
Заголовок
Signature: <sha256 подпись тела callback + private_key>
Алгоритм тот же, что для исходящих запросов. Всегда проверяйте подпись на своей стороне.
2xx в разумные сроки. При ошибке доставки возможны повторные попытки.
API Keys — создание
POST /api/v1/payments/keys/
Создаёт новую активную пару ключей. Предыдущие активные ключи деактивируются.
Тело запроса: пустое {}
Ответ 201
{
"id": "9e3e624c-175c-496a-a7e7-e408ed671163",
"token": "0000000000000000000000000000000000000000",
"private_key": "00000000-0000-4000-8000-000000000001",
"created_at": "2026-06-01T12:00:00Z",
"whitelist_on": false,
"whitelist_ips": []
}
private_key отображается только при создании. Сохраните его сразу в защищённом хранилище.
API Keys — IP whitelist
POST /api/v1/payments/keys/{id}/whitelist/
{
"whitelist_on": true,
"whitelist": ["203.0.113.10", "203.0.113.11"]
}
Рекомендуется включать whitelist в production.
Pay-in — H2H
POST /api/v1/payments/in/h2h/
Создание заявки с немедленной выдачей реквизитов в поле payment_details.
Тело запроса
{
"amount": "3000.00",
"currency": "KZT",
"payment_system": "C2CKZT",
"merchant_order_id": "order-demo-10002",
"callback_url": "https://merchant.example.com/callbacks/avapay",
"success_url": "https://merchant.example.com/payment/success",
"failed_url": "https://merchant.example.com/payment/failed",
"ftd": false,
"client": {
"client_id": "user-demo-42",
"email": "client@example.com",
"phone": "+77000000000",
"name": "Demo Client"
}
}
| Поле | Обяз. | Описание |
|---|---|---|
amount | да | Сумма в валюте операции (строка или число) |
currency | да | Код валюты, напр. KZT, RUB |
payment_system | да | Имя метода из справочника / договора (напр. Sber, SBP, C2C, C2CKZT) |
merchant_order_id | да | Уникальный ID заказа в вашей системе |
callback_url | да | URL для webhook статусов |
success_url | нет | Редирект при успехе (invoice-режим) |
failed_url | нет | Редирект при ошибке |
ftd | да | true — первый депозит клиента, false — повторный |
client | да | Объект клиента (см. ниже) |
Объект client
| Поле | Обяз. | Описание |
|---|---|---|
client_id | да | Стабильный ID пользователя у мерчанта |
email | нет | Email клиента |
phone | нет | Телефон в международном формате |
name | нет | Имя получателя / плательщика |
Ответ 201 (успех)
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"currency": "KZT",
"amount": "3000.00",
"payment_system": "C2CKZT",
"status": "New",
"merchant_order_id": "order-demo-10002",
"callback_url": "https://merchant.example.com/callbacks/avapay",
"payment_details": {
"card_number": "4000000000000001",
"owner": "Иванов И. И.",
"bank": "Example Bank"
},
"expires_at": 1718127056,
"recalculated": false,
"usd_amount": 5.77
}
Формат payment_details зависит от payment_system:
Sber,C2C,C2CKZT—card_number,owner,bankSBP,SberPay—phone,owner,bankSberDep—deposit_number,bic,owner
min / max) и доступные payment_system настраиваются
индивидуально для вашего мерчанта. Уточняйте в личном кабинете или у менеджера.
Pay-in — Invoice (редирект)
POST /api/v1/payments/in/invoice/
Те же поля, что у H2H. В ответе дополнительно redirect_url — ссылка на hosted-страницу оплаты AvaPay.
Рекомендуется для мерчантов без собственного UI: редирект пользователя на redirect_url, подтверждение — через callback.
Начальный статус: In Progress
Пример запроса
{
"amount": 10000,
"currency": "KZT",
"payment_system": "C2CKZT",
"merchant_order_id": "order-12345",
"callback_url": "https://merchant.example.com/webhook/payin",
"success_url": "https://merchant.example.com/payment/success",
"failed_url": "https://merchant.example.com/payment/fail",
"ftd": false,
"client": { "client_id": "user-42" }
}
Пример ответа 201
{
"id": "03f502ce-572d-4e39-b986-0275597b59f7",
"currency": "KZT",
"amount": "10000.00",
"payment_system": "C2CKZT",
"status": "In Progress",
"merchant_order_id": "order-12345",
"redirect_url": "https://pay.avapay.net/03f502ce-572d-4e39-b986-0275597b59f7",
"payment_details": {
"card_number": "5488880767284602",
"owner": "naira baldarian",
"bank": "bank of georgia"
},
"expires_at": 1782228707,
"success_url": "https://merchant.example.com/payment/success",
"failed_url": "https://merchant.example.com/payment/fail"
}
Схема интеграции
- Backend мерчанта:
POST /api/v1/payments/in/invoice/(Token + Signature) - Редирект пользователя на
redirect_urlиз ответа - Клиент видит страницу оплаты, копирует реквизиты / открывает банк, нажимает «Я оплатил»
- AvaPay шлёт webhook на
callback_urlпри смене статуса - После Success / Failed — редирект на
success_url/failed_url
https://pay.{domain}/{pay_in_id} — C2C / C2CKZT и др.https://payment.{domain}/{id} — SBPhttps://payments.{domain}/{id} — SberPay
Платёжное окно (UI)
Так выглядит hosted-страница для KZT (локализация KZ/RU, переключатель в шапке).
Көрсетілген соманы нақты реквизитке аударыңыз, содан кейін «Төледім» басыңыз.
Экраны
| Экран | Когда |
|---|---|
| Оплата | Реквизиты выданы, таймер активен |
| Ожидаем подтверждение | После «Я оплатил» — статус проверяется, refresh не ведёт на fail |
| Success / Failed | Редирект на success_url / failed_url |
Публичное API платёжной страницы
Вызывается страницей оплаты. Авторизация мерчанта не требуется.
| Метод | URL | Назначение |
|---|---|---|
| GET | /api/v1/payments/in/invoice/{id}/obtain/ | Реквизиты, таймер, bank_actions, locale |
| POST | .../sent/ | Клиент нажал «Я оплатил» |
| POST | .../cancel/ | Отмена платежа |
| GET | .../complete/ | Терминальный статус + URL редиректа |
| POST | .../arbitrage/ | Апелляция (multipart, file) |
Query-параметр ?lang=kk или ?lang=ru на obtain.
Страница: GET https://pay.avapay.net/{pay_in_id}/
Развёртывание (для администратора)
Файлы, которые нужно обновить на сервере для hosted checkout + invoice API.
| Файл | Назначение |
|---|---|
titanpay/templates/payment_page/pay.html | UI страницы оплаты |
titanpay/payments/payment_page.py | Django view страницы |
titanpay/payments/payment_page_enrich.py | locale, bank_actions для obtain |
titanpay/payments/bank_deeplinks.py | Kaspi / Homebank кнопки |
titanpay/payments/invoice_obtain.py | obtain по статусу |
titanpay/payments/viewsets.py | obtain, complete |
titanpay/payments/serializers.py | waiting_confirmation |
titanpay/titanpay/urls.py | /{uuid}/ маршрут страницы |
titanpay/trade/utils2.py | expire: не сбрасывать «Money sent by user» |
docker-compose (Traefik)
# app.environment
PAYMENT_PAGE_URL=avapay.net
PUBLIC_API_URL=https://api.avapay.net
# app.labels — router pay.avapay.net → app:8080
# DNS A: pay.avapay.net, payment.avapay.net, payments.avapay.net
docker compose build app && docker compose up -d app traefik
HTTPS и favicon на pay.avapay.net
pay.avapay.net.
Проверьте DNS, Traefik labels и логи ACME.
dig +short pay.avapay.net— A-запись на IP сервера- Traefik router с
tls.certresolver=letsencryptдляpay.avapay.net docker compose logs traefik 2>&1 | grep -i acme- После выпуска cert — предупреждение браузера исчезнет
Favicon задаётся в pay.html (inline SVG логотип AvaPay). Обновите образ app после деплоя шаблона.
Статусы pay-in
| Статус | Описание |
|---|---|
| New | Заявка создана, ожидается оплата (H2H) |
| In Progress | В обработке (invoice-режим) |
| Success | Платёж подтверждён |
| Failed | Ошибка / истечение без оплаты |
| Declined | Заявка отклонена при создании (нет реквизитов, лимиты, метод неактивен) |
Поле expires_at — Unix timestamp, до которого действительны реквизиты.
Дополнительные действия pay-in
Получить заявку
GET /api/v1/payments/in/h2h/{id}/
Отметить «деньги отправлены»
POST /api/v1/payments/in/h2h/{id}/sent/
Для invoice: /api/v1/payments/in/invoice/{id}/sent/ (вызывается со страницы оплаты)
Отмена заявки
POST /api/v1/payments/in/h2h/{id}/cancel/
Для invoice: /api/v1/payments/in/invoice/{id}/cancel/
Апелляция
POST /api/v1/payments/in/h2h/{id}/arbitrage/
Для invoice: /api/v1/payments/in/invoice/{id}/arbitrage/
Формат: multipart/form-data, поле file — PNG, JPEG или PDF (до 5 MB).
Используйте, если клиент утверждает, что оплатил, а статус не перешёл в Success.
Pay-out — H2H
POST /api/v1/payments/out/h2h/
{
"amount": "5000.00",
"currency": "RUB",
"payment_system": "Sber",
"merchant_order_id": "payout-demo-20001",
"callback_url": "https://merchant.example.com/callbacks/avapay-payout",
"ftd": false,
"client": {
"client_id": "user-demo-42",
"email": "client@example.com",
"phone": "+79000000000",
"name": "Demo Client"
},
"details": {
"card_number": "4000000000000002"
}
}
Поле details обязательно. Набор полей зависит от payment_system — см. required_fields в справочнике.
Справочник валют
GET /api/v1/payments/currencies/
Возвращает валюты, доступные вашему мерчанту.
[
{ "symbol": "KZT" },
{ "symbol": "RUB" }
]
Справочник платёжных систем
GET /api/v1/payments/payment-systems/
[
{
"name": "C2CKZT",
"currency": "KZT",
"required_fields": {
"card_number": {
"regex": "^\\d{16}$",
"pattern": "16 digits"
}
}
}
]
Типичные ошибки
| HTTP | Сообщение | Причина |
|---|---|---|
| 403 | Invalid signature | Неверная подпись тела запроса |
| 403 | Signature required | Нет заголовка Signature на POST |
| 403 | This IP is not in whitelist | IP не в whitelist API-ключа |
| 400 | This method is not active | Метод не подключён или неверный ftd |
| 400 | Amount out of limits! | Сумма вне лимитов для метода |
| 400 | Order with such merchant_order_id already exists | Дубликат ID заказа |
| 400 | Could not allocate payment requisites... | Временно нет реквизитов — повторите позже или другую сумму |
Безопасность
- Храните
private_keyтолько на backend - Используйте HTTPS для callback URL
- Включите IP whitelist в production
- Проверяйте подпись каждого callback
- Не логируйте полные реквизиты карт в открытом виде
- Ротируйте ключи при компрометации: создайте новую пару в кабинете
Чеклист запуска
- Получите доступ в личный кабинет AvaPay
- Создайте API Keys, сохраните
tokenиprivate_key - Реализуйте подпись исходящих POST-запросов
- Реализуйте приём и проверку callback
- Для redirect-интеграции:
POST /in/invoice/→ редирект наredirect_url - Укажите
success_urlиfailed_urlдля возврата клиента после оплаты - Проверьте доступные
payment_systemи лимиты для вашего аккаунта - Проведите тестовые заявки на минимальных суммах
- Включите IP whitelist перед production
Техническая поддержка: обращайтесь к вашему менеджеру AvaPay.