ДОКУМЕНТАЦИЯ ДЛЯ РАЗРАБОТЧИКОВ

Платёжный API v2

Создайте платёж на своём сервере, отправьте покупателя на страницу оплаты и отметьте заказ оплаченным, когда Coino Live подтвердит платёж в сети.

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

1. Создайте API-ключ для своего шлюза в панели, в разделе «Разработчикам». 2. Создайте платёж на сумму заказа. 3. Перенаправьте покупателя на полученный checkout_url. 4. Когда придёт вебхук (или покупатель вернётся), снова прочитайте платёж и отправляйте заказ, когда статус станет "paid".

 curl https://coino.live/api/v2/payments \
  -H "Authorization: Bearer ck_live_..." \
  -H "Idempotency-Key: order-1001" \
  -H "Content-Type: application/json" \
  -d '{"amount": "25.00", "currency": "EUR", "order_id": "1001",
       "success_url": "https://shop.example/thanks",
       "notify_url": "https://shop.example/coino-webhook"}' 

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

Передавайте секретный ключ в заголовке Authorization каждого запроса. Ключ принадлежит одному шлюзу и видит только его платежи. Храните ключ на сервере: никогда не размещайте его в браузере, приложении или публичном репозитории. Если ключ утёк, отзовите его в панели и создайте новый.

Authorization: Bearer ck_live_...
Базовый URL: https://coino.live/api/v2

Все суммы — десятичные строки (не числа), всё время — ISO 8601 в UTC, каждый ответ — JSON с результатом в "data".

POST · /payments

Создать платёж

Цены могут быть в USD или в любой валюте из GET /currencies; другие валюты пересчитываются в USD по текущему курсу при создании платежа. Покупатель выбирает монету и сеть на странице оплаты.

ПолеОписание
amountОбязательно. Не более 2 знаков после запятой, например "25.00". Минимум 1 USD (или эквивалент).
currencyТрёхбуквенный код; если не указан — USD.
order_idНомер вашего заказа, до 128 символов. Виден вам, по нему можно искать через GET /payments.
descriptionПоказывается покупателю на странице оплаты, до 500 символов.
customer_emailНеобязательный email покупателя.
success_url, cancel_urlКуда страница оплаты возвращает покупателя. Возврат на success_url не доказывает оплату.
notify_urlАдрес вебхука для этого платежа (только https). Заменяет адрес вебхука из настроек шлюза.
metadataВаши собственные данные ключ/значение, до 20 ключей и 4 КБ. Возвращаются без изменений.
assetНеобязательный код монеты из GET /assets (например "usdt-tron"), чтобы пропустить выбор монеты.
expires_inСколько минут у покупателя на оплату, от 15 до 10080. По умолчанию 1440 (сутки).
Idempotency-Key

Отправляйте уникальный ключ для каждой попытки заказа (до 128 букв, цифр и символов -_:.). Повторный запрос с тем же ключом возвращает тот же платёж, а не создаёт второй, поэтому повтор после таймаута или двойного клика безопасен. Используйте новый ключ, если сумма изменилась или прошлый платёж истёк.

Ответ (201 при создании, 200 для повторного ключа) — объект платежа ниже.

Объект платежа

{
  "data": {
    "id": "01m62ewd502p9774d6trd7rhr7",
    "status": "paid",
    "amount": "22.32",
    "currency": "USD",
    "requested_amount": "20.00",
    "requested_currency": "EUR",
    "exchange_rate_usd": "1.115926958947",
    "received_usd": "22.32",
    "remaining_usd": "0.00",
    "order_id": "943",
    "description": "Order #943",
    "customer_email": "[email protected]",
    "metadata": {"cart": "abc"},
    "checkout_url": "https://coino.live/pay/01m62ewd502p9774d6trd7rhr7",
    "success_url": "https://shop.example/thanks",
    "cancel_url": "https://shop.example/cart",
    "asset": null,
    "quote": {
      "asset": "usdc-ethereum", "symbol": "USDC", "network": "Ethereum",
      "address": "0x8e2e…61bc", "amount": "22.330545",
      "network_fee": "0.000001", "rate_usd": "0.9995", "expires_at": "…"
    },
    "deposits": [{
      "asset": "usdc-ethereum", "symbol": "USDC", "network": "Ethereum",
      "tx_hash": "0xf13d…1439", "explorer_url": "https://etherscan.io/tx/0xf13d…1439",
      "amount": "22.330545", "network_fee": "0.000001",
      "platform_fee": "0.223305", "net": "22.107239",
      "usd_value": "22.32", "credited_at": "…"
    }],
    "expires_at": "…", "paid_at": "…", "created_at": "…"
  }
}

