API Reference / Version 1
От первого запроса
до выпуска карты.
Выпуск, пополнение и управление виртуальными картами из вашего приложения. Все методы, параметры и примеры ответов — здесь.
/v1Быстрый старт
- Шаг 01
Создайте аккаунт и API-ключ в личном кабинете.
- Шаг 02
Передайте ключ в заголовке Authorization.
- Шаг 03
Выпустите карту с нужной платёжной сетью.
curl /v1/me \
-H "Authorization: Bearer cmk_live_YOUR_KEY"Спецификация для вашего проекта
Импортируйте OpenAPI в ваш API-клиент или передайте ИИ-агенту для генерации интеграции. Используйте переменную окружения вместо реального ключа.
Авторизация и правила
Bearer API key
Все запросы требуют заголовок Authorization: Bearer cmk_live_….
Формат JSON
Тело запроса и ответ используют application/json. Результат находится в поле data.
Идемпотентность
Для выпуска и пополнения обязательно передавайте уникальный client_request_id в JSON. Для повтора той же операции используйте прежнее значение. Другой запрос с тем же ID получит 409. При operation_requires_review обратитесь в поддержку; деньги автоматически не возвращаются.
Аккаунт
Проверка ключа и внутреннего баланса клиента.
GET/meТекущий аккаунт
/meТекущий аккаунт
Проверяет API-ключ и возвращает владельца аккаунта.
{
"data": {
"id": "uuid",
"username": "demo",
"role": "user",
"balance_usd": 125.5,
"disabled": false
}
}Подготовка операции
Посмотрите справочную информацию о карточных продуктах. Конкретный BIN при выпуске не выбирается.
GET/binsДоступные BIN
/binsДоступные BIN
Список доступных карточных продуктов с сетью, страной, валютой и лимитами.
{
"data": [
{
"bin": "424242",
"network": "visa",
"country": "US",
"currency": "USD",
"min_amount": 20,
"max_amount": 1000,
"available": true,
"apple_pay": false,
"google_pay": false,
"stripe": false
}
]
}Карты
Выпуск, реквизиты и пополнение виртуальной карты.
GET/cards?limit=50&offset=0Список карт
/cards?limit=50&offset=0Список карт
Возвращает карты владельца ключа.
{
"data": [
{
"id": "card-uuid",
"status": "active",
"network": "visa",
"last4": "4242",
"amount_usd": 25,
"total_loaded_usd": 25,
"balance_usd": 25,
"holder_name": "IVAN IVANOV",
"created_at": 1791378000000
}
],
"total": 1
}POST/cardsВыпустить карту
/cardsВыпустить карту
Создаёт виртуальную карту и списывает рассчитанную стоимость с внутреннего баланса.
Передавайте уникальный client_request_id в JSON, чтобы повтор запроса не создал вторую карту.
{
"amount_usd": 25,
"network": "visa",
"holder_name": "IVAN IVANOV",
"holder_email": "[email protected]",
"client_request_id": "order-1001"
}{
"data": {
"id": "card-uuid",
"status": "active",
"network": "visa",
"last4": "4242",
"amount_usd": 25,
"total_loaded_usd": 25,
"balance_usd": 25,
"holder_name": "IVAN IVANOV",
"created_at": 1791378000000
}
}GET/cards/{id}Состояние карты
/cards/{id}Состояние карты
Возвращает статус, сеть, последние 4 цифры, баланс и лимиты одной карты.
{
"data": {
"id": "card-uuid",
"status": "active",
"network": "visa",
"last4": "4242",
"amount_usd": 25,
"total_loaded_usd": 25,
"balance_usd": 25,
"holder_name": "IVAN IVANOV",
"created_at": 1791378000000
}
}GET/cards/{id}/detailsРеквизиты карты
/cards/{id}/detailsРеквизиты карты
Возвращает PAN, CVV и срок действия. Используйте только в защищённом интерфейсе.
Ограничение: 20 запросов в минуту.
{
"data": {
"id": "uuid",
"number": "4242…",
"cvv": "123",
"expiry": "12/30",
"holder_name": "IVAN IVANOV"
}
}POST/cards/{id}/topupПополнить карту
/cards/{id}/topupПополнить карту
Добавляет USD на баланс карты и списывает стоимость с внутреннего баланса.
Передавайте client_request_id в JSON. Повтор той же операции не приводит к повторному списанию.
{
"amount_usd": 50,
"client_request_id": "topup-1001"
}{
"data": {
"id": "card-uuid",
"status": "active",
"network": "visa",
"last4": "4242",
"amount_usd": 25,
"total_loaded_usd": 75,
"balance_usd": 75,
"holder_name": "IVAN IVANOV",
"created_at": 1791378000000
}
}Операции и 3DS
История платежей и события карты, включая 3DS.
GET/cards/{id}/transactions?limit=50&offset=0Транзакции
/cards/{id}/transactions?limit=50&offset=0Транзакции
Возвращает покупки, пополнения, статусы и причины отклонения.
{
"data": [
{
"id": "transaction-uuid",
"card_id": "card-uuid",
"type": "authorization",
"status": "posted",
"amount_usd": 12.5,
"currency": "USD",
"merchant": "Example Store",
"created_at": 1791378000000
}
],
"total": 1
}GET/cards/{id}/events?limit=50&offset=0События
/cards/{id}/events?limit=50&offset=0События
Возвращает технические события карты, включая запросы 3DS.
{
"data": [
{
"id": "event-uuid",
"card_id": "card-uuid",
"type": "card.3ds.required",
"otp_code": "123456",
"merchant": "Example Store",
"currency": "USD",
"created_at": 1791378000000
}
],
"total": 1
}Вебхуки
Уведомления отправляются после обработки события в Cardmaker. ID карты и события — наши. Состояние карты отражает момент отправки; при повторной доставке оно может измениться. Уведомления формируются из сохранённых записей Cardmaker. Реквизиты карты не отправляются.
GET/webhooksСписок вебхуков
/webhooksСписок вебхуков
Активные URL текущего пользователя. Настройки также доступны в личном кабинете в разделе «Вебхуки».
{
"data": [
{
"id": "webhook-uuid",
"url": "https://example.com/webhooks/cardmaker",
"events": [],
"active": true,
"created_at": 1791378000000
}
]
}GET/webhooks/{id}/deliveries?limit=50&offset=0Журнал доставок
/webhooks/{id}/deliveries?limit=50&offset=0Журнал доставок
Статусы pending, delivered, failed, cancelled. Ошибки повторяются до 12 попыток с растущей задержкой от 5 секунд. Срок доставки — 24 часа, журнал хранится 30 дней. Ответ 2xx подтверждает доставку; редиректы не выполняются.
{
"data": [
{
"id": "delivery-uuid",
"event_id": "event-uuid",
"event_type": "card.issued",
"status": "delivered",
"attempts": 1,
"status_code": 200,
"next_attempt_at": 0,
"delivered_at": 1791378000000,
"created_at": 1791378000000
}
],
"total": 1
}POST → ваш URLВходящее уведомление
→ ваш URLВходящее уведомление
События: card.issued, card.frozen, card.unfrozen, card.closed, card.topup.succeeded, card.transaction.posted, card.transaction.declined, card.3ds.required, card.3ds.resolved. Для пополнений data.topup включается при точном совпадении client_request_id. Для 3DS data.event содержит otp_code и expires_at.
Проверяйте X-Cardmaker-Signature по алгоритму из раздела «Подпись вебхука». Заголовки X-Cardmaker-Event-Id, X-Cardmaker-Delivery-Id, X-Cardmaker-Event идентифицируют событие и доставку. Обрабатывайте id идемпотентно: повторы возможны, порядок доставки не гарантируется. Поля времени в JSON — Unix в миллисекундах.
{
"id": "event-uuid",
"type": "card.transaction.posted",
"created_at": 1791378000000,
"processed_at": 1791378001000,
"data": {
"card": {
"id": "card-uuid",
"status": "active",
"amount_usd": 25,
"total_loaded_usd": 25,
"balance_usd": 12.5,
"created_at": 1791378000000
},
"event": {
"id": "event-uuid",
"card_id": "card-uuid",
"type": "card.transaction.posted",
"amount": 12.5,
"currency": "USD",
"created_at": 1791378000000
}
}
}Подпись вебхука
Каждый запрос содержит заголовок X-Cardmaker-Signature. Его значение — MD5-хеш в виде 32 шестнадцатеричных символов в нижнем регистре. MD5 не шифрует тело: уведомление передаётся обычным JSON.
- Возьмите исходные байты HTTP-тела до разбора JSON. Пробелы, переносы строк и порядок полей имеют значение.
- Добавьте в конец байты вашего signing_secret в UTF-8 без разделителя.
- Вычислите MD5 и преобразуйте результат в hex в нижнем регистре. Формула:
md5(raw_body + signing_secret). - Сравните результат с X-Cardmaker-Signature. Секрет показывается при создании вебхука в личном кабинете.
import { createHash, timingSafeEqual } from "node:crypto";
// rawBody — Buffer с исходными байтами HTTP-тела.
function verifySignature(rawBody, signingSecret, signature) {
if (typeof signature !== "string" || !/^[0-9a-f]{32}$/.test(signature)) return false;
const expected = createHash("md5")
.update(rawBody)
.update(signingSecret, "utf8")
.digest();
return timingSafeEqual(expected, Buffer.from(signature, "hex"));
}Заголовок содержит только хеш, без timestamp и префиксов. Храните секрет на сервере. Повторные уведомления с тем же id обрабатывайте идемпотентно.
Возможные ошибки
HTTP-статус описывает тип ошибки. Поле error содержит её причину.
400Некорректный JSON, сумма401Ключ отсутствует, отозван или неверен403Аккаунт отключён или нет доступа404Карта или событие не найдено402insufficient_balance — недостаточно средств409Конфликт состояния или реквизиты ещё не готовы429rate_limited — превышен лимит запросов502service_unavailable — сервис временно недоступен500Внутренняя ошибка сервиса{
"error": "insufficient_balance"
}