документация API для мерчантов · v1

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

Finem принимает оплату в USDT (TRC-20, сеть TRON) по инвойсовой модели: вы создаёте инвойс через API, показываете покупателю ссылку на страницу оплаты, Finem отслеживает поступление в блокчейне и уведомляет вас вебхуком.

Как это работает

  1. Ваш сервер создаёт инвойс — POST /api/invoice — и получает paymentUrl.
  2. Покупатель переходит по paymentUrl: видит сумму в USDT, QR-код и адрес кошелька, отправляет перевод.
  3. Finem видит транзакцию в сети (статус Confirming), дожидается подтверждения и закрывает инвойс (Success).
  4. На каждую смену статуса вам уходит вебхук на urlCallback.

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

Создание инвойса аутентифицируется двумя заголовками:

ApiKey (секрет из панели) по сети не передаётся — участвует только в вычислении подписи. Не публикуйте его в клиентском коде и репозиториях. Подпись считается на сервере магазина над той же байтовой строкой тела, которая реально уходит в запросе (иначе подпись не сойдётся).

# псевдокод
body = '{"amount":1000,"currency":"RUB","orderId":"shop-order-482"}'
sign = md5( base64_encode(body) + API_KEY )

# заголовки:
merchant: 3f2b8c1e-…      (Merchant ID)
sign:     e99a4f0c…       (подпись тела)

Так же подписываются и остальные POST-запросы мерчанта (resend-webhook, test-webhook).

Создание инвойса

POST/api/invoice
ПолеТипОписание
amount обязательноеnumber Сумма в валюте currency. Больше нуля.
currency обязательноеstring Код валюты: фиат (RUB, KZT, …) или USDT. Фиат конвертируется в USDT по курсу на момент создания, курс фиксируется в инвойсе.
orderId обязательноеstring Идентификатор заказа в вашей системе. Ключ идемпотентности: повторный запрос с тем же orderId вернёт уже созданный инвойс, а не новый.
lifetimeint Срок жизни инвойса в секундах, 300–43200. По умолчанию 1800 (30 минут).
urlCallbackstring URL для вебхуков по этому инвойсу. Если не задан — берётся callback-адрес мерчанта из профиля.
urlSuccessstring Кнопка «Вернуться в магазин» на странице оплаты после успешной оплаты.
urlReturnstring Кнопка возврата при отмене или недоплате.
curl -X POST {baseUrl}/api/invoice \
  -H "merchant: <Merchant ID>" -H "sign: <md5(base64(тело)+ApiKey)>" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 1000,
    "currency": "RUB",
    "orderId": "shop-order-482",
    "urlCallback": "https://shop.example/finem/hook",
    "urlSuccess": "https://shop.example/thanks"
  }'

Ответ:

{
  "orderId": 42,
  "merchantOrderId": "shop-order-482",
  "paymentUrl": "{baseUrl}/pay.html?pt=WtzAkHHVPP-RMV3lhpcazQ...",
  "walletAddress": "T...",
  "network": "TRC20",
  "amountUsdt": 10.53,
  "amountFiat": 1000,
  "currency": "RUB",
  "rate": 95,
  "status": "Pending",
  "expiresAt": "2026-07-05T12:00:00Z"
}

paymentUrl — ссылка для покупателя. amountUsdt — сумма, которую он должен отправить (страница оплаты показывает её сама).

Статус инвойса

GET/api/invoice/status?pt={token}

Публичный эндпоинт (без ключа): pt — токен из paymentUrl. Его же опрашивает страница оплаты. Удобен, чтобы сверить статус при получении вебхука.

{
  "orderId": 42,
  "status": "Success",
  "walletAddress": "T...",
  "network": "TRC20",
  "amountUsdt": 10.53,
  "amountFiat": 1000,
  "receivedUsdt": 12.0,
  "paidOver": true,
  "currency": "RUB",
  "expiresAt": "2026-07-05T12:00:00Z",
  "uiPollSeconds": 5,
  "urlSuccess": "https://shop.example/thanks",
  "urlReturn": null
}

Статусы и жизненный цикл

Основной путь: Pending → Confirming → Success. Терминальные статусы: Success, WrongAmount, Expired, Canceled.

