NetPay Payment Aggregator API (1.0.0)

NetPay Payment Aggregator API

API для работы с платёжным агрегатором NetPay.

Основные возможности

  • 💰 PayIn - получение реквизитов для оплаты
  • 💸 PayOut - выплаты на карты и СБП
  • 💳 Управление балансом - получение информации о балансе
  • 🔔 Callback - уведомления об изменении статуса платежей

Начало работы

1. Первоначальная настройка

Перед использованием API необходимо выполнить настройку:

Предусловия

  • Аккаунт зарегистрирован и доступен вход в систему
  • Доступ к API выдан администратором
  • OTP (2FA) подключён

Шаги настройки

  1. Запросить доступ к API - напишите администратору в рабочем чате
  2. Подключить OTP (2FA) - перейдите в Профиль → включите OTP
  3. Создать API‑ключи - перейдите в Профиль → раздел API‑ключи → Создать
    • Сохраните: uuid, public_key, private_key
    • ⚠️ private_key, public_key показываются один раз - сохраните сразу!
  4. Настроить права ключа - включите Trading для создания заявок
  5. Создать платформу - перейдите в раздел Платформы → Создать платформу
    • Запросите модерацию в рабочем чате
    • После модерации получите ID платформы

Термины

  • ID платформы - идентификатор платформы для разделения трафика
  • uuid (kid) - идентификатор API‑ключа
  • public_key - публичная часть ключа
  • private_key - секрет для подписи запросов (хранить конфиденциально!)
  • Trading - право на торговые операции

2. Аутентификация

Все запросы (кроме получения токена) требуют JWT аутентификации:

Authorization: JWT <token>

Подробнее см. эндпоинт /session/jwt/ в разделе "Authentication".

Callback (уведомления о статусе)

Сервис отправляет callback на ваш URL при изменении статуса:

  • PayIN (входящий платёж)
  • PayOut (выплата)

Callback отправляется HTTP POST с JSON телом.

1) Верификация подписи (что запрос пришёл от сервиса)

Сервис добавляет HTTP‑заголовок:

X-Token-Sign: <signature_base64>

Алгоритм подписи

  • RSA + SHA‑256 (PKCS#1 v1.5)
  • X-Token-Sign — это base64 от байтов подписи.

Что именно подписывается

Подписываемая строка строится так:

REQUEST_METHOD + "\n" + BODY_RAW

Где:

  • REQUEST_METHOD — HTTP‑метод (например, POST)
  • BODY_RAWсырой текст тела запроса

Пример: валидация подписи (Python / pyOpenSSL)

Требования:

  • pyOpenSSL==23.2.0

Важно:

  • raw_body должен быть bytes, полученный от веб‑фреймворка (например, request.body), без любых изменений.
  • method должен быть тем, что пришло в запросе (POST).
  • строка для проверки строится ровно как METHOD + "\n" + raw_body.decode("utf-8") (перенос строки — \n).
import base64
from OpenSSL import crypto

# PEM строка публичного ключа сервиса
PUBLIC_KEY_PEM = """-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvocGJQ8SeTO7sWe6Qkyd
7aeLC/PBKhvzZOhm6U7h6IzY2xHDQHbu6fvEqVqmLZML7LXmLUmcBXptD7ENSXzi
en0oweQXVQJNi6CRGFZNXlmiimG7xoUu77tLyAyP8RxZnEKOHOADO0Vom6tsVYdE
vQfz66so6e2IRTKWW8OXgpx4WW14MjepShxMYpP9t+WMYnG3y/+nzb8Y53u3ZO07
hFfveOIAtoXVPZvDUnFd+iJHZSePhnxlf2tiln2rOPVth5vpezMISbQJRqPgmHk/
jN4hPsJkIn+OuM/med4xaUA50Uqg+7cYeDVIcQfm/IoIhyq/uGn+zUi46MrrF44I
PQIDAQAB
-----END PUBLIC KEY-----"""


def verify_callback_signature(method: str, raw_body: bytes, x_token_sign: str) -> bool:
    message = method.upper() + "\n" + raw_body.decode("utf-8")
    signature = base64.b64decode(x_token_sign)

    pub_key = crypto.load_publickey(crypto.FILETYPE_PEM, PUBLIC_KEY_PEM)
    cert = crypto.X509()
    cert.set_pubkey(pub_key)

    try:
        crypto.verify(cert, signature, message.encode("utf-8"), "sha256")
        return True
    except Exception:
        return False

Публичный ключ сервиса

Публичный ключ для проверки подписи:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvocGJQ8SeTO7sWe6Qkyd
7aeLC/PBKhvzZOhm6U7h6IzY2xHDQHbu6fvEqVqmLZML7LXmLUmcBXptD7ENSXzi
en0oweQXVQJNi6CRGFZNXlmiimG7xoUu77tLyAyP8RxZnEKOHOADO0Vom6tsVYdE
vQfz66so6e2IRTKWW8OXgpx4WW14MjepShxMYpP9t+WMYnG3y/+nzb8Y53u3ZO07
hFfveOIAtoXVPZvDUnFd+iJHZSePhnxlf2tiln2rOPVth5vpezMISbQJRqPgmHk/
jN4hPsJkIn+OuM/med4xaUA50Uqg+7cYeDVIcQfm/IoIhyq/uGn+zUi46MrrF44I
PQIDAQAB
-----END PUBLIC KEY-----

2) Повторные попытки доставки

