a1b2

Документация API

Базовый адрес — https://api.a1b2.io. Все тела запросов и ответов в JSON.

Быстрый старт

Заведите проект в кабинете и выпустите ключ. Ключей два типа, и они не взаимозаменяемы: payment открывает приём средств, payout — отправку. Разделение намеренное: ключ, лежащий на витрине сайта, не должен уметь выводить деньги.

Полный ключ показывается один раз при создании — дальше в кабинете видна только маска.

Подпись запросов

Каждый запрос несёт два заголовка:

ЗаголовокЗначение
projectUUID проекта
signhex(HMAC-SHA256(base64(body), api_key))

Подписывается base64 от тела, а не само тело. Для запросов без тела подписывается пустая строка. Подпись принимается только в нижнем регистре.

// Node.js
import { createHmac } from 'node:crypto';

const sign = (body, key) =>
  createHmac('sha256', key)
    .update(Buffer.from(body).toString('base64'))
    .digest('hex');

const body = JSON.stringify({ order_id: 'ORD-1', amount: '100.00', base_currency: 'USD' });

await fetch('https://api.a1b2.io/v1/payment', {
  method: 'POST',
  headers: {
    'content-type': 'application/json',
    project: PROJECT_ID,
    sign: sign(body, API_KEY),
  },
  body,
});
Подписывайте ровно те байты, которые уходят в сеть. Если сериализовать объект дважды — например, собрать body для подписи и отдельно передать объект в HTTP-клиент — порядок ключей может отличиться, и подпись не сойдётся.

Приём платежей

POST/v1/paymentключ payment

Создаёт счёт в фиате. Криптовалюту и сеть выбирает плательщик на платёжной странице — курс фиксируется в момент выбора.

ПолеТипОписание
order_idstringВаш идентификатор заказа. Должен быть уникален в проекте.
amountstringСумма в фиате. Строкой, чтобы не терять точность.
base_currencystringВалюта суммы, например USD.
invoice_ttl_secondsnumberНеобязательно. Срок жизни счёта.
success_urlstringНеобязательно. Куда вернуть плательщика после оплаты.
{
  "uuid": "62a37ad7-d0c3-4a4d-a103-f70d4e34b836",
  "order_id": "ORD-901",
  "status": "awaiting_selection",
  "currency": "", "network": "", "address": "",
  "pay_amount": "0",
  "expires_at": "2026-08-31T09:43:28Z"
}

Отправьте плательщика на https://pay.a1b2.io/pay/{uuid}. Как только он выберет сеть, счёт получит адрес, точную сумму в крипте и перейдёт в pending.

POST/v1/payment/infoключ payment

Статус счёта по uuid или order_id. Если переданы оба, приоритет у order_id.

POST/v1/payment/listключ payment

Список счетов проекта. Поле limit ограничивает выдачу.

GET/v1/balanceключ payment

Балансы по валютам: доступно и в резерве.

Постоянные адреса

Адрес закрепляется за парой «заказ + валюта/сеть» и принимает переводы неограниченно. Подходит для пополнения счёта и донатов, где выставлять счёт на каждый перевод неудобно.

POST/v1/static-walletключ payment
ПолеОписание
currencyОбязательно. Например USDT.
networkОбязательно. Например TRX-TRC20.
order_idОбязательно. Ваш идентификатор пользователя или счёта.
labelНеобязательно. Пометка для кабинета.
url_callbackНеобязательно. Адрес для вебхуков по этому кошельку.

Повторный вызов с теми же параметрами вернёт существующий адрес, а не создаст новый. Остальные операции: /v1/static-wallet/info, /list, /transactions, /enable, /disable.

Выплаты

POST/v1/payoutключ payout
ПолеОписание
order_idВаш идентификатор выплаты.
currencyВалюта, например USDT.
networkСеть, например TRX-TRC20.
to_addressАдрес получателя.
amountСумма.
fee_optiondeduct — комиссия из суммы, add — сверх неё.

Крупные суммы и выплаты в TRON уходят в статус pending_approval и ждут подтверждения оператором. Это защита от увода баланса при утечке ключа.

POST/v1/payout/calcключ payout

Расчёт без создания выплаты: сколько получит получатель и сколько спишется с баланса.

GET/v1/payout/status/{uuid}ключ payout

Вебхуки

На адрес из настроек проекта уходит POST при каждой смене статуса. Тело подписано тем же алгоритмом, заголовок — sign.

{
  "event": "payment.paid",
  "uuid": "62a37ad7-d0c3-4a4d-a103-f70d4e34b836",
  "status": "paid",
  "pay_amount": "665.065842",
  "received_amount": "665.065842"
}

События: payment.* (по статусу платежа), static_wallet.deposit, payout.completed, payout.failed.

Проверяйте подпись перед тем, как поверить телу — иначе кто угодно, знающий ваш адрес обработчика, сможет отметить заказ оплаченным. Отвечайте 2xx: любой другой код считается неудачей, и доставка повторится.

Повторы идут с нарастающей паузой. Исчерпав попытки, доставка переходит в dead — такие видны в разделе «Вебхуки» кабинета.

Статусы

Платежи

СтатусЗначение
awaiting_selectionСчёт создан, плательщик ещё не выбрал сеть
pendingОжидается перевод на адрес
checkПеревод виден, ждём подтверждений сети
paidОплачен полностью
underpaidПришло меньше суммы счёта
overpaidПришло больше суммы счёта
cancelОтменён или истёк
aml_lockЗадержан проверкой

Выплаты

СтатусЗначение
pendingПринята в обработку
pending_approvalЖдёт подтверждения оператором
processingОтправляется в сеть
completedОтправлена
failedНе удалась, средства возвращены на баланс
cancelledОтменена

Ошибки

Не-2xx ответ содержит код и описание:

{ "error": { "code": "insufficient_balance", "message": "..." } }
КодКогда возникает
unauthorizedНеверная подпись или проект
bad_requestНе хватает обязательного поля или тело не разобрать
not_foundОбъект не найден в вашем проекте
duplicate_order_idТакой order_id уже есть в проекте
insufficient_balanceНедостаточно средств для выплаты
network_not_allowedНаправление не включено в проекте
no_networks_enabledВ проекте не включено ни одно направление
amount_out_of_rangeСумма вне допустимых границ направления
invoice_expiredСрок счёта истёк
selection_lockedСеть уже выбрана и не меняется
rates_unavailableКурсы временно недоступны