Обзор API

Quantum Payouts предоставляет REST API для интеграции с внешними системами. API позволяет создавать выплаты, отслеживать их статус и получать информацию о возможностях системы.

Основные возможности

  • Создание выплат - регистрация выплаты с получением ссылки на страницу указания реквизитов
  • Отслеживание статуса - получение актуальной информации о состоянии выплаты
  • Информация о системе - получение доступных функций и ограничений
  • Безопасная авторизация - использование Bearer токенов для аутентификации

Базовый URL

https://payouts-dev.quantumlabs.ru/api/v1/

Формат данных

  • Запросы: JSON (Content-Type: application/json; charset=UTF-8)
  • Ответы: JSON (Accept: application/json; version=1.0)
  • Кодировка: UTF-8
  • Суммы: в копейках (например, 150000 = 1500.00 рублей)

Авторизация

Все API запросы требуют авторизации с использованием Bearer токена.

Получение API токена

  1. Войдите в личный кабинет
  2. Перейдите в Настройки → API
  3. Нажмите "Создать API токен"
  4. Скопируйте сгенерированный токен
  5. Сохраните токен в безопасном месте

Использование токена

HTTP заголовок
Authorization: Bearer YOUR_API_TOKEN

⚠️ Безопасность: Никогда не передавайте API токен в URL параметрах или в незащищенном виде. Используйте только HTTPS соединения.

Создание выплаты

Эндпоинт для регистрации новой выплаты и получения ссылки на страницу указания реквизитов.

Параметры запроса

Требуемые заголовки:
Authorization: Bearer YOUR_API_TOKEN,
Accept: application/json; version=1.0,
Content-Type: application/json; charset=UTF-8.

Параметр Тип Обязательный Описание
orderNumber String Да Уникальный идентификатор выплаты (до 36 символов)
amount Integer Да Сумма в копейках (до 12 цифр)
urls Object Да Контейнер ссылок для редиректов
urls.returnUrl String Да URL для перенаправления при успехе
urls.failUrl String Нет URL для перенаправления при ошибке
description String Нет Описание выплаты
sessionTimeoutSecs Integer Нет Время жизни сессии в секундах (по умолчанию 600)
type String Нет Тип выплаты: "card" или "sbp" или не отправлять его.

Пример запроса

POST /api/v1/createPayoutJSON
curl -X POST 'https://payouts-dev.quantumlabs.ru/api/v1/createPayout' \
  -H 'Content-Type: application/json; charset=UTF-8' \
  -H 'Accept: application/json; version=1.0' \
  -H 'Authorization: Bearer YOUR_API_TOKEN' \
  -d '{
    "orderNumber": "ORDER_12345",
    "amount": 150000,
    "description": "Выплата по заказу #12345",
    "sessionTimeoutSecs": 1800,
    "type": "card",
    "urls": {
      "returnUrl": "https://your-site.com/success",
      "failUrl": "https://your-site.com/fail"
    }
  }'

Параметры ответа

Параметр Тип Обязательный Описание
result.error String Да Код ошибки ("0" = успех)
result.message String Да Сообщение об ошибке (null при успехе)
payoutUrl String Да Ссылка на страницу указания реквизитов
orderId String Да Внутренний идентификатор заказа
orderNumber String Да Номер заказа из запроса

Пример успешного ответа

200HTTP 200 - Успешный ответ
{
  "result": {
    "error": "0",
    "message": null
  },
  "payoutUrl": "https://payouts-dev.quantumlabs.ru/static/payout.php?payout_id=123&token=abc123",
  "orderId": "PAY_2024_12_19_abc123",
  "orderNumber": "ORDER_12345"
}

Пример ошибочного ответа

400HTTP 400 - VALIDATION_ERROR
{
  "result": {
    "error": "VALIDATION_ERROR",
    "message": "urls.returnUrl is required; amount must be positive"
  }
}

Выполнение выплаты

Эндпоинт для немедленного выполнения одиночной выплаты на карту. Заявка создается и отправляется в банк в рамках одного запроса.

Параметры запроса