amount и currency — сколько покупатель платит в USD; requested_amount и requested_currency — что запросили вы. quote — монета, адрес и сумма, которые сейчас видит покупатель; deposits перечисляет все полученные транзакции с удержанной комиссией и суммой, зачисленной на ваш баланс (net).

СтатусЗначениеЧто делать
openОжидается оплата покупателем.Пока ничего.
confirmingТранзакция замечена и ждёт подтверждений сети.Покажите «платёж получен, подтверждается». Пока не отправляйте.
partially_paidПришло меньше суммы. Страница оплаты просит доплатить остаток (remaining_usd).Подождите: покупатель ещё может доплатить.
paidПолностью оплачен и подтверждён. Окончательно.Отметьте заказ оплаченным и отправьте.
expiredВремя вышло. Если received_usd больше нуля, эта часть на вашем балансе.Отмените заказ или урегулируйте оплаченную часть с покупателем.
cancelledОтменён вами до поступления оплаты. Окончательно.Ничего.

Платёж, очень близкий к сумме, считается оплаченным, чтобы округление кошельков не оставляло заказы открытыми.

GET · /payments/{id}

Чтение и отмена платежей

Читайте платёж заново всякий раз, когда нужно его текущее состояние: после вебхука, при возврате покупателя или из задачи по расписанию. Неизвестные ID и платежи других шлюзов отвечают 404.

GET · /payments?status=paid&order_id=1001&cursor=…

Список ваших платежей, сначала новые, по 50 на страницу. Оба фильтра необязательны. meta.next_cursor и meta.prev_cursor листают результаты.

POST · /payments/{id}/cancel

Отменяет открытый платёж, по которому ничего не поступило, например когда покупатель очистил корзину. Платежи с поступлением отменить нельзя (422).

Вебхуки

Coino Live отправляет POST на notify_url (или на адрес вебхука шлюза) при каждой смене статуса платежа. Вебхуки отправляются, только если у шлюза есть секрет подписи: создайте его в настройках шлюза.

 POST /coino-webhook
X-Coino-Event: payment.paid
X-Coino-Delivery: 01m62f23xhkz39ahqv4h64ttfk
X-Coino-Signature: t=1761696953,v1=5f2c…

{"id": "01m62f23xhkz39ahqv4h64ttfk", "event": "payment.paid",
 "created_at": "…", "data": { …the payment object… }} 
СобытиеКогда
payment.confirming, payment.partially_paid, payment.paid, payment.expired, payment.cancelledПлатёж перешёл в этот статус.
custody.deposit.detected, custody.deposit.creditedПоступление пользователя кастоди замечено, затем зачислено.
withdrawal.<status>Статус API-вывода изменился.

Проверяйте подпись: вычислите HMAC-SHA256 от "<t>.<raw body>" с вашим секретом подписи, сравните с v1 за постоянное время и отклоняйте метки времени старше пяти минут.

// PHP
$header = $_SERVER['HTTP_X_COINO_SIGNATURE'] ?? '';
$body = file_get_contents('php://input');
parse_str(str_replace(',', '&', $header), $sig);
$ok = isset($sig['t'], $sig['v1'])
    && abs(time() - (int) $sig['t']) <= 300
    && hash_equals(hash_hmac('sha256', $sig['t'] . '.' . $body, $secret), $sig['v1']);

// Node.js
const [t, v1] = header.split(',').map(p => p.split('=')[1]);
const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
const ok = Math.abs(Date.now() / 1000 - t) <= 300
  && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));

# Python
t, v1 = (p.split('=', 1)[1] for p in header.split(','))
expected = hmac.new(secret.encode(), f'{t}.{raw_body}'.encode(), 'sha256').hexdigest()
ok = abs(time.time() - int(t)) <= 300 and hmac.compare_digest(expected, v1)
Считайте вебхук сигналом

Прежде чем отметить заказ оплаченным, прочитайте платёж через GET /payments/{id} и проверьте статус, сумму и ваш order_id. Ответьте любым статусом 2xx в течение 10 секунд. Неудачные доставки повторяются через 1, 5, 30, 120, 360, 720 и 1440 минут; редиректы не выполняются. Одно событие может прийти несколько раз, поэтому обрабатывайте его идемпотентно.

Валюты, монеты и балансы

GET · /currencies

Валюты, в которых можно выставить платёж, с их стоимостью в USD: {"code": "EUR", "usd_per_unit": "1.09"}. Скрывайте криптооплату, если валюты вашего магазина нет в списке.

