API платёжных ссылок и ключи
Создайте счёт из своего backend и сразу получите checkoutUrl. API поддерживает права ключей, идемпотентные повторы, отдельные доли комиссии и НДС, идентификатор заказа и приватные метаданные.
В этой статье
Серверный запрос и готовая ссылка#
POST /api/v1/payments и /api/v1/payment-links создают один и тот же тип счёта. Название маршрута payments не означает списание: результат — сохранённые условия и checkoutUrl для покупателя.
Отправьте Authorization: Bearer <ключ>, Content-Type: application/json и Idempotency-Key. Ключ идемпотентности содержит 16–100 символов A–Z, a–z, 0–9, дефис или подчёркивание. Сохраните его на сервере для одного логического заказа.
curl 'https://kevmi.maxeevmax1.chatgpt.site/api/v1/payments' \
-H "Authorization: Bearer $KEVMI_API_KEY" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: order-1042-create-v1' \
--data '{"title":"Design project · order 1042","description":"One-time payment for the agreed design work","amountMinor":500,"currency":"USD","methods":["card","alipay"],"vatCustomerPercent":100,"feeCustomerPercent":0,"orderId":"order-1042","metadata":{"campaign":"autumn"}}'Права и срок API-ключа#
Создайте ключ в кабинете /account#keys после подтверждения аккаунта. Полное значение показывается один раз; в базе хранится только хеш. По умолчанию ключ действует 90 дней, допустимый срок — 1–365 дней. У аккаунта может быть до десяти активных ключей.
Выдавайте только нужные права. Отзыв или истечение срока прекращают доступ. Ключ не заменяет браузерную сессию для настроек аккаунта, управления endpoints, заявок и модерации. Секрет не должен попадать в виджет, URL, публичный репозиторий или сообщения поддержки.
Браузер сайта использует /api/payment-links с cookie сессии, точным Origin и X-CSRF-Token. Эти маршруты работают с теми же собственными счетами.
| Право | Назначение |
|---|---|
| invoices:read | Читать собственные счета и их список |
| invoices:write | Создавать счета и менять доступность ссылок |
| events:read | Читать серверный журнал событий |
Any и конкретные способы в API#
Any — режим выбора в интерфейсе. Для нового счёта API принимает methods: ["card", "alipay"] или непустое подмножество в USD; ["sbp"] в RUB; ["crypto"] в USDT. Значение any не является методом API.
В интерфейсе для нового счёта USD доступны карты и Alipay, для RUB — СБП, для USDT — криптовалюта. API для совместимости может сохранить USD + crypto, но такая криптооплата не запускается и возвращает crypto_requires_usdt. USD и USDT различаются; автоматической конвертации или курса 1:1 нет. Для криптооплаты нужен отдельный счёт в USDT.
Для нового реального платежа картой или Alipay текущий шлюз поддерживает только feeCustomerPercent=0 и vatCustomerPercent=100: комиссию полностью покрывает магазин, НДС полностью добавляется покупателю. Остальные доли можно сохранить в счёте и рассчитать, но такой платёж не запускается и получает unsupported_allocation. Сервер не меняет сохранённые условия автоматически. Для СБП и USDT-криптооплаты доступны все доли комиссии; НДС у них отсутствует.
Поля и сохранённые условия#
Сохраняются имя магазина, цена, валюта, методы, обе доли расходов и расчёты. Метаданные возвращаются владельцу и в серверных событиях, но не в публичном checkout. Не храните там платёжные секреты.
Если доли пропущены, комиссия полностью относится к магазину; НДС наследует vatPayer или правило аккаунта. В промежуточном распределении ответ может содержать vatPayer=shared. Название заказа, orderId и описание публичны.
| Поле | Правило |
|---|---|
| title / description | 1–120 / 0–500 символов |
| amountMinor | Целое 1–10 000 000 000; 500 означает $5,00 в USD |
| currency / methods | USD: card, alipay; RUB: sbp; USDT: crypto. Непустой уникальный список. |
| vatCustomerPercent / feeCustomerPercent | Две независимые целые доли покупателя 0–100 |
| vatPayer | Совместимость: customer или merchant; не противоречит доле НДС |
| orderId | Необязательно, до 100 символов; виден покупателю |
| metadata | До 10 строковых полей; ключ 1–40 A–Z a–z 0–9 _ -; значение до 500; всего до 3000 UTF-8 байт |
| expiresAt | Будущий Unix ms не дальше 90 дней; по умолчанию 7 дней |
Повтор после ошибки сети#
Первое создание возвращает 201 и replayed=false. Тот же ключ с тем же каноническим телом возвращает 200, исходный checkoutUrl и replayed=true. Другой запрос с прежним ключом даёт 409 IDEMPOTENCY_CONFLICT.
Не генерируйте новый ключ после тайм-аута. Повторите исходный запрос с теми же полями. Пропущенные значения не наследуют заново изменившиеся настройки. orderId помогает сопоставить заказ, но не заменяет Idempotency-Key и не обязан быть уникальным в базе.
Чтение и пагинация#
GET /api/v1/payments возвращает links и nextCursor; GET /api/v1/payments/{id} — один принадлежащий владельцу link. Нужен invoices:read. Размер страницы по умолчанию 30, limit — от 1 до 100.
Ответы GET списка и отдельного счёта включают link.payment: краткую сводку связанной операции или null, если операции ещё нет. Ответы POST/PATCH могут не включать это поле: при необходимости прочитайте счёт повторно. Состояние ссылки отдельно описывает возможность начать новый платёж. Реквизиты карты и закрытые ключи сюда не входят.
Передавайте nextCursor без изменений через URLSearchParams. null означает конец списка; чужой и неизвестный ID возвращают 404.
GET /api/v1/payments?limit=30
Authorization: Bearer <server-side key>Пауза, возобновление и отмена#
PATCH /api/v1/payments/{id} с правом invoices:write принимает только {"status":"active"}, {"status":"paused"} или {"status":"cancelled"}. Отмена окончательна. expired определяется по сроку; истёкший счёт не продлевается.
Цена, доли расходов, описание, orderId, метаданные и срок неизменны. Для других условий создайте новый счёт. Изменение доступности создаёт invoice.updated, а не событие успешного платежа.
Что получает покупатель#
GET /api/checkout/{token}?method=card возвращает публичный счёт, расчёт, доступность способа и существующую операцию. Метаданные владельца, секреты и баланс не раскрываются.
POST /api/checkout/{token}/pay требует Origin сайта и выбранный конкретный метод. Карта передаётся только в sealed: {intent,jwe}; предварительно браузер получает /card-intent. Код банка отправляется зашифрованным через /code. Для криптооплаты используется сохранённый USDT-счёт и доступная пара монеты/сети.
Новый платёж и подготовка карточного запроса требуют одобренной последней заявки магазина на проверку сайта. Одобрение само по себе не подключает платёжный шлюз. Если проверка магазина изменилась после отправки платежа, уже созданная операция остаётся доступна для статуса, сверки и запрошенного банковского кода.
Отсутствие рабочего соединения возвращает GATEWAY_NOT_CONNECTED; несовместимое распределение не заменяется другим расчётом. Статус и reconcile читают прежнюю операцию и не создают повторное списание.
Несколько магазинов и единая цена в USD#
В меню магазина выберите «Все магазины» для общего обзора и операций или конкретный магазин для его данных. Каждый магазин имеет собственный storeId, название, правило НДС, счета, API-ключи, вебхуки, журнал событий и заявку на проверку сайта. Уведомления и обращения принадлежат аккаунту. Можно создать до 100 магазинов. Ранее созданные данные сохранены в первом магазине.
Новые ссылки из кабинета используют pricingMode="universal": базовая цена хранится в USD. Any включает card, alipay, sbp и crypto; при необходимости магазин выбирает подмножество. Карты и Alipay оплачиваются в USD, СБП — в RUB по официальному курсу USD/RUB Банка России, криптовалюта — в USDT по явно установленному соотношению 1 USD = 1 USDT. Это правило расчёта счёта, а не рыночная котировка USDT. Курс другой монеты и точные реквизиты предоставляет шлюз перед переводом.
Курс ЦБ и обе суммы сохраняются при создании. Ссылки с рублёвой конвертацией действуют не более 24 часов. Если курс получить не удалось, создание возвращает FX_UNAVAILABLE; выдуманный или старый запасной курс не применяется. amountMinor и quotes в ответе владельцу выражены в базовой валюте USD; quotes[method].settlement содержит сумму и валюту конкретного способа. Публичный checkout возвращает выбранную валюту оплаты в currency, исходную цену в baseAmountMinor/baseCurrency и курс в fx. Возврат к другой валюте после отправки платежа запрещён: у счёта одна операция шлюза.
Для серверной интеграции создайте API-ключ внутри выбранного магазина и передавайте Authorization: Bearer <key>. Привязка ключа к магазину неизменна: заголовок X-Kevmi-Store не позволяет получить данные другого магазина. Для браузерной сессии передавайте X-Kevmi-Store: <storeId>; без заголовка используется первый магазин. Значение all разрешено только для GET /api/account/dashboard и GET /api/payment-links. Изменения требуют выбранного магазина, Origin и X-CSRF-Token. ID аккаунта и ID магазина — разные идентификаторы.
Без pricingMode="universal" API сохраняет прежний режим native и исходные ограничения валют для совместимости. Старые ссылки не пересчитываются. Подтверждённые поступления в обзоре — это проверенные платежи за вычетом расходов по сохранённому расчёту, а не доступный остаток для вывода. Валюты старых счетов учитываются раздельно; выплаты согласуются с поддержкой. Подтверждение исполнения заказа проверяйте через payment.fulfillmentReady=true и payment.status="succeeded" в серверном API, журнале событий или подписанном вебхуке.