Требуемые заголовки:
Authorization: Bearer YOUR_API_TOKEN,
Accept: application/json; version=1.0,
Content-Type: application/json; charset=UTF-8.

Параметр Тип Обязательный Описание
orderNumber String Да Уникальный идентификатор выплаты (до 32 символов). Идемпотентность по связке (user, orderNumber).
amount Integer Да Сумма в копейках (до 12 цифр). Пример: 150000 = 1500.00 ₽
description String Да Описание операции (до ~600 символов)
target Object Да Контейнер реквизитов получателя
target.pan String Да Номер карты получателя (13–19 цифр)

Пример запроса

POST /api/v1/performPayoutJSON
curl -X POST 'https://payouts-dev.quantumlabs.ru/api/v1/performPayout' \
  -H 'Content-Type: application/json; charset=UTF-8' \
  -H 'Accept: application/json; version=1.0' \
  -H 'Authorization: Bearer YOUR_API_TOKEN' \
  -d '{
    "orderNumber": "ORDER_12345",
    "amount": 150000,
    "description": "Разовая выплата",
    "target": {
      "pan": "4111111111111111"
    }
  }'

Параметры ответа

Параметр Тип Обязательный Описание
result Object Да Блок статуса выполнения запроса
result.error String Да Код ошибки ("0" = успех)
result.message String Да Сообщение об ошибке (null при успехе)
target Object Нет Информация о реквизитах (при наличии)
target.maskedPan String Да Маскированный номер карты
orderNumber String Да Идентификатор заказа
orderStatus String Да Статус заказа (created, processing, completed, failed)
amount Integer Да Сумма в копейках
creationDate Integer Да Unix timestamp создания
orderId String Да Банковский код заказа (если есть)

Пример успешного ответа

200HTTP 200 - Успешный ответ
{
  "result": { "error": "0", "message": null },
  "orderNumber": "ORDER_12345",
  "orderStatus": "processing",
  "amount": 150000,
  "creationDate": 1737097200,
  "orderId": "BANK_ORDER_CODE_OPTIONAL",
  "target": { "maskedPan": "411111******1111" }
}

Пример ошибочного ответа

400HTTP 400 - VALIDATION_ERROR
{
  "result": {
    "error": "VALIDATION_ERROR",
    "message": "orderNumber is required; amount must be greater than 0"
  }
}

Получение статуса выплаты

Эндпоинт для получения актуальной информации о состоянии выплаты.

Параметры запроса

Требуемые заголовки:
Authorization: Bearer YOUR_API_TOKEN,
Accept: application/json; version=1.0,
Content-Type: application/json; charset=UTF-8.

Параметр Тип Обязательный Описание
orderNumber String Да Идентификатор выплаты (до 32 символов)

Пример запроса

POST /api/v1/getPayoutStatusJSON
curl -X POST 'https://payouts-dev.quantumlabs.ru/api/v1/getPayoutStatus' \
  -H 'Content-Type: application/json; charset=UTF-8' \
  -H 'Accept: application/json; version=1.0' \
  -H 'Authorization: Bearer YOUR_API_TOKEN' \
  -d '{
    "orderNumber": "ORDER_12345"
  }'

Параметры ответа

Параметр Тип Обязательный Описание
result Object Да Блок статуса выполнения запроса
result.error String Да Код ошибки ("0" = успех)
result.message String Да Сообщение об ошибке (null при успехе)
target Object Нет Информация о реквизитах (при наличии)
target.maskedPan String Да Маскированный номер карты (для карточных выплат)
target.maskedPhone String Нет Маскированный номер телефона (для СБП выплат)
orderNumber String Да Идентификатор заказа
orderStatus String Да Статус заказа (created, processing, completed, failed)
amount Integer Да Сумма в копейках
creationDate Integer Да Unix timestamp создания
orderId String Да Банковский код заказа (если есть)

Пример успешного ответа

200HTTP 200 - Успешный ответ
{
  "result": {
    "error": "0",
    "message": null
  },
  "orderStatus": "success",
  "orderNumber": "ORDER_12345",
  "amount": 150000,
  "currency": "RUB"
}