Callback отправляется с повторами при ошибках:

  • до 10 повторов
  • с увеличивающейся задержкой (retry backoff)

Успешной доставкой считается:

  • PayIN: HTTP 200 / 201 / 202
  • PayOut: HTTP 200 / 202

3) Callback для PayIN (входящий платёж)

Статусы PayIN

Статус находится в payment.status:

Значение Смысл
created Создана
in_progress В работе
success Выполнена
success_incorrect_amount Выполнена с неверной суммой
cancelled Отменена/истекла
failed Не удалось обработать

Тело callback (PayIN)

{
  "payment": {
    "id": "13a840e4-f078-4efc-9372-008ac038dee3",
    "external_id": "my-pay-in-id-001",
    "total": "20.60",
    "fee": "0.60",
    "fee_native": "60.00",
    "amount": "20.00",
    "amount_native": "2000.00",
    "received_amount": "10.00",
    "received_amount_native": "1000.00",
    "rate": "100",
    "redirect_url": "https://example.com/redirect",
    "paymethod": 3547,
    "paymethod_description": "Сбербанк",
    "date_created": 1697798134,
    "timeout": 900,
    "status": "success_incorrect_amount",
    "card": "4111111111100031",
    "name": "Иванов И.",
    "cancel_message": null
  },
  "platform": {
    "name": "client",
    "id": "127ea230-ab27-4941-bf1f-8fd2ceaf92d1"
  }
}

Примечания:

  • Все денежные поля обычно приходят строками.
  • external_id — это ваш id, который вы передавали при создании.

5) Callback для PayOut (выплата)

Статусы PayOut

Статус находится в payment.status:

Значение Смысл
created Создана
in_progress В обработке
confirmed Выполнена
cancelled Отменена
failed Ошибка

Тело callback (PayOut)

{
  "payment": {
    "id": 1,
    "external_id": "Your Payment #100",
    "amount": "100",
    "amount_native": "10000",
    "rate": "100",
    "fee": "1",
    "fee_native": "100",
    "total": "101",
    "date_created": 1697809937,
    "date_closed": 0,
    "sbp": false,
    "status": "confirmed",
    "details": "1111111111111111",
    "comment": "Комментарий",
    "cancel_comment": null,
    "cheque": {
      "content": null,
      "ext": null
    },
    "paymethod": 3547,
    "paymethod_description": "Сбербанк"
  }
}

Примечания:

  • Если sbp=true, дополнительно придут bank и bank_namepaymethod может отсутствовать).

Основные операции

Авторизация и управление балансом

Получение JWT токена

Эндпоинт для получения JWT токена на основе подписанного JWT request.

Проекты NetPay используют JWT авторизацию (см. jwt.io и RFC 7519).

Общая схема

  1. Сформировать JWT request (подписанный вашим приватным ключом алгоритмом RS256)
  2. Отправить JWT request на сервер и получить в ответ JWT token (access token)
  3. Сохранить JWT token и использовать его в API запросах как:
    Authorization: JWT <token>
    

