Документация / Интеграция

Счета

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

Создание

POST/v1/invoices

Заголовки: Authorization (CP-HMAC), Idempotency-Key, Content-Type: application/json.

тело запроса
{
  "order_id": "ORDER-1001",
  "price_amount": "49.99",
  "price_currency": "USD",
  "allowed_assets": ["USDT-TRON", "USDC-BASE", "BTC"],
  "return_url": "https://shop.example/orders/ORDER-1001",
  "expires_in_seconds": 1800,
  "metadata": { "user_id": "42", "plan": "pro" }
}
ПолеОбязательноПравила
order_idда1–128 символов, уникален у мерчанта (повтор — 409 duplicate_order)
price_amountдаДесятичная строка > 0, до 18 знаков после точки
price_currencyдаUSD, EUR, USDT или USDC
allowed_assetsнетДо 30 id активов (GET /v1/assets). Пусто — все доступные. Счёт получит пересечение с доступными; пустое — 422 invalid_allowed_assets
return_urlнетhttps://… — кнопка «Вернуться в магазин»
expires_in_secondsнет300–86 400, по умолчанию 1800 (30 минут)
metadataнетДо 20 ключей [A-Za-z0-9_.-]{1,64}, значения до 500 символов; возвращаются в счёте

Ответ 201:

JSON
{
  "id": "inv_x7k2…",
  "order_id": "ORDER-1001",
  "status": "created",
  "price_amount": "49.99",
  "price_currency": "USD",
  "allowed_assets": ["USDT-TRON", "BTC"],
  "checkout_url": "https://pay.coinetic.money/pay/inv_x7k2…#t=…",
  "return_url": "https://shop.example/orders/ORDER-1001",
  "expires_at": "2026-10-12T15:30:00Z",
  "created_at": "2026-10-12T15:00:00Z",
  "quote": null,
  "paid_amount": "0", "outstanding_amount": "0", "overpaid_amount": "0",
  "refunded_amount": "0", "refundable_amount": "0",
  "payments": [],
  "metadata": { "user_id": "42", "plan": "pro" },
  "livemode": true
}
  • price_amount возвращается в канонической форме без хвостовых нулей: на "3.00" придёт "3". Сравнивайте суммы как десятичные, не как float и не побайтно.
  • checkout_url содержит токен страницы оплаты после #. Не логируйте и не публикуйте его.
  • livemode: false — счёт песочницы. Продакшен-магазин должен такие отвергать.

Какие активы попадут в счёт

Актив доступен, если он включён в Coinetic, у вас есть действующий кошелёк приёма этой сети и вы не исключили его в кабинете («Настройки» → «Активы для оплаты»). У каждого актива есть минимум (min_amount в GET /v1/assets): если сумма счёта в этом активе меньше, актив в счёт не попадёт. Пример: счёт на 3 USD при BTC = 60 000 USD — это 5 000 сат при минимуме 10 000, такой счёт получит только стейблкоины.

Поле selectable_assets — те из allowed_assets, которые можно выбрать прямо сейчас; страница оплаты предлагает только их.

Идемпотентность

  • Idempotency-Key: 8–128 печатных ASCII-символов без пробелов, не начинается с d:. Удобно — от номера заказа: order-ORDER-1001.
  • Тот же ключ и то же тело — тот же ответ (тот же счёт).
  • Тот же ключ с другим телом — 409 idempotency_conflict.
  • Первый запрос ещё выполняется — 409 idempotency_in_progress, повторите через секунду.
  • Отказ по бизнес-правилу (например, 422) тоже запоминается.

Получение

GET/v1/invoices/{id}

Когда покупатель выбрал валюту, в счёте появляется quote:

quote
{
  "asset_id": "USDT-TRON", "network": "tron", "token_contract": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
  "address": "TX…", "amount_due": "49990000", "decimals": 6, "display_amount": "49.99",
  "payment_uri": "tron:…", "rate": "1", "rate_valid_until": null,
  "network_warning": "Отправляйте только USDT в сети TRON (TRC-20)…"
}

payments — платежи: tx_hash, amount (в минимальных единицах), confirmations, required_confirmations, state (mempool, included, confirmed, reorged, replaced, failed, dropped).

unmatched_payments — переводы на адрес счёта, которые не засчитаны: в другой EVM-сети (wrong_network) или токеном не из белого списка (token_not_whitelisted). Статус и paid_amount они не меняют.

Список

GET/v1/invoices?status=paid&from=…&to=…&limit=50&cursor=…

Ответ: { "items": [...], "next_cursor": "…" | null }, от новых к старым, limit 1–200.

Статусы

СтатусЗначениеЧто делать магазину
createdСчёт создан, валюта не выбранаждать
awaiting_paymentВалюта выбрана, адрес выданждать
detectedПлатёж виден в сети (мемпул)показать «платёж найден», не выдавать
confirmingВ блоке, подтверждений меньше нужногопоказать прогресс, не выдавать
paidОплачено полностью и подтвержденовыдать заказ
overpaidОплачено больше нужноговыдать заказ; излишек — возврат по запросу
underpaidПодтверждено меньше нужного (за вычетом допуска)попросить доплатить на тот же адрес
expiredСрок вышел, оплаты не былопредложить новый счёт (см. ниже)
late_paymentОплата пришла после срокарешение за вами: выдать или вернуть
manual_reviewПлатёж на проверке AMLждать решения; не выдавать
refunded, cancelledЗакрытне выдавать
Главное правилоВыдавайте заказ только при paid или overpaid, полученных из GET /v1/invoices/{id}.

Оплата стейблкоином после срока

USDT или USDC для счёта в USD курсом не рискуют, поэтому оплата после срока (до 30 дней) засчитывается автоматически: счёт, уже получивший invoice.expired, становится paid, приходит invoice.paid с data.late: true. Поэтому не закрывайте заказ по invoice.expired безвозвратно. Для волатильных активов такая оплата даёт late_payment.

Суммы и курс

  • Цена задаётся в валюте счёта. Сумму в криптовалюте Coinetic фиксирует в момент выбора валюты покупателем.
  • Стейблкоин в своей валюте (USDT для счёта в USD): 1:1, сумма зафиксирована до конца счёта.
  • Волатильный актив (BTC, ETH и др.): медиана курсов Kraken, Coinbase и Bitstamp, фиксируется на 20 минут.
  • amount_due — в минимальных единицах актива (USDT в TRON — 6 знаков: "49990000" = 49.99). display_amount — то же в обычной записи.
  • Допуск недоплаты (по умолчанию 0,5%) покрывает округления кошельков.

Справочный курс — GET /v1/rates?base=BTC&quote=USD. Не показывайте по нему покупателю «точную» сумму в криптовалюте: обязывающую сумму даёт только счёт.