Пример ошибочного ответа

404HTTP 404 - PAYOUT_NOT_FOUND
{
  "result": {
    "error": "PAYOUT_NOT_FOUND",
    "message": "Payout with this orderNumber not found"
  }
}

Webhook

Статический webhook для уведомлений о событиях (например, об изменении статуса выплаты). Настройка выполняется в ЛК → Настройки → Webhook.

Формат события

{
  "event": "payout.status_changed",
  "eventId": "2f4b1b0a0c2a4d32b2b0c9d311e7e59b",
  "occurredAt": "2025-09-15T19:40:21+03:00",
  "payout": {
    "id": 123456,
    "externalId": "INV-2025-0001",
    "status": "SUCCESS",
    "amount": 12345,
    "currency": "RUB"
  }
}
  • amount — сумма в копейках (минимальные единицы валюты)
  • occurredAt — ISO8601 (Europe/Moscow)

Заголовки

  • Content-Type: application/json
  • X-Payouts-Event
  • X-Payouts-Event-Id
  • X-Payouts-Timestamp
  • X-Payouts-Signature (опционально): sha256=<hex>

Проверка подписи (опционально)

Алгоритм расчёта подписи

Подпись рассчитывается по алгоритму HMAC-SHA256 следующим образом:

  1. Исходные данные: берём сырое тело HTTP-запроса (raw body) в том виде, как оно было отправлено
  2. Нормализация JSON: применяем JSON minify к телу запроса (удаляем пробелы, переносы строк, табуляции)
  3. Секретный ключ: используем секрет, сгенерированный в настройках webhook
  4. Алгоритм хеширования: применяем HMAC-SHA256 к нормализованному JSON с использованием секрета
  5. Формат результата: получаем шестнадцатеричную строку и добавляем префикс sha256=
  6. Сравнение: сравниваем полученную подпись с заголовком X-Payouts-Signature с использованием безопасного сравнения строк

Пошаговый пример расчёта подписи

Рассмотрим пример с тестовым webhook'ом:

1. Исходное тело запроса (как отправлено):

{
  "event": "payout.status_changed",
  "eventId": "2f4b1b0a0c2a4d32b2b0c9d311e7e59b",
  "occurredAt": "2025-09-15T19:40:21+03:00",
  "payout": {
    "id": 123456,
    "externalId": "INV-2025-0001",
    "status": "SUCCESS",
    "amount": 12345,
    "currency": "RUB"
  }
}

2. Нормализованный JSON (после minify):

{"event":"payout.status_changed","eventId":"2f4b1b0a0c2a4d32b2b0c9d311e7e59b","occurredAt":"2025-09-15T19:40:21+03:00","payout":{"id":123456,"externalId":"INV-2025-0001","status":"SUCCESS","amount":12345,"currency":"RUB"}}

3. Секретный ключ (пример):

sk_test_1234567890abcdef1234567890abcdef12345678

4. HMAC-SHA256 расчёт:

HMAC-SHA256(
  "sk_test_1234567890abcdef1234567890abcdef12345678",
  "{\"event\":\"payout.status_changed\",\"eventId\":\"2f4b1b0a0c2a4d32b2b0c9d311e7e59b\",\"occurredAt\":\"2025-09-15T19:40:21+03:00\",\"payout\":{\"id\":123456,\"externalId\":\"INV-2025-0001\",\"status\":\"SUCCESS\",\"amount\":12345,\"currency\":\"RUB\"}}"
) = "d923ed84eac76c985b045b003649c60ca6884bd1d415fcca16f9f83d1ef127a2"

5. Итоговая подпись:

sha256=d923ed84eac76c985b045b003649c60ca6884bd1d415fcca16f9f83d1ef127a2

Примеры кода для проверки подписи

PHP:

$raw = file_get_contents('php://input');
$normalized = json_encode(json_decode($raw), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
$sig = $_SERVER['HTTP_X_PAYOUTS_SIGNATURE'] ?? '';
$expected = 'sha256=' . hash_hmac('sha256', $normalized, $yourSecret);
if (!hash_equals($expected, $sig)) { http_response_code(401); exit; }

Node.js:

const crypto = require('crypto');
const rawBody = req.rawBody; // unmodified body
const normalized = JSON.stringify(JSON.parse(rawBody));
const signature = req.get('X-Payouts-Signature') || '';
const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(normalized).digest('hex');
if (!timingSafeEqual(Buffer.from(expected), Buffer.from(signature))) {
  return res.status(401).end();
}

Повторы доставки

0s → 15s → 30s → 60s → 5m → 15m → 30m → 60m → 120m → 180m до первого HTTP 2xx. Тестовая отправка — 1 попытка.

Требования к обработчику

  • Возвращать HTTP 2xx при успехе
  • Долгие операции выносить в очередь и отвечать 200 сразу
  • Таймаут ожидания ответа ~10 секунд

Идемпотентность и безопасность

  • Используйте eventId для защиты от повторной обработки
  • Требуется HTTPS; рекомендуем включить подпись

Возможности системы

Эндпоинт для получения информации о доступных функциях и ограничениях системы.

Параметры запроса

Требуемые заголовки:
Authorization: Bearer YOUR_API_TOKEN,
Accept: application/json; version=1.0.

Пример запроса

GET /api/v1/features
curl -X GET 'https://payouts-dev.quantumlabs.ru/api/v1/features' \
  -H 'Accept: application/json; version=1.0' \
  -H 'Authorization: Bearer YOUR_API_TOKEN'

Параметры ответа

Параметр Тип Обязательный Описание
system String Да Название системы ("payouts")
environment String Да Окружение (development, uat, production)
version String Да Версия API ("v1")
timestamp Integer Да Unix timestamp ответа
features Object Да Набор флагов доступности функционала (см. детальное описание ниже)
result.error String Да Код ошибки ("0" = успех)
result.message String Да Сообщение об ошибке (null при успехе)

Детальное описание объекта features

Поле Тип Обязательный Описание
single_payout Boolean Да Доступность API для одиночных выплат (всегда true для пользователей с валидным токеном)
batch_processing Boolean Да Доступность пакетной обработки выплат через файлы (всегда true)
bearer_auth Boolean Да Поддержка авторизации по Bearer токену (всегда true)
card_payouts Boolean Да Доступность выплат на банковские карты (зависит от настроек клиента и наличия client_id/client_secret)
sbp_payouts Boolean Да Доступность выплат через СБП (зависит от настроек клиента и наличия sbp_client_id/sbp_client_secret)
file_download Boolean Да Доступность скачивания файлов с результатами выплат (зависит от прав пользователя)

Пример успешного ответа

200HTTP 200 - Успешный ответ
{
  "system": "payouts",
  "environment": "production",
  "version": "v1",
  "timestamp": 1737097200,
  "features": {
    "single_payout": true,
    "batch_processing": true,
    "bearer_auth": true,
    "card_payouts": false,
    "sbp_payouts": false,
    "file_download": false
  },
  "result": { "error": "0", "message": null }
}

Пример ошибочного ответа

401HTTP 401 - UNAUTHORIZED
{
  "result": {
    "error": "UNAUTHORIZED",
    "message": "Invalid or missing Bearer token"
  }
}

Примеры интеграции

Python

Python с библиотекой requests
import requests

class PayoutsAPI:
    def __init__(self, api_token, base_url='https://payouts-dev.quantumlabs.ru/api/v1'):
        self.api_token = api_token
        self.base_url = base_url
        self.headers = {
            'Content-Type': 'application/json; charset=UTF-8',
            'Accept': 'application/json; version=1.0',
            'Authorization': f'Bearer {api_token}'
        }
    
    def create_payout(self, order_number, amount, return_url, description=None, payout_type='card'):
        data = {
            'orderNumber': order_number,
            'amount': amount,
            'urls': {'returnUrl': return_url},
            'type': payout_type
        }
        if description:
            data['description'] = description
        
        response = requests.post(f'{self.base_url}/createPayout', json=data, headers=self.headers)
        return response.json()
    
    def get_payout_status(self, order_number):
        params = {'orderNumber': order_number}
        response = requests.get(f'{self.base_url}/getPayoutStatus', params=params, headers=self.headers)
        return response.json()

# Использование
api = PayoutsAPI('your_token_here')
result = api.create_payout('ORDER_001', 100000, 'https://example.com/success')
print(result)

PHP

PHP с cURL
class PayoutsAPI {
    private $apiToken;
    private $baseUrl;
    
    public function __construct($apiToken, $baseUrl = 'https://payouts-dev.quantumlabs.ru/api/v1') {
        $this->apiToken = $apiToken;
        $this->baseUrl = $baseUrl;
    }
    
    public function createPayout($orderNumber, $amount, $returnUrl, $description = null, $type = 'card') {
        $data = [
            'orderNumber' => $orderNumber,
            'amount' => $amount,
            'urls' => ['returnUrl' => $returnUrl],
            'type' => $type
        ];
        
        if ($description) {
            $data['description'] = $description;
        }
        
        return $this->makeRequest('POST', '/createPayout', $data);
    }
    
    private function makeRequest($method, $endpoint, $data = null) {
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL => $this->baseUrl . $endpoint,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_CUSTOMREQUEST => $method,
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/json; charset=UTF-8',
                'Accept: application/json; version=1.0',
                'Authorization: Bearer ' . $this->apiToken
            ]
        ]);
        
        if ($data && $method !== 'GET') {
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        }
        
        $response = curl_exec($ch);
        curl_close($ch);
        
        return json_decode($response, true);
    }
}