Важно: не нужно получать новый token на каждый запрос. Получайте новый token только при истечении срока действия или при отзыве/перевыпуске ключей.

TTL (сроки жизни)

Есть два разных TTL:

  • JWT token (который возвращает сервер): TTL определяется настройками API‑ключа
    • Минимум: 30 минут
    • Максимум: 24 часа
    • По умолчанию: 24 часа
  • JWT request (который вы подписываете и отправляете на сервер): его exp вы задаёте сами. Делайте его коротким (например, 5–60 минут)

Параметры JWT request (который вы подписываете)

  • jti (обязательно): уникальный идентификатор запроса (случайное значение достаточной длины, минимум 12 байт)
  • exp (рекомендуется): время истечения JWT request в формате Unix time (секунды)
  • Алгоритм подписи: RS256

Формат запроса

  • Приватный ключ хранится как base64 строка, внутри которой лежит PEM RSA private key
  • kid — это UID/uuid API-ключа

Частые ошибки

  • jti слишком короткий или не уникальный (нужна достаточная энтропия, например 12+ байт)
  • Использование ID платформы вместо uuid API ключа
  • Неправильный формат приватного ключа: для RS256 требуется RSA private key в PEM
  • Получение нового token на каждый запрос (не нужно!)
Request Body schema: application/json
required
kid
required
string

UID/идентификатор API-ключа

jwt_token
required
string

Подписанный JWT request (алгоритм RS256)

Responses

Response Schema: application/json
token
string

JWT access token для использования в последующих запросах

Request samples

Content type
application/json
{
  • "kid": "550e8400-e29b-41d4-a716-446655440000",
  • "jwt_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MDc5MDk2MDAsImp0aSI6ImFiY2RlZjEyMzQ1Njc4OTAifQ.signature"
}

Response samples