GET · /assets

Монеты, которыми покупатели могут платить сейчас: code (например "usdt-tron"), symbol, name, network, decimals и price_usd.

GET · /balances

Баланс вашего аккаунта по каждой монете за вычетом комиссий: asset, symbol, network, balance и usd_value (null, пока нет курса).

Кастоди-аккаунты

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

ЗапросОписание
POST /custody/usersСоздать пользователя (external_id обязателен; name, email, metadata необязательны). Тот же external_id возвращает существующего пользователя.
GET /custody/users?external_id=…Список пользователей, по 50 на страницу.
GET /custody/users/{id}Адреса (с монетами, которые принимает каждый) и балансы.
GET /custody/users/{id}/depositsЗачисленные поступления, сначала новые, с next_cursor.
POST /custody/users/{id}/transfersПереводит баланс пользователя в одном активе на ваш основной баланс (весь, если amount не указан). Необязательный reference позволяет безопасно повторить запрос.
Читать руководство по кастоди
POST · /withdrawals

Вывод средств

Выплата с вашего баланса на адрес: asset, amount и address обязательны; custody_user списывает средства с баланса кастодиального пользователя; reference (уникальный в пределах шлюза) позволяет безопасно повторить запрос. По умолчанию выключено: включите выводы через API в настройках шлюза, где также задаются дневной лимит в USD и IP-адреса серверов, которым разрешён вызов (оба эндпоинта отвечают только этим IP). Reference, повторно использованный для другого вывода, отклоняется с кодом 409. Крупные выводы могут ожидать проверки.

GET · /withdrawals/{id}

Статус: pending_review, approved, processing, broadcast, completed, rejected (см. error), cancelled или failed. tx_hash появляется после отправки.

Ошибки и лимиты

HTTPЗначение
401Ключ отсутствует, неверен или отозван, либо шлюз приостановлен.
404Не найдено (или принадлежит другому шлюзу).
422Запрос отклонён: "message" объясняет причину, "errors" называет поля.
429Слишком много запросов: 120 в минуту на ключ. Подождите и повторите.
5xxВременная проблема на нашей стороне. Повторите с тем же Idempotency-Key.
{"message": "The minimum payment is 1.00 USD."}

{"message": "amount must be a decimal string with at most 2 decimals, e.g. \"25.00\".",
 "errors": {"amount": ["amount must be a decimal string with at most 2 decimals, e.g. \"25.00\"."]}}

Библиотеки для разработчиков

Официальные библиотеки для этого API, без зависимостей. Они проверяют подписи вебхуков, выдают понятную ошибку при каждом отказе и повторяют запрос после сетевой ошибки, только когда повтор безопасен.

ЯзыкВерсияТребования
PHP1.0.0PHP 8.1+ with cURLСкачать
Node.js1.0.0Node.js 18+, TypeScript types includedСкачать
Python1.0.0Python 3.8+Скачать
// PHP
$coino = new \CoinoLive\Client('ck_live_...');
$payment = $coino->payments->create(['amount' => '25.00', 'currency' => 'EUR', 'order_id' => '1001']);

// Node.js
const coino = new CoinoLive('ck_live_...');
const payment = await coino.payments.create({ amount: '25.00', currency: 'EUR', order_id: '1001' });

# Python
coino = coinolive.Client("ck_live_...")
payment = coino.payments.create(amount="25.00", currency="EUR", order_id="1001") 

В каждой загрузке есть README со всеми вызовами, обработкой вебхуков и классами ошибок.

Интеграции с платформами

Готовые плагины на основе этого API. Установите плагин, вставьте API-ключ и включите его: заказы обновляются автоматически, а каждый плагин показывает ваш баланс и платежи в своей админке.

ПлатформаВерсияТребования
WooCommerce1.1.0WordPress 6.2+, WooCommerce 7.6+, PHP 7.4+Скачать
WHMCS1.0.0WHMCS 8.0+, PHP 7.4+Скачать
OpenCart 41.0.0OpenCart 4.0.2+, PHP 8.0+Скачать
Shopware 61.0.0Shopware 6.6.5+ or 6.7, PHP 8.2+Скачать
PrestaShop1.0.0PrestaShop 8.0+ or 9, PHP 7.2+Скачать
Easy Digital Downloads1.0.0Easy Digital Downloads 3, WordPress 6.7+, PHP 8.0+Скачать
GiveWP1.0.0GiveWP 3+, WordPress 6.6+, PHP 7.4+Скачать

Другие платформы: используйте API напрямую, как описано выше.