Один API, единый хостинг-процесс
CryptoPayIn рассчитывает стоимость заказа в выбранной вами валюте отображения, фиксирует проверенные снапшоты курсов фиат/USD и крипто/USD, выделяет отдельный адрес для депозита и отслеживает поступление платежа через собственные блокчейн-ноды. Внутренний учёт, комиссии и балансы всегда ведутся в USD. Ваш бэкенд сразу получает URL чекаута, а затем — подписанные события жизненного цикла.
Это боевой API. Здесь нет тестового (sandbox) префикса. Каждое успешное создание выделяет реальный адрес в блокчейне. Для сквозных тестов используйте небольшую сумму в поддерживаемой валюте и храните секретные ключи только на своём сервере.
Как устроена интеграция
Сгенерируйте секрет один раз в Кабинет -> Разработчики.
Отправьте POST-запрос с валютой заказа, суммой и выбранным активом.
Перенаправьте клиента на полученный хостинг-URL.
Проверьте HMAC и обновите заказ идемпотентно.
Создайте первый платёж
Сгенерируйте ключ API в кабинете мерчанта, сохраните секрет в переменной окружения, а затем создайте платёж со своего бэкенда. В примере используется ETH — его можно протестировать без выбора сети токена.
curl --request POST https://cryptopayin.com/v1/payments \
--header "Authorization: Bearer $CPI_SECRET_KEY" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: order_1042" \
--data '{
"amount": 49.99,
"currency": "USD",
"asset": "ETH",
"order_ref": "order_1042",
"redirect_url": "https://shop.example/orders/1042/paid"
}'
const response = await fetch("https://cryptopayin.com/v1/payments", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.CPI_SECRET_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": "order_1042"
},
body: JSON.stringify({
amount: 49.99, currency: "USD", asset: "ETH",
order_ref: "order_1042",
redirect_url: "https://shop.example/orders/1042/paid"
})
});
if (!response.ok) throw new Error(await response.text());
const payment = await response.json();
$payload = json_encode([
'amount' => 49.99, 'currency' => 'USD', 'asset' => 'ETH',
'order_ref' => 'order_1042',
'redirect_url' => 'https://shop.example/orders/1042/paid',
]);
$ch = curl_init('https://cryptopayin.com/v1/payments');
curl_setopt_array($ch, [
CURLOPT_POST => true, CURLOPT_POSTFIELDS => $payload,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CPI_SECRET_KEY'),
'Content-Type: application/json',
'Idempotency-Key: order_1042',
],
]);
$payment = json_decode(curl_exec($ch), true, flags: JSON_THROW_ON_ERROR);
import os, requests
response = requests.post(
"https://cryptopayin.com/v1/payments",
headers={
"Authorization": f"Bearer {os.environ['CPI_SECRET_KEY']}",
"Idempotency-Key": "order_1042",
},
json={
"amount": 49.99, "currency": "USD", "asset": "ETH",
"order_ref": "order_1042",
"redirect_url": "https://shop.example/orders/1042/paid",
}, timeout=15,
)
response.raise_for_status()
payment = response.json()Используйте ответ
Сохраните id платежа рядом с вашим заказом, а затем перенаправьте клиента на checkout_url. Не вычисляйте сумму в криптовалюте или адрес депозита самостоятельно.
{
"id": "P-9F27C1E4KD",
"object": "payment",
"status": "created",
"amount": 49.99,
"amount_decimal": "49.99",
"amount_minor": 4999,
"currency": "USD",
"currency_minor_units": 2,
"amount_usd": 49.99,
"amount_usd_cents": 4999,
"fx_rate_usd": "1.000000000000",
"fx_source": "fixed:USD",
"fx_observed_at": "2026-07-17T13:00:00+00:00",
"fx_discrepancy_bps": 0,
"asset": "ETH",
"network": "mainnet",
"crypto_amount": "0.01388612",
"crypto_received": "0",
"deposit_address": "0x71b8c3d4700000000000000000000000000084e2",
"exchange_rate": "3600.00000000",
"exchange_rate_currency": "USD",
"exchange_rate_source": "median:cb,cg,cl",
"exchange_rate_source_count": 3,
"exchange_rate_observed_at": "2026-07-17T13:00:00+00:00",
"exchange_rate_discrepancy_bps": 12,
"confirmations": 0,
"confirmations_required": 12,
"order_ref": "order_1042",
"checkout_url": "https://cryptopayin.com/i/P-9F27C1E4KD",
"expires_at": "2026-07-17T13:30:00+00:00",
"created_at": "2026-07-17T13:00:00+00:00",
"completed_at": null
}Аутентификация
Каждый запрос к API использует секретный ключ в HTTP-заголовке Bearer. Секретные ключи начинаются с csk_live_. Сопутствующее значение cpk_live_ — это публичный идентификатор для вашего кабинета, его нельзя использовать как учётные данные Bearer.
Authorization: Bearer csk_live_...Каждая точка входаИсходный секрет возвращается только при создании ключа. CryptoPayIn хранит хеш пароля и индексированный SHA-256-отпечаток для поиска, но никогда — секрет в открытом виде.
Создавайте отдельные ключи для каждого приложения или окружения и отзывайте их независимо друг от друга. На аккаунт допускается до 50 активных ключей.
Никогда не помещайте значение csk_live_ в клиентский JavaScript, в мобильное приложение, в публичный репозиторий или на страницу чекаута.
Точка входа webhook может охватывать весь аккаунт или быть привязана к одному ключу API — это изолирует интеграции друг от друга.
Отсутствующий, некорректный, отозванный или неизвестный секрет возвращает 401 unauthorized. Приостановленный или закрытый аккаунт мерчанта отклоняется так же. Действительный ключ, использованный за пределами предоставленных прав доступа, возвращает 403 insufficient_scope.
Идемпотентность
При каждом создании платежа отправляйте уникальный Idempotency-Key. Если соединение обрывается после отправки, повторите запрос с идентичным JSON и тем же ключом: CryptoPayIn вернёт исходный платёж вместо выделения нового адреса.
| Случай | Результат | HTTP |
|---|---|---|
| Первое использование | Создаёт и возвращает новый платёж. | 201 |
| Тот же ключ + тот же JSON | Возвращает существующий платёж с Idempotent-Replayed: true. | 200 |
| Тот же ключ + другой JSON | Отклоняет запрос как idempotency_conflict. | 409 |
Ключи идемпотентности привязаны к учётным данным API и могут содержать от 1 до 128 букв, цифр, точек, подчёркиваний, двоеточий или дефисов. Хороший выбор — постоянный UUID заказа. Тот же механизм защищает и вывод средств, поэтому повторная попытка вывода никогда не переместит средства дважды.
Справочник API
API охватывает платежи, платёжные ссылки, магазины, товары, балансы и вывод средств. Ответы возвращаются в формате UTF-8 JSON поверх HTTPS; любое создание или обновление требует Content-Type: application/json. Операции изменения данных контролируются правами доступа вызывающего ключа. CORS для браузера намеренно не поддерживается: вызовы должны выполняться с вашего бэкенда.
/v1/assetsСписок доступных активов/v1/currenciesСписок фиатных валют отображения/v1/paymentsСоздание платежа/v1/paymentsСписок и фильтрация платежей/v1/payments/{id}Получение платежаВерсия 1 может получать обратно совместимые поля и точки входа. Любое несовместимое изменение контракта будет оформлено через новый базовый путь, а не через незаметное изменение /v1.
Список активов
/v1/assetsТребуется Bearer-аутентификацияИспользуйте эту точку входа как источник достоверных данных для выбора при чекауте. Она возвращает включённые позиции каталога, актуальные независимо проверенные курсы, минимальные суммы в эквиваленте USD и статус готовности ноды и ленты котировок. Позиция может оставаться в списке с available: false, пока нода синхронизируется или её курс не удаётся подтвердить.
curl https://cryptopayin.com/v1/assets \
--header "Authorization: Bearer $CPI_SECRET_KEY"{
"object": "list",
"data": [{
"asset": "USDT",
"network": "TRC20",
"type": "token",
"decimals": 6,
"minimum_amount": 1,
"currency": "USD",
"base_confirmations": 19,
"available": true,
"rate_usd": "1.00000000",
"rate_source": "median:cb,cg,cl",
"rate_source_count": 3,
"rate_discrepancy_bps": 4,
"rate_status": "healthy",
"rate_updated_at": "2026-07-17T13:00:00+00:00"
}]
}Идентификаторы каталога и сети
| Актив | Значение сети | Сокращение | Базовые подтверждения |
|---|---|---|---|
| BTC | mainnet | BTC | 2 |
| ETH | mainnet | ETH | 6 |
| USDT | TRC20 / ERC20 | USDT.TRC20 | 19 / 6 |
| USDC | ERC20 | USDC.ERC20 | 6 |
| DAI | ERC20 | DAI | 6 |
| SHIB | ERC20 | SHIB | 6 |
| PEPE | ERC20 | PEPE | 6 |
| LTC | mainnet | LTC | 6 |
| TRX | mainnet | TRX | 19 |
| DOGE | mainnet | DOGE | 20 |
| XMR | mainnet | XMR | 10 |
| SOL | mainnet | SOL | 32 |
Доступность активов может меняться. Не жёстко прописывайте таблицу выше как актуальный список разрешённых активов. Для символов с несколькими сетями, таких как USDT, явно указывайте network или используйте сокращение ASSET.NETWORK.
Список фиатных валют
/v1/currenciesТребуется Bearer-аутентификацияВозвращает включённые валюты отображения, их точность по ISO и текущее состояние конвертации в USD. Предлагайте клиенту только строки с available: true. USD является базовой валютой; для всех остальных валют требуется актуальная живая котировка и независимая сверочная проверка. minimum_amount переводит минимальный настроенный порог для включённых активов в эту валюту; выбранный актив может требовать более высокую сумму, поэтому всегда проверяйте и GET /v1/assets.
curl https://cryptopayin.com/v1/currencies \
--header "Authorization: Bearer $CPI_SECRET_KEY"{
"object": "list",
"accounting_currency": "USD",
"data": [{
"currency": "EUR",
"name": "Euro",
"symbol": "€",
"minor_units": 2,
"available": true,
"minimum_amount": "0.86",
"rate_usd": "1.160000000000",
"rate_source": "coinbase+ecb",
"rate_source_count": 2,
"rate_discrepancy_bps": 18,
"rate_updated_at": "2026-07-17T13:00:00+00:00",
"rate_reference_at": "2026-07-16T00:00:00+00:00"
}]
}Если валюта не указана в POST /v1/payments, по-прежнему подразумевается USD — для обратной совместимости. Валюты без дробной части, например JPY, не принимают дробные суммы. Относитесь к минимумам и курсам каталога как к живым данным, а не как к жёстко заданным константам.
Создание платежа
/v1/payments120 запросов в минуту на ключСоздаёт счёт в запрошенной валюте отображения, фиксирует свежие проверенные снапшоты курсов фиат/USD и крипто/USD, вычисляет точную сумму в криптовалюте и привязывает выделенный адрес депозита в блокчейне.
Тело запроса
| Поле | Тип | Обязательность | Описание |
|---|---|---|---|
| amount | число или десятичная строка | обязательно | Значение в currency с точностью по ISO для этой валюты. Зафиксированный эквивалент в USD не должен превышать $1,000,000.00; также действуют минимумы по активу. |
| currency | string | необязательно | Включённая трёхбуквенная валюта из GET /v1/currencies. По умолчанию — USD. |
| asset | string | обязательно | Символ, например ETH, либо сокращение, например USDT.TRC20. |
| network | string | условно | Обязательно, если символ существует в нескольких сетях. Пример: ERC20. |
| order_ref | string | необязательно | Идентификатор вашего заказа, максимум 128 символов. Возвращается в ответах API и событиях. |
| customer_email | string | необязательно | Действительный адрес электронной почты, максимум 190 символов. Сохраняется вместе с записью платежа мерчанта. |
| redirect_url | string | необязательно | HTTPS-URL, максимум 255 символов, предлагается после успешного прохождения чекаута. |
Поля ответа
| Поле | Тип | Описание |
|---|---|---|
| id | string | Стабильный идентификатор платежа, начинающийся с P-. |
| status | string | Текущее состояние жизненного цикла. |
| amount / amount_decimal / amount_minor | number / string / integer | Запрошенное значение отображения в удобной, точной десятичной форме и в минимальных единицах ISO. |
| currency / currency_minor_units | string / integer | Зафиксированная валюта отображения и её точность. |
| amount_usd / amount_usd_cents | number / integer | Неизменяемое значение внутреннего учёта в USD. |
| fx_rate_usd / fx_source / fx_observed_at | decimal string / string / ISO 8601 | Зафиксированный снапшот курса USD за единицу валюты отображения и метаданные для аудита. |
| asset / network | string | Определённый актив в блокчейне. |
| crypto_amount | decimal string | Точная сумма, которую должен отправить клиент. Никогда не разбирайте десятичные значения криптовалют как двоичные числа с плавающей точкой. |
| crypto_received | decimal string | Текущая наблюдаемая сумма на адресе депозита. |
| deposit_address | string | Выделенный адрес, привязанный к этому платежу. |
| exchange_rate | decimal string | Зафиксированный курс крипто/USD, использованный для вычисления crypto_amount; это поле сохраняет своё изначальное значение из v1. |
| exchange_rate_source / exchange_rate_observed_at | string / ISO 8601 | Неизменяемый снапшот курса криптовалюты для аудита. |
| confirmations | integer | Текущее число подтверждений сети. |
| confirmations_required | integer | Порог для этого платежа. Более высокие суммы в USD могут требовать дополнительных подтверждений. |
| checkout_url | URL | Хостинг-счёт для показа клиенту. |
| expires_at | ISO 8601 | Крайний срок для неоплаченного счёта. |
| completed_at | ISO 8601 / null | Время финального расчёта после завершения. |
Перед созданием обе живые конвертации проверяются на актуальность, количество источников и расхождение курсов. Если проверка не проходит, создание завершается ошибкой вместо использования устаревшего курса. Сумма в криптовалюте округляется вверх с полезной для актива точностью, поэтому округление никогда не оставляет мерчанта в минусе.
Список платежей
/v1/payments240 запросов в минуту на ключВозвращает платежи аутентифицированного аккаунта мерчанта, начиная с самых новых. Используйте курсорную пагинацию для сверки и точные фильтры, чтобы найти заказ, не просматривая всю историю.
Параметры запроса
| Параметр | По умолчанию | Описание |
|---|---|---|
| limit | 20 | Размер страницы от 1 до 100. |
| starting_after | — | ID платежа, возвращённый как next_cursor предыдущей страницы. |
| status | — | Точный статус жизненного цикла, например pending, completed или expired. |
| order_ref | — | Точный номер заказа мерчанта, максимум 128 символов. |
curl "https://cryptopayin.com/v1/payments?status=completed&limit=20" \
--header "Authorization: Bearer $CPI_SECRET_KEY"{
"object": "list",
"data": [{
"id": "P-9F27C1E4KD",
"object": "payment",
"status": "completed",
"amount": 49.99,
"currency": "USD",
"asset": "ETH",
"network": "mainnet",
"crypto_amount": "0.01388612",
"crypto_received": "0.01388612",
"order_ref": "order_1042",
"confirmations": 12,
"confirmations_required": 12,
"completed_at": "2026-07-17T13:12:42+00:00"
}],
"has_more": true,
"next_cursor": "P-9F27C1E4KD"
}Если has_more равно true, передавайте next_cursor без изменений как starting_after. Неизвестные или повторяющиеся параметры запроса в виде массива отклоняются, а не игнорируются.
Получение платежа
/v1/payments/{id}240 запросов в минуту на ключВозвращает тот же объект платежа, что и при создании, но с актуальным статусом, полученной суммой, хешем транзакции и числом подтверждений. Ключ может получать только платежи, принадлежащие его аккаунту мерчанта.
curl https://cryptopayin.com/v1/payments/P-9F27C1E4KD \
--header "Authorization: Bearer $CPI_SECRET_KEY"Обычные обновления заказа должны управляться webhooks. Используйте получение платежа для сверки после тайм-аута, проверки события, отображения страницы статуса на бэкенде или восстановления пропущенных доставок.
Жизненный цикл платежа
Всегда считайте статус API источником истины. Не делайте вывод о завершении платежа по редиректу браузера или по словам клиента о том, что он заплатил.
| Статус | Значение | Действие мерчанта |
|---|---|---|
| created | Счёт и адрес выделены; поступление средств пока не обнаружено. | Покажите хостинг-чекаут. |
| pending | Ожидание пригодного платежа в блокчейне. | Держите заказ открытым. |
| underpaid | Поступившая сумма ниже допустимого мерчантом порога. | Попросите плательщика отправить показанный остаток. |
| confirming | Обнаружена достаточная сумма; ожидание подтверждений. | Пока не выполняйте заказ. |
| completed | Достигнуты требуемая сумма и число подтверждений. | Выполните заказ ровно один раз. |
| overpaid | Подтверждено больше ожидаемого. | Выполните заказ и проверьте излишек. |
| expired | До истечения срока не обнаружено подходящего платежа. | Создайте новый платёж. |
| failed | Сбой при выделении адреса или обработке. | Зафиксируйте ошибку и создайте новый платёж. |
Переводы в блокчейне необратимы, а у CryptoPayIn нет механизма возврата средств — подтверждённый платёж окончателен. Любой добровольный возврат средств клиенту происходит напрямую между вами и клиентом, вне платформы.
Хостинг-чекаут
Каждый платёж, созданный через API, включает адаптивный checkout_url. На нём показаны мерчант, запрошенная сумма отображения, зафиксированный эквивалент в USD (если применимо), точная сумма в криптовалюте, адрес депозита, QR-код, предупреждение о сети, обратный отсчёт и прогресс подтверждений в реальном времени.
Клиент видит тот же crypto_amount, что возвращён API, на протяжении всего окна действия счёта.
Плательщику не нужно создавать аккаунт CryptoPayIn или передавать учётные данные.
Страница безопасно опрашивает статус платежа и последовательно проходит стадии от ожидания к подтверждению и оплате.
После успешной оплаты предлагается HTTPS-redirect_url; это не является доказательством платежа.
Выполнение заказа должно оставаться на вашем бэкенде. Переход в браузере можно прервать, повторить или подделать; только проверенный webhook или аутентифицированный GET-запрос подтверждают статус платежа.
Права доступа и области действия
Каждый ключ API имеет фиксированный набор прав доступа, который выбирается при его создании в Кабинет → Разработчики. Каждая точка входа проверяет области действия ключа перед выполнением любой операции; вызов за пределами предоставленных прав возвращает 403 insufficient_scope с заголовком X-Required-Scope, указывающим отсутствующее право. Области действия задаются один раз при создании и не могут быть расширены позже — вместо этого выпустите новый ключ. Ключи, созданные до появления областей действия, сохраняют ровно свои изначальные возможности: payments:read и payments:write.
| Область действия | Предоставляет | Точки входа |
|---|---|---|
payments:read | Просмотр списка и получение платежей | GET /v1/payments, GET /v1/payments/{id} |
payments:write | Создание хостинг-платежей | POST /v1/payments |
links:read | Просмотр списка и получение платёжных ссылок | GET /v1/links, GET /v1/links/{id} |
links:write | Создание, редактирование, приостановка и удаление платёжных ссылок | POST/PATCH/DELETE /v1/links |
shops:read | Просмотр списка и получение магазинов и их товаров | GET /v1/shops, GET .../products |
shops:write | Создание и редактирование магазинов, товаров и вариантов | POST/PATCH/DELETE /v1/shops и товаров |
balance:read | Чтение криптобалансов и оценок в USD | GET /v1/balance |
payouts:read | Просмотр списка и получение выводов средств | GET /v1/payouts, GET /v1/payouts/{id} |
payouts:write | Запрос вывода средств в блокчейн | POST /v1/payouts |
payouts:write перемещает средства в блокчейне, и это необратимо. Предоставляйте это право только полностью доверенным ключам, храните такие ключи на сервере и по возможности используйте отдельный ключ для каждого автоматизированного процесса. GET /v1/account показывает области действия вызывающего ключа и лимиты вашего аккаунта.
Платёжные ссылки
Многоразовые хостинг-ссылки, по которым клиент может платить сколько угодно раз. Ссылка использует ту же логику цен, активов, доставки и вопросов при чекауте, что и конструктор ссылок в кабинете — API просто управляет ею. На аккаунт допускается до 50 платёжных ссылок.
/v1/linkslinks:read/v1/linkslinks:write/v1/links/{id}links:read/v1/links/{id}links:write/v1/links/{id}links:writeТело запроса
| Поле | Тип | Обязательность | Описание |
|---|---|---|---|
| title | string | обязательно | 3–120 символов. |
| description | string | необязательно | До 2,000 символов, отображается при чекауте. |
| template | string | необязательно | Тема чекаута: signature (по умолчанию), midnight, atelier, horizon, compact или ledger. |
| public_label | string | необязательно | Публичное имя продавца, видимое покупателям (2–80 символов). Никогда не идентификатор аккаунта. |
| amount_type | string | необязательно | fixed (по умолчанию) или open (клиент выбирает сумму в пределах min/max). |
| currency | string | необязательно | Валюта отображения из GET /v1/currencies. По умолчанию — валюта вашего аккаунта. |
| amount | number or string | условно | Обязательно для fixed. В currency с точностью по ISO. |
| min / max | number or string | условно | Границы для ссылок open. max может быть 0 или отсутствовать — тогда верхнего предела нет. |
| accepted_assets | array of strings | необязательно | Коды активов, например ["BTC","USDT.TRC20"]. Опустите, чтобы разрешить все доступные активы. |
| max_uses | integer | необязательно | Лимит завершённых платежей. 0 означает без ограничений. |
| expires_at | ISO 8601 | необязательно | Не менее чем через 5 минут, не более чем через 12 месяцев. UTC. |
| delivery_type | string | необязательно | none, text, url или keys — цифровой товар, доставляемый после оплаты. |
| delivery_text / delivery_url | string | условно | Содержимое (≤50,000 символов) или https-URL для соответствующего типа доставки. |
| delivery_keys | array of strings | условно | По одному ключу на элемент для доставки типа keys. До 10,000 штук, каждый ≤500 символов. |
| checkout_fields | array | необязательно | До 5 объектов {label, type, required}; тип — text, email, textarea или number. |
| success_message / redirect_url | string | необязательно | Сообщение после оплаты (≤500 символов) и https-редирект. |
| status | string | необязательно | Только PATCH: active или paused. |
curl -X POST https://cryptopayin.com/v1/links \
-H "Authorization: Bearer $CPI_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Pro license",
"amount": 49.99,
"currency": "EUR",
"accepted_assets": ["BTC", "ETH", "USDT.TRC20"],
"delivery_type": "keys",
"delivery_keys": ["ABC-1", "ABC-2", "ABC-3"]
}'{
"id": "PL-N5PKTYB7",
"object": "payment_link",
"url": "https://cryptopaylink.co/pay/PL-N5PKTYB7",
"status": "active",
"title": "Pro license",
"amount_type": "fixed",
"currency": "EUR",
"amount": 49.99,
"amount_decimal": "49.99",
"accepted_assets": [{"asset":"BTC","network":"mainnet"},{"asset":"ETH","network":"mainnet"},{"asset":"USDT","network":"TRC20"}],
"uses": {"started": 0, "completed": 0, "in_flight": 0},
"delivery": {"type": "keys", "keys_available": 3, "keys_total": 3},
"expires_at": null,
"created_at": "2026-07-19T19:00:00+00:00"
}PATCH — это частичное обновление: отправляйте только изменяемые поля, остальные сохраняются, включая непроданные лицензионные ключи. Для ссылок keys отправка delivery_keys заменяет пул непроданных ключей; уже доставленные ключи никогда не затрагиваются. Удаление ссылки, у которой есть платежи, фактически отклоняется — её история остаётся нетронутой.
Чекаут агентов
Каждая активная платёжная ссылка — это ещё и машиночитаемый чекаут: ИИ-агент или любой скрипт может обнаружить её, создать счёт и получить доставку без браузера — и без какого-либо ключа API, потому что это публичные точки входа для покупателя на домене ссылки, а не точки входа мерчанта. Полное описание контракта и рабочий пример: cryptopayin.com/agents.
https://cryptopaylink.co/pay/{link}.jsonпублично · обнаружениеВозвращает состояние, цену, принимаемые активы и точный контракт входных данных для вызова создания счёта (обязательные поля, схему доставки, варианты).
https://cryptopaylink.co/pay/{link}/invoiceпублично · поддерживает Idempotency-KeyСоздаёт счёт через то же ядро, снапшот цены и лимиты защиты от злоупотреблений, что и хостинг-страница, и возвращает адрес депозита, точную сумму в криптовалюте, URI кошелька и URL квитанции. После этого агент оплачивает в блокчейне с любого контролируемого им кошелька.
https://cryptopaylink.co/pay/{link}/receipt?p={payment}публично · опрашивайте раз в 5–10 сСтатус и подтверждения в реальном времени; после завершения платежа ответ содержит доставку — ваш текстовый контент, приватный URL или лицензионный ключ, зарезервированный для этого платежа, — а также ваше сообщение об успехе и URL редиректа.
Магазины используют тот же протокол
Витрины реализуют тот же процесс на собственном домене: каталог с актуальными остатками, а затем один вызов, который проверяет корзину, резервирует товар и возвращает счёт.
https://shopycrypto.com/s/{shop}.jsonпублично · каталогhttps://shopycrypto.com/s/{shop}/orderпублично · корзина → счёт, поддерживает Idempotency-Keyhttps://shopycrypto.com/s/{shop}/o/{order}/receipt?p={payment}публично · опрашивайте раз в 5–10 сНастройки продавца
Чекаут агентов включён по умолчанию и стоит ту же фиксированную комиссию 1%. Отключить его для всего аккаунта можно в Кабинет → Настройки → Общее → ИИ и чекаут агентов: после этого машинные точки входа для ссылок и магазинов будут отвечать 403 agents_disabled, а обычные страницы чекаута для людей продолжат работать. Платежи, созданные агентами, не помечаются никак особо — это обычные платежи в вашем кабинете, webhooks и экспортах.
Магазины
Хостинг-витрина, объединяющая товары на одной брендированной странице. На аккаунт допускается до 10 магазинов. Товары управляются через вложенные точки входа для товаров, описанные ниже.
/v1/shopsshops:read/v1/shopsshops:write/v1/shops/{id}shops:read/v1/shops/{id}shops:write/v1/shops/{id}shops:writeТело запроса
| Поле | Тип | Обязательность | Описание |
|---|---|---|---|
| name | string | обязательно | 2–80 символов. |
| tagline | string | необязательно | До 160 символов. |
| theme | string | необязательно | light (по умолчанию) или dark. |
| accent | string | необязательно | Hex-акцент из палитры магазина, возвращаемой как accent_palette в GET /v1/shops. |
| accepted_assets | array of strings | необязательно | Активы по умолчанию для товаров магазина, например ["BTC","LTC","XMR"]. При изменении применяются ко всем товарам. |
| status | string | необязательно | Только PATCH: active или paused. |
Магазин, отключённый CryptoPayIn по причинам, связанным с политикой платформы, нельзя ни повторно активировать, ни удалить через API — API вернёт admin_disabled (403). Удаление магазина удаляет его товары; прошлые платежи остаются нетронутыми.
Товары & варианты
Товары находятся внутри магазина. Каждый магазин допускает до 50 товаров. Товар может быть цифровым (с мгновенной доставкой) или физическим (со странами доставки) и может иметь до 30 комбинаций вариантов, построенных из 1–3 групп опций.
/v1/shops/{shop}/productsshops:read/v1/shops/{shop}/productsshops:write/v1/shops/{shop}/products/{id}shops:read/v1/shops/{shop}/products/{id}shops:write/v1/shops/{shop}/products/{id}shops:writeТело запроса
| Поле | Тип | Обязательность | Описание |
|---|---|---|---|
| title | string | обязательно | 3–120 символов. |
| description / blurb | string | необязательно | Полное описание и строка для карточки в магазине (≤200 символов). |
| emoji | string | необязательно | Один эмодзи, отображаемый на карточке товара. |
| featured | boolean | необязательно | Не более одного рекомендуемого товара на магазин. |
| product_type | string | необязательно | digital (по умолчанию) или physical. |
| shipping_countries | array of strings | условно | Только для физических товаров: коды ISO, например ["FR","BE"], либо ["*"] для доставки по всему миру. |
| amount_type / currency / amount / min / max | mixed | условно | Базовая цена, правила идентичны платёжным ссылкам. Физические товары должны быть fixed. |
| max_uses | integer | необязательно | Общий лимит продаж (0 = без ограничений). |
| delivery_type + delivery_text/url/keys | mixed | необязательно | Цифровая доставка для базового товара, те же форматы, что и у платёжных ссылок. |
| variant_options | array | необязательно | 1–3 группы {name, values[]}, в каждой 2–10 значений. Число комбинаций не должно превышать 30. |
| variants | array | условно | По одному объекту на комбинацию (см. ниже). Обязательно и должно быть исчерпывающим при наличии variant_options. |
| status | string | необязательно | Только PATCH: active или paused. |
Объект варианта
| Поле | Тип | Описание |
|---|---|---|
| options | array of strings | По одному значению на группу опций, в порядке групп, например ["Pro","Lifetime"]. |
| price | number or string | Цена варианта в валюте товара. |
| stock | integer or null | Оставшееся количество единиц или null для неограниченного запаса. |
| delivery_type + delivery_text/url/keys | mixed | Необязательное переопределение цифровой доставки для конкретного варианта (по умолчанию inherit). Ключи должны быть уникальны в пределах всего товара. |
curl -X POST https://cryptopayin.com/v1/shops/SH-JYRK8TFJ/products \
-H "Authorization: Bearer $CPI_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Software license",
"amount": 30,
"currency": "USD",
"variant_options": [
{"name": "Edition", "values": ["Standard", "Pro"]},
{"name": "Term", "values": ["1 year", "Lifetime"]}
],
"variants": [
{"options": ["Standard","1 year"], "price": 30, "delivery_type": "keys", "delivery_keys": ["S1Y-1"]},
{"options": ["Standard","Lifetime"], "price": 79, "stock": 10, "delivery_type": "keys", "delivery_keys": ["SLT-1"]},
{"options": ["Pro","1 year"], "price": 59, "delivery_type": "keys", "delivery_keys": ["P1Y-1"]},
{"options": ["Pro","Lifetime"], "price": 149, "stock": 5, "delivery_type": "keys", "delivery_keys": ["PLT-1"]}
]
}'PATCH сохраняет существующие заказы и уже доставленные ключи. Чтобы изменить цены или остатки, отправьте заново соответствующий массив variants; опущенные комбинации приостанавливаются, если по ним есть заказы, иначе удаляются. Товар может содержать не более 10,000 активных лицензионных ключей суммарно по базовому товару и вариантам, и каждый ключ должен быть уникален в пределах товара.
Баланс
/v1/balancebalance:readВозвращает ваши расчётные балансы по каждому активу с приблизительной оценкой в USD и комиссией сети, взимаемой при выводе. Внутренний учёт всегда ведётся в USD; балансы формируются из завершённых платежей за вычетом комиссии мерчанта.
{
"object": "list",
"accounting_currency": "USD",
"minimum_payout_usd": 25,
"data": [{
"asset": "USDT",
"network": "TRC20",
"amount": "99.099",
"usd_estimate": 99.02,
"payout_network_fee": "2.445463"
}]
}usd_estimate равно null, когда проверенный живой курс временно недоступен; сам баланс при этом остаётся точным. Используйте эти значения для принятия решений о выводе средств, а не для итогового учёта.
Вывод средств
Переводит расчётную криптовалюту на внешний кошелёк. Вывод средств необратим, поэтому эта точка входа применяет те же меры защиты, что и кабинет: корректный адрес назначения для актива, проверенный живой курс, минимум по аккаунту, достаточный баланс с учётом комиссии сети и двухфакторное подтверждение, если на аккаунте включена 2FA.
/v1/payoutspayouts:read/v1/payoutspayouts:write · 30 / мин / ключ/v1/payouts/{id}payouts:readТело запроса
| Поле | Тип | Обязательность | Описание |
|---|---|---|---|
| asset | string | обязательно | Символ или сокращение, например LTC или USDT.TRC20. |
| network | string | условно | Обязательно, если символ существует в нескольких сетях. |
| amount | number or string | обязательно | Сумма к отправке без учёта комиссии сети, с точностью данного актива. Её эквивалент в USD должен соответствовать минимуму аккаунта. |
| address | string | обязательно | Адрес назначения, проверяется по сети соответствующего актива. |
| note | string | необязательно | Ваша собственная пометка, до 255 символов. |
| totp_code | string | условно | Текущий 6-значный код или код восстановления. Обязателен, если на аккаунте включена 2FA. |
curl -X POST https://cryptopayin.com/v1/payouts \
-H "Authorization: Bearer $CPI_SECRET_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: withdraw-2026-07-19-01" \
-d '{
"asset": "USDT.TRC20",
"amount": "50",
"address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"note": "weekly settlement"
}'{
"id": "W-EM64ZCJB",
"object": "payout",
"status": "requested",
"asset": "USDT",
"network": "TRC20",
"amount": "50",
"fee": "2.445463",
"total_debited": "52.445463",
"address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"txid": null,
"confirmations": 0,
"created_at": "2026-07-19T19:10:00+00:00"
}Жизненный цикл статуса
| Статус | Значение |
|---|---|
requested | Зарезервировано из вашего баланса; ожидает проверки оператором или автоматического одобрения. |
approved / processing | Одобрено и поставлено в очередь на отправку исполнителем. |
sent | Отправлено в блокчейн; заполняется поле txid. |
confirmed | Достигнуты необходимые подтверждения. Финальный статус. |
failed | Не удалось отправить; failure_message объясняет причину, средства возвращаются на баланс. |
cancelled | Отменено до отправки в блокчейн; зарезервированный баланс возвращается. |
Отправляйте Idempotency-Key, чтобы повторная попытка из-за сетевого сбоя никогда не создала второй вывод: тот же ключ с тем же телом запроса возвращает исходный вывод (Idempotent-Replayed: true); тот же ключ с другим телом возвращает 409 idempotency_conflict. Код 2FA намеренно исключён из отпечатка идемпотентности, чтобы меняющийся код не вызывал ложный конфликт. Резервирование списывает средства с баланса немедленно; при отклонённом или отменённом выводе средства возвращаются.
Аккаунт
/v1/accountлюбой действительный ключВозвращает профиль вашего аккаунта, области действия вызывающего ключа, комиссию платформы и все актуальные лимиты — полезно для самонастраивающейся интеграции или предварительной проверки.
{
"object": "account",
"id": "MC67T3PHQZ",
"fee_bps": 100,
"fee_percent": 1,
"default_currency": "USD",
"two_factor_enabled": false,
"api_key": {"label": "production", "scopes": ["payments:read","payments:write"]},
"limits": {
"shops": {"used": 1, "max": 10},
"payment_links": {"used": 0, "max": 50},
"products_per_shop_max": 50,
"variant_combinations_per_product_max": 30,
"license_keys_per_product_max": 10000,
"active_api_keys_max": 50,
"checkout_fields_per_link_max": 5
},
"minimum_payout_usd": 25
}Webhooks
Добавьте до 10 публичных HTTPS-точек входа в Кабинет -> Разработчики. Каждая точка входа получает собственный секрет подписи whsec_..., который показывается один раз. Она может прослушивать весь аккаунт или быть привязана к конкретному активному ключу API; точки входа, привязанные к ключу, получают только платежи, созданные этим ключом.
Проверяйте перед разбором
CryptoPayIn подписывает точное необработанное тело запроса с помощью секрета точки входа. Версия 1 подписывает timestamp + "." + raw_body. Отклоняйте устаревшие метки времени, прежде чем принять событие.
import crypto from "node:crypto";
const timestamp = req.headers["x-cpi-timestamp"];
const signature = req.headers["x-cpi-signature"];
const rawBody = req.rawBody; // Buffer captured before JSON parsing
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) {
throw new Error("stale webhook");
}
const expected = "sha256=" + crypto
.createHmac("sha256", process.env.CPI_WEBHOOK_SECRET)
.update(Buffer.concat([Buffer.from(`${timestamp}.`), rawBody]))
.digest("hex");
const valid = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
if (!valid) throw new Error("invalid webhook signature");
$rawBody = file_get_contents('php://input');
$timestamp = $_SERVER['HTTP_X_CPI_TIMESTAMP'] ?? '';
$received = $_SERVER['HTTP_X_CPI_SIGNATURE'] ?? '';
if (!ctype_digit($timestamp) || abs(time() - (int)$timestamp) > 300) {
http_response_code(400); exit('stale webhook');
}
$expected = 'sha256=' . hash_hmac(
'sha256', $timestamp . '.' . $rawBody, getenv('CPI_WEBHOOK_SECRET')
);
if (!hash_equals($expected, $received)) {
http_response_code(401); exit('invalid signature');
}
$event = json_decode($rawBody, true, flags: JSON_THROW_ON_ERROR);
import hashlib, hmac, os, time
raw_body = request.get_data() # bytes, before JSON decoding
timestamp = request.headers.get("X-CPI-Timestamp", "")
received = request.headers.get("X-CPI-Signature", "")
if not timestamp.isdigit() or abs(time.time() - int(timestamp)) > 300:
raise ValueError("stale webhook")
signed = timestamp.encode() + b"." + raw_body
expected = "sha256=" + hmac.new(
os.environ["CPI_WEBHOOK_SECRET"].encode(), signed, hashlib.sha256
).hexdigest()
if not hmac.compare_digest(expected, received):
raise ValueError("invalid signature")Заголовки доставки
| Заголовок | Пример | Назначение |
|---|---|---|
| Content-Type | application/json | Тело в формате UTF-8 JSON. |
| X-CPI-Timestamp | 1784293200 | Unix-время (секунды), включённое в подписываемое сообщение. |
| X-CPI-Signature | sha256=... | HMAC-SHA256 в hex-формате. |
| X-CPI-Signature-Version | v1 | Версия схемы подписи. |
| X-CPI-Event-Id | evt_a12b... | Стабильный логический ID события; одинаков при повторных попытках. |
| X-CPI-Delivery-Id | 1842 | Стабильный ID записи о доставке для точки входа. |
Полезная нагрузка платежа
{
"event_id": "evt_a12b34c56d78e90f12345678",
"event": "payment.completed",
"id": "P-9F27C1E4KD",
"status": "completed",
"order_ref": "order_1042",
"amount": 49.99,
"amount_decimal": "49.99",
"amount_minor": 4999,
"currency_minor_units": 2,
"currency": "USD",
"amount_usd": 49.99,
"amount_usd_cents": 4999,
"fx_rate_usd": "1.000000000000",
"fx_source": "fixed:USD",
"fx_observed_at": "2026-07-17T13:00:00Z",
"fx_discrepancy_bps": 0,
"exchange_rate": "3600.00000000",
"exchange_rate_currency": "USD",
"exchange_rate_source": "median:cb,cg,cl",
"exchange_rate_source_count": 3,
"exchange_rate_observed_at": "2026-07-17T13:00:00Z",
"exchange_rate_discrepancy_bps": 12,
"asset": "ETH",
"network": "mainnet",
"crypto_amount": "0.01388612",
"crypto_received": "0.01388612",
"txid": "0x9d81...75af",
"confirmations": 12,
"confirmations_required": 12,
"deposit_address": "0x71b8c3d4700000000000000000000000000084e2",
"sent_at": "2026-07-17T13:12:42Z"
}Повторные попытки и безопасность точки входа
Доставка считается успешной при HTTP 200-299. Выполняйте затратные операции асинхронно и отвечайте быстро.
Точное тело запроса и ID события сохраняются; при сбое повтор происходит примерно через 1 минуту, 5 минут, 30 минут, 2 часа и 6 часов.
Ответы 3xx не обрабатываются. Регистрируйте сразу конечный HTTPS-URL.
Частные, локальные (loopback), link-local и зарезервированные IP-адреса заблокированы; каждый DNS-ответ проверяется, а соединение закрепляется (pinning).
Доставка гарантируется как минимум один раз. Сделайте свой обработчик идемпотентным: записывайте event_id с ограничением уникальности перед выполнением заказа. При сверке неожиданного события получайте объект через API.
Справочник событий
payment.completedОжидаемая сумма подтверждена.payment.overpaidПодтверждено больше ожидаемого.payment.underpaidОбнаружено поступление ниже допустимого порога.payment.expiredИстекло окно для неоплаченного счёта.payment.failedСбой при создании или обработке платежа.payout.sentВывод отправлен в блокчейн.payout.confirmedВывод достиг нужных подтверждений.payout.failedВывод не удалось завершить.webhook.testРучная проверка соединения.Формат события вывода средств
{
"event_id": "evt_b98c76d54e32a10f87654321",
"event": "payout.sent",
"id": "W-8J2K7M4RQP",
"status": "sent",
"asset": "ETH",
"network": "mainnet",
"amount": "0.25",
"fee": "0.00081768",
"address": "0x84f2...9bc1",
"txid": "0xa1c4...07ee",
"confirmations": 0,
"note": "weekly treasury",
"sent_at": "2026-07-17T14:08:31Z"
}Ошибки и лимиты запросов
Ошибки всегда используют единый JSON-конверт. Ветвите логику по error.type; текст сообщения для человека может улучшаться без изменения версии. При обращении в поддержку указывайте error.request_id или соответствующий заголовок ответа X-Request-Id.
{
"error": {
"type": "ambiguous_asset",
"message": "specify network (e.g. USDT.ERC20 or USDT.TRC20)",
"request_id": "b942e21f8dca4b06b8672eb9"
}
}| HTTP | Типичные типы | Значение |
|---|---|---|
| 400 | invalid_request, unknown_parameter | Некорректный JSON, параметры запроса или заголовок идемпотентности. |
| 401 | unauthorized | Отсутствующие, недействительные или неактивные учётные данные/аккаунт. |
| 403 | insufficient_scope, admin_disabled | Действительный ключ без нужного права доступа (см. X-Required-Scope), либо ресурс, заблокированный администратором. |
| 404 | not_found | Неизвестная точка входа либо ресурс за пределами этого аккаунта мерчанта. |
| 405 | method_not_allowed | Используйте метод, указанный в заголовке Allow. |
| 409 | idempotency_conflict | Ключ использован повторно с другим JSON. |
| 413 | request_too_large | Тело JSON превышает 64 KiB. |
| 415 | unsupported_media_type | Тело POST-запроса не объявлено как application/json. |
| 422 | invalid, limit, invalid_amount, below_minimum, bad_address, 2fa_required, unsupported_asset | Корректно оформленный запрос не прошёл детерминированную валидацию либо достиг лимита ресурса. |
| 429 | rate_limited | Дождитесь Retry-After. |
| 500 | server_error | Непредвиденный сбой; можно безопасно повторить запрос с тем же ключом идемпотентности. |
| 503 | maintenance, temporarily_unavailable, asset_unavailable, no_rate, price_stale, fiat_rate_unavailable, fiat_rate_stale, derive_failed | Временный сбой платформы, ноды, курса или выделения адреса. Устаревшая конвертация никогда не подставляется. |
Текущие лимиты
| Категория | Лимит | Окно |
|---|---|---|
| Защитный лимит Nginx на IP | 10 запросов/секунду, всплеск до 30 | Непрерывно |
| Лимит для неаутентифицированного IP | 300 запросов | 60 секунд |
| POST /v1/payments, links, shops, products | 120 запросов на ключ API | 60 секунд |
| POST /v1/payouts | 30 запросов на ключ API | 60 секунд |
| GET-точки входа | 240 запросов на ключ API | 60 секунд |
Лимиты аккаунта
| Ресурс | Лимит |
|---|---|
| Магазинов на аккаунт | 10 |
| Платёжных ссылок на аккаунт | 50 |
| Товаров на магазин | 50 |
| Комбинаций вариантов на товар | 30 |
| Лицензионных ключей на товар / ссылку | 10,000 |
| Вопросов при чекауте на ссылку | 5 |
| Активных ключей API на аккаунт | 50 |
Актуальное использование относительно этих лимитов можно посмотреть в GET /v1/account.
Успешные ответы, ограниченные на уровне приложения, содержат заголовки X-RateLimit-Limit, X-RateLimit-Remaining и X-RateLimit-Reset. Повторяйте 429, 500 и 503 с экспоненциальной задержкой и джиттером. Для POST всегда используйте тот же исходный Idempotency-Key и идентичный JSON.
Безопасность интеграции
Загружайте их во время выполнения; никогда не записывайте полное значение в логи и не сохраняйте в системе контроля версий.
Браузер или мобильное приложение не могут безопасно хранить секрет мерчанта.
Перед разбором JSON проверяйте актуальность метки времени и сравнивайте подпись за постоянное время.
Записывайте обработанные события/заказы транзакционно, чтобы повторные попытки никогда не приводили к двойной отправке.
Запрашивайте платёж, если событие неожиданно или ваше локальное состояние расходится с ним.
Создайте новый ключ, разверните его, убедитесь в корректности трафика и только потом удалите старый ключ.
Доступ к аккаунту контролируется невосстанавливаемым 16-значным ключом мерчанта, дополнительно защищаемым TOTP по желанию. Храните и ключ доступа мерчанта, и секреты API с той же осторожностью, что и учётные данные от кошелька.
Чек-лист перед запуском
Не используйте повторно личную копию ключа разработчика в разных сервисах.
Используйте GET /v1/assets и GET /v1/currencies; отображайте только записи, которые присутствуют и available: true.
Сохраните секрет подписи один раз; проверяйте метку времени и подпись, а затем дедуплицируйте по стабильному ID события.
Проверьте повторную отправку дубликата и убедитесь, что существует только один ID платежа.
Состояние вашего заказа должно оставаться корректным при устаревших фиатных курсах, недоступных активах, задержке подтверждений и любом нештатном сценарии.
Сравнивайте свои заказы со статусами платежей в API, логами webhook и реестром мерчанта.
Готовы к интеграции?
Создайте аккаунт за несколько секунд, сгенерируйте ключ и держите этот справочник рядом с кодом.