Content type
application/json
{
  • "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Получение баланса

Эндпоинт для получения информации о балансе аккаунта пользователя.

Параметры запроса отсутствуют — эндпоинт возвращает информацию о балансе текущего пользователя, определённого по JWT токену.

Права доступа: API ключу достаточно иметь права read-only

Описание полей ответа

Основной баланс (balance)

Поле Тип Описание
balance string (decimal) Общий баланс пользователя в USDT (с учётом замороженных средств). Формат: "{:.2f}" (2 знака после запятой)
available string (decimal) Доступный баланс (общий минус замороженный): balance - frozen. Формат: "{:.2f}"
frozen string (decimal) Замороженные средства (средства, зарезервированные для активных платежей/выплат). Формат: "{:.2f}"

Кошельки (wallets)

Объект, где ключ — код валюты (например, "RUB", "USD"), а значение — объект с информацией о кошельке:

Поле Тип Описание
currency string Код валюты кошелька (например, "RUB", "USD")
uuid string (UUID) Уникальный идентификатор кошелька
balance string (decimal) Общий баланс кошелька в указанной валюте (с учётом замороженных средств). Формат: "{:.2f}"
available string (decimal) Доступный баланс кошелька: balance - frozen. Формат: "{:.2f}"
frozen string (decimal) Замороженные средства на кошельке. Формат: "{:.2f}"

Примечание: Если у пользователя нет кошельков в других валютах, объект wallets будет пустым {}.

Важные моменты

  1. Основной баланс в USDT: Поле balance на верхнем уровне относится к основному балансу пользователя в USDT
  2. Формат чисел: Все суммы возвращаются как строки с двумя знаками после запятой (формат "{:.2f}"). Для вычислений необходимо преобразовывать в Decimal или float
  3. Замороженные средства: Поле frozen показывает средства, зарезервированные для активных операций (например, созданные, но ещё не обработанные выплаты)
  4. Кошельки: Если у пользователя нет кошельков в других валютах, объект wallets будет пустым {}
Authorizations:
JWTAuth

Responses

Response Schema: application/json
username
string
email
string <email>
object

Основной баланс в USDT

object

Кошельки в различных валютах

Request samples

import requests

host = "{HOST, уточнить у поддержки}"
token = "{JWT токен}"

response = requests.get(
    f"https://{host}/api/papi/accounts/get/",
    headers={
        "Authorization": f"JWT {token}",
        "Content-Type": "application/json"
    }
)

if response.status_code == 200:
    data = response.json()
    print(f"Username: {data['username']}")
    print(f"Balance (USDT): {data['balance']['balance']}")
    print(f"Available: {data['balance']['available']}")
    
    for currency, wallet in data['wallets'].items():
        print(f"\nWallet {currency}:")
        print(f"  Balance: {wallet['balance']}")
        print(f"  Available: {wallet['available']}")

Response samples

Content type
application/json
{
  • "username": "merchant_username",
  • "email": "[email protected]",
  • "balance": {
    },
  • "wallets": {
    }
}

PayIn

Входящие платежи

Callbacks: При изменении статуса платежа сервер отправляет webhook на указанный callback_url. См. документацию по верификации подписи в схеме CallbackPayIn.

Создание входящего платежа (получение реквизитов)

Создание входящего платежа и получение реквизитов для оплаты.

Обязательные поля

Поле Тип Описание
platform string (UUID) UUID платформы. Платформа должна принадлежать текущему пользователю и быть активной
currency string Код валюты (например, RUB). Рекомендуется передавать валюту, соответствующую выбранному paymethod
client_id string Идентификатор клиента в вашей системе
paymethod integer Код метода оплаты. Запрашивается в рабочем чате
amount string/number (Decimal) Сумма в "нативной" валюте зачисления. Обязательно, если usdt_amount не передан
usdt_amount string/number (Decimal) Сумма в USDT для пересчёта в нативную валюту. Обязательно, если amount не передан

Важно: Нужно передать ровно одно из полей: amount или usdt_amount.

Опциональные поля

Поле Тип Описание
callback_url string (URL) URL для коллбеков по платежу
id string Ваш внешний идентификатор платежа
bank string Наименование банка отправителя

Что возвращается

  • link - ссылка на виджет/страницу оплаты
  • card - реквизиты (вне зависимости от метода оплаты)
  • wallet - реквизиты кошелька (если применимо)
  • name - получатель платежа
  • paymethod_description - возвращается название банка
  • timeout - время жизни заявки в секундах
  • date_created - Unix time (секунды)
  • Числовые поля могут возвращаться как строки (в зависимости от JSON сериализации Decimal)
Authorizations:
JWTAuth
Request Body schema: application/json
required
platform
required
string <uuid>

UUID платформы

currency
required
string

Код валюты (например, RUB, USD)

client_id
required
string

Идентификатор клиента в вашей системе

paymethod
required
integer

Код метода оплаты (запрашивается в рабочем чате)

amount
string

Сумма в нативной валюте (обязательно, если нет usdt_amount)

usdt_amount
string

Сумма в USDT (обязательно, если нет amount)

callback_url
string <uri>

URL для callback уведомлений

id
string

Ваш внешний идентификатор платежа

Responses

Response Schema: application/json
ok
boolean
message
string
object (PayInPayment)

Callbacks

Request samples

Content type
application/json
Example
{
  • "platform": "e2488acf-4c5c-4859-b24a-35f09d9e105a",
  • "currency": "RUB",
  • "client_id": "client-123",
  • "paymethod": 102120,
  • "amount": "10000",
  • "callback_url": "https://example.com/callback",
  • "id": "my-payment-001"
}

Response samples

Content type
application/json
{
  • "ok": true,
  • "message": "Универсальная обработка: выбран метод оплаты: 102120",
  • "payment": {
    }
}

Callback payload samples

Callback
POST: Callback при изменении статуса PayIn
Content type
application/json
{
  • "payment": {
    },
  • "platform": {
    }
}

Получение информации о входящем платеже

Получение детальной информации о входящем платеже по его UUID.

Важно: метод ищет только по внутреннему UUID заявки (поле id в ответе при создании), а НЕ по вашему внешнему external_id.

Обязательные поля

Поле Тип Описание
id string (UUID) UUID заявки в нашей системе. Метод не ищет по вашему внешнему id

Статусы PayIn

Значение Смысл
created Заявка создана, реквизиты ещё не получены / процессинг не завершён
in_progress Заявка в работе (реквизиты выданы, ожидается оплата)
success Заявка успешно завершена на верную сумму
success_incorrect_amount Заявка завершена, но сумма поступления отличается от ожидаемой
cancelled Заявка отменена/истекла
failed Не удалось обработать заявку (ошибка процессинга)
Authorizations:
JWTAuth
Request Body schema: application/json
required
id
required
string <uuid>

UUID заявки в системе NetPay

Responses

Response Schema: application/json
ok
boolean
object
object

Request samples

Content type
application/json
{
  • "id": "e2488acf-4c5c-4859-b24a-35f09d9e105a"
}

Response samples

Content type
application/json
{
  • "ok": true,
  • "payment": {
    },
  • "platform": {
    }
}

PayOut

Исходящие платежи (выплаты)

Callbacks: При изменении статуса выплаты сервер отправляет webhook на указанный callback_url. См. документацию по верификации подписи в схеме CallbackPayOut.

Создание выплаты

Создание исходящей выплаты на карту или через СБП.

Поля верхнего уровня

Поле Тип Обязательность Описание
platform string (UUID) Да UUID платформы/витрины. Платформа должна принадлежать пользователю и быть активной
payment object Да Данные выплаты (см. ниже)

Поля payment

Обязательные поля

Поле Тип Описание
details string Реквизит для выплаты: номер карты или номер телефона для СБП. Допустимы только цифры, пробелы и + (другие символы вроде - приведут к ошибке Incorrect Details)
amount string/number (Decimal) Сумма выплаты (сервер конвертирует/округляет до 2 знаков)
paymethod integer Код метода оплаты
bank integer ID банка. Обязателен для СБП (Запрашивается в рабочем чате)

Опциональные поля

Поле Тип Описание
callback_url string (URL) или null URL для коллбеков
comment string Комментарий к выплате
id string Ваш внешний идентификатор выплаты

Важные моменты

  • details - допустимы только цифры, пробелы и + (символы - могут вызвать ошибку)
  • Для СБП обязательно поле bank (ID банка)
  • При успешном создании средства замораживаются на балансе
  • Если ответ не 200, выплата не считается созданной

Статусы PayOut

Значение Смысл
created Выплата создана (средства уже заморожены)
in_progress Выплата в обработке
confirmed Выплата выполнена успешно
cancelled Выплата отменена
failed Ошибка при обработке выплаты
Authorizations:
JWTAuth
Request Body schema: application/json
required
platform
required
string <uuid>

UUID платформы

required
object

Responses

Response Schema: application/json
ok
boolean
message
string
object (PayOutPayment)

Callbacks

Request samples

Content type
application/json
Example
{
  • "platform": "dbe7dd2e-7481-4ade-92c0-227ea5b758aa",
  • "payment": {
    }
}

Response samples

Content type
application/json
{
  • "ok": true,
  • "message": "Payment(s) successfully created.",
  • "payment": {
    }
}

Callback payload samples

Callback
POST: Callback при изменении статуса PayOut
Content type
application/json
{
  • "payment": {
    }
}

Получение информации о выплате

Получение детальной информации о выплате.

Нужно передать одно из полей: id или external_id.

Поля

Поле Тип Обязательность Описание
id integer/string (число) Да* Внутренний ID выплаты. Также допускается передать ваш внешний ID
external_id string Да* Ваш внешний ID выплаты

* Если id не передан — обязателен external_id, и наоборот.

Статусы выплаты

Значение Смысл
created Выплата создана (средства заморожены), ожидает обработки
in_progress Выплата в обработке
confirmed Выплата выполнена успешно
cancelled Выплата отменена
failed Ошибка при обработке выплаты

Примечание: Если sbp=true, вместо paymethod/paymethod_description возвращаются поля bank и bank_name. Часть числовых полей может возвращаться как строки (Decimal).

Authorizations:
JWTAuth
Request Body schema: application/json
required
id
integer

Внутренний ID выплаты

external_id
string

Ваш внешний ID выплаты

Responses

Response Schema: application/json
ok
boolean
object (PayOutPayment)

Request samples

Content type
application/json
Example
{
  • "id": 120123
}

Response samples

Content type
application/json
{
  • "ok": true,
  • "payment": {
    }
}