СтатусЗначение
Pending Инвойс создан, ждём поступление в блокчейне.
Confirming Транзакция видна в сети, ждём подтверждения. Деньги ещё не зачислены. Обычно длится меньше минуты.
Success Оплачено и подтверждено сетью. receivedUsdt — фактически полученная сумма; при переплате в пределах допуска paidOver = true, зачисляется всё полученное.
WrongAmount Недоплата сверх допуска. Терминальный: инвойс закрыт, средства ожидают ручного разбора оператором. Покупатель видит «получена неполная сумма».
Expired Не оплачен в течение lifetime.
Canceled Отменён вручную оператором.
Подтверждение, пришедшее чуть позже дедлайна, не пропадает: если транзакция была видна в сети до истечения срока (Confirming), инвойс всё равно закроется в Success.

Допуски сумм

Сумма перевода сверяется с суммой инвойса. Значения по умолчанию (настраиваются на стороне Finem):

СитуацияПравило по умолчаниюРезультат
Недоплата «на комиссию» не больше 5 USDT и не больше 20% от суммы Success, зачисляется фактическая сумма
Переплата не больше 5 USDT Success, paidOver = true, зачисляется всё полученное
Недоплата сверх допуска получено ≥ 50% суммы WrongAmount, средства на ручном разборе
Прочее (слишком мало / слишком много) Инвойс остаётся активным, перевод уходит в очередь ручного разбора
Типичный случай недоплаты — биржа покупателя удержала комиссию вывода из суммы перевода. Учитывайте это в ценообразовании: допуск покрывает такие случаи автоматически.

Страница оплаты

paymentUrl ведёт на хостед-страницу Finem: сумма в USDT, QR-код (генерируется локально, адреса не передаются третьим сторонам), адрес кошелька с кнопкой копирования и таймер. Страница сама обновляет состояние: «платёж обнаружен, ждём подтверждения», «оплачено», «получена неполная сумма», «время истекло». Кнопки возврата берутся из urlSuccess / urlReturn.

Вебхуки: формат и доставка

При каждой смене статуса Finem отправляет POST с JSON на urlCallback инвойса (или callback-адрес мерчанта, если у инвойса свой не задан):

{
  "orderId": 42,
  "merchantOrderId": "shop-order-482",
  "status": "Success",
  "amountUsdt": 10.53,
  "receivedUsdt": 10.53,
  "paidOver": false,
  "currency": "RUB",
  "txHash": "9df31a..."
}

Правила доставки:

Вебхуки пока не подписываются. До появления подписи рекомендуем при получении вебхука сверять статус запросом GET /api/invoice/status и не доверять только телу уведомления.

Переотправка вебхука

POST/api/invoice/resend-webhook

Ставит в очередь вебхук с текущим статусом инвойса — например, если ваш обработчик был недоступен дольше окна ретраев. Авторизация — merchant + sign (см. выше).

{ "orderId": "shop-order-482" }   // ваш orderId из создания инвойса

Ответ 202 — поставлено в очередь; 400 — у инвойса нет callback-адреса; 404 — инвойс не найден.

Тестовый вебхук

POST/api/invoice/test-webhook

Для отладки обработчика: синхронно шлёт payload той же формы, что и боевой, с полем "test": true, и сразу возвращает результат. В очередь не пишется, ретраев нет. Авторизация — merchant + sign (см. выше).

// запрос
{ "url": "https://shop.example/finem/hook", "status": "WrongAmount" }
// url необязателен (возьмётся callback мерчанта), status по умолчанию Success

// ответ
{ "delivered": true, "httpStatus": 200, "url": "https://shop.example/finem/hook" }

Ошибки

КодТелоПричина
401jsonНеверная подпись sign или неизвестный merchant.
400{"error":"invalid"}Сумма ≤ 0 или пустой orderId.
400{"error":"bad_currency"}Валюта не поддерживается / нет курса.
409{"error":"no_available_wallets"} Нет свободного кошелька под эту сумму — повторите позже или измените сумму на несколько USDT.
404Инвойс не найден (статус/переотправка).

Валюты и сеть

Приём — только USDT TRC-20 (сеть TRON). Валюта инвойса: USDT либо фиат — RUB, KZT, UZS, TJS, KGS, VND, PHP, GEL, IDR, MDL, THB (список расширяется). Курс фиксируется на момент создания инвойса и возвращается в поле rate.

Finem · документация API v1 · вопросы — вашему менеджеру