// Использование
$api = new PayoutsAPI('your_token_here');
$result = $api->createPayout('ORDER_001', 100000, 'https://example.com/success');
var_dump($result);

JavaScript/Node.js

Node.js с axios
const axios = require('axios');

class PayoutsAPI {
    constructor(apiToken, baseUrl = 'https://payouts-dev.quantumlabs.ru/api/v1') {
        this.apiToken = apiToken;
        this.baseUrl = baseUrl;
        this.headers = {
            'Content-Type': 'application/json; charset=UTF-8',
            'Accept': 'application/json; version=1.0',
            'Authorization': `Bearer ${apiToken}`
        };
    }
    
    async createPayout(orderNumber, amount, returnUrl, description = null, type = 'card') {
        const data = {
            orderNumber,
            amount,
            urls: { returnUrl },
            type
        };
        
        if (description) {
            data.description = description;
        }
        
        try {
            const response = await axios.post(`${this.baseUrl}/createPayout`, data, { headers: this.headers });
            return response.data;
        } catch (error) {
            throw new Error(`API Error: ${error.response?.data || error.message}`);
        }
    }
}

// Использование
const api = new PayoutsAPI('your_token_here');
api.createPayout('ORDER_001', 100000, 'https://example.com/success')
    .then(result => console.log(result))
    .catch(error => console.error(error));

Обработка ошибок

API использует стандартные HTTP коды статуса для индикации успеха или ошибки запроса.

Коды ошибок

HTTP код Код ошибки Описание
400 VALIDATION_ERROR Ошибка валидации входных данных
401 UNAUTHORIZED Неверный или отсутствующий Bearer токен
403 PERMISSION_DENIED Недостаточно прав для выполнения операции
500 INTERNAL_ERROR Внутренняя ошибка сервера

Лучшие практики

Безопасность

  • Используйте HTTPS - никогда не отправляйте API токены по незащищенному соединению
  • Храните токены безопасно - используйте переменные окружения
  • Ротация токенов - регулярно обновляйте API токены

Производительность

  • Соблюдайте лимиты - не превышайте 30 запросов в секунду
  • Используйте таймауты - устанавливайте разумные таймауты для HTTP запросов
  • Повторные попытки - реализуйте exponential backoff для повторов

Надежность

  • Обработка ошибок - всегда проверяйте коды ответов
  • Идемпотентность - используйте уникальные orderNumber
  • Логирование - логируйте все API запросы и ответы