API Overview

Quantum Payouts provides REST API to integrate with external systems. It allows creating payouts, tracking their status and getting information about available features.

Main Capabilities

  • Create Payouts - register a payout and get a link to the recipient details page
  • Status Tracking - get current information about payout status
  • System Information - get available features and limitations
  • Secure Authorization - use Bearer tokens for authentication

Base URL

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

Data Format

  • Requests: JSON (Content-Type: application/json; charset=UTF-8)
  • Responses: JSON (Accept: application/json; version=1.0)
  • Encoding: UTF-8
  • Amounts: in kopecks (e.g., 150000 = 1500.00 rubles)

Authentication

All API requests require authorization using Bearer tokens.

Getting an API Token

  1. Log into your account
  2. Go to Settings → API
  3. Click "Create API Token"
  4. Copy the generated token
  5. Store the token securely

Using the Token

HTTP Header
Authorization: Bearer YOUR_API_TOKEN

⚠️ Security: Never pass API tokens in URL parameters or in unprotected form. Use only HTTPS connections.

Create Payout

Endpoint for registering a new payout and getting a link to the recipient details page.

Request Parameters

Required headers:
Authorization: Bearer YOUR_API_TOKEN,
Accept: application/json; version=1.0,
Content-Type: application/json; charset=UTF-8.

Parameter Type Required Description
orderNumber String Yes Unique payout identifier (up to 36 characters)
amount Integer Yes Amount in kopecks (up to 12 digits)
urls Object Yes Container for redirect URLs
urls.returnUrl String Yes URL for redirect on success
urls.failUrl String No URL for redirect on error
description String No Payout description
sessionTimeoutSecs Integer No Session lifetime in seconds (default 600)
type String No Payout type: "card" or "sbp" or don't send it (none)

Example Request

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": "Payout for order #12345",
    "sessionTimeoutSecs": 1800,
    "type": "card",
    "urls": {
      "returnUrl": "https://your-site.com/success",
      "failUrl": "https://your-site.com/fail"
    }
  }'

Response Parameters

Parameter Type Description
result Object Request status block
result.error String Error code ("0" = success)
result.message String Error message (null on success)
payoutUrl String Link to the recipient details page
orderId String Internal order identifier
orderNumber String Order number from the request

Example Success Response

200HTTP 200 - Success Response
{
  "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"
}

Example Error Response

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

Payout Lifecycle

  1. Registration - API creates payout with status uploaded
  2. Details Entry - user goes to payoutUrl to enter recipient details
  3. Processing - status changes to created, then processing
  4. Completion - final status success, failed, or cancelled

Perform Single Payout

Endpoint to immediately execute a single payout to a card. The request both registers the payout and submits it to the bank in one call.

Request Parameters

Required headers:
Authorization: Bearer YOUR_API_TOKEN,
Accept: application/json; version=1.0,
Content-Type: application/json; charset=UTF-8.

Parameter Type Required Description
orderNumber String Yes Unique payout identifier (up to 32 chars). Idempotency per (user, orderNumber).
amount Integer Yes Amount in kopecks (up to 12 digits). Example: 150000 = 1500.00 RUB
description String Yes Operation description (up to ~600 chars)
target Object Yes Recipient details container
target.pan String Yes Recipient card number (13–19 digits)

Example Request

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": "One-time payout",
    "target": { "pan": "4111111111111111" }
  }'

Response Parameters

Parameter Type Description
result Object Request status block
result.error String Error code ("0" = success)
result.message String Error message (null on success)
target Object No Recipient info (when present)
target.maskedPan String Yes Masked card number
orderNumber String Order identifier
orderStatus String Order status (created, processing, completed, failed)
amount Integer Amount in kopecks
creationDate Integer Creation Unix timestamp
orderId String Bank order code (if available)

Example Success Response

200HTTP 200 - Success
{
  "result": { "error": "0", "message": null },
  "orderNumber": "ORDER_12345",
  "orderStatus": "processing",
  "amount": 150000,
  "creationDate": 1737097200,
  "orderId": "BANK_ORDER_CODE_OPTIONAL",
  "target": { "maskedPan": "411111******1111" }
}

Example Error Response

400HTTP 400 - VALIDATION_ERROR
{
  "result": {
    "error": "VALIDATION_ERROR",
    "message": "orderNumber is required; amount must be greater than 0"
  }
}
  • Repeated call with the same orderNumber is idempotent (no re-submission to the bank).
  • Requires configured Client ID/Secret and permission for card payouts.

Get Payout Status

Endpoint for getting current information about payout status.

Request Parameters

Required headers:
Authorization: Bearer YOUR_API_TOKEN,
Accept: application/json; version=1.0,
Content-Type: application/json; charset=UTF-8.

Parameter Type Required Description
orderNumber String Yes Payout identifier (up to 32 chars)

Example Request

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"
  }'

Response Parameters

Parameter Type Required Description
result Object Yes Request status block
result.error String Yes Error code ("0" = success)
result.message String Yes Error message (null on success)
orderNumber String Yes Order identifier
orderStatus String Yes Order status (created, processing, completed, failed)
amount Integer Yes Amount in kopecks
creationDate Integer Yes Creation Unix timestamp
orderId String Yes Bank order code (if available)
target Object No Recipient info (when present)
target.maskedPan String Yes Masked card number (for card payouts)
target.maskedPhone String No Masked phone number (for SBP payouts)

Response

200HTTP 200 - Success Response
{
  "result": {
    "error": "0",
    "message": null
  },
  "orderStatus": "success",
  "orderNumber": "ORDER_12345",
  "amount": 150000,
  "currency": "RUB"
}

Webhook

Static webhook for event notifications (e.g., payout status changes). Configure it in Dashboard → Settings → Webhook.

Payload format

{
  "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 — integer minor units (kopecks)
  • occurredAt — ISO8601 (Europe/Moscow)

Headers

  • Content-Type: application/json
  • X-Payouts-Event
  • X-Payouts-Event-Id
  • X-Payouts-Timestamp
  • X-Payouts-Signature (optional): sha256=<hex>

Signature verification (optional)

Signature calculation algorithm

The signature is calculated using HMAC-SHA256 algorithm as follows:

  1. Source data: take the raw HTTP request body exactly as it was sent
  2. JSON normalization: apply JSON minify to the request body (remove spaces, line breaks, tabs)
  3. Secret key: use the secret generated in webhook settings
  4. Hashing algorithm: apply HMAC-SHA256 to the normalized JSON using the secret
  5. Result format: get a hexadecimal string and add the sha256= prefix
  6. Comparison: compare the resulting signature with the X-Payouts-Signature header using secure string comparison

Step-by-step signature calculation example

Let's consider an example with a test webhook:

1. Original request body (as sent):

{
  "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. Normalized JSON (after 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. Secret key (example):

sk_test_1234567890abcdef1234567890abcdef12345678

4. HMAC-SHA256 calculation:

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. Final signature:

sha256=d923ed84eac76c985b045b003649c60ca6884bd1d415fcca16f9f83d1ef127a2

Code examples for signature verification

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();
}

Retry policy

0s → 15s → 30s → 60s → 5m → 15m → 30m → 60m → 120m → 180m until the first HTTP 2xx. Test delivery uses a single attempt.

Receiver requirements

  • Return HTTP 2xx on success
  • Offload heavy work to your queue and respond 200 immediately
  • Response timeout ~10 seconds

Idempotency and security

  • Use eventId to prevent reprocessing
  • HTTPS is required; signature is recommended

System Features

Endpoint for getting information about available features and system limitations.

Request Parameters

Required headers:
Authorization: Bearer YOUR_API_TOKEN,
Accept: application/json; version=1.0.

Example Request

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'

Response Parameters

Parameter Type Required Description
system String Yes System name ("payouts")
environment String Yes Environment (development, uat, production)
version String Yes API version ("v1")
timestamp Integer Yes Response Unix timestamp
features.* Object Yes Set of capability flags
result.error String Yes Error code ("0" = success)
result.message String Yes Error message (null on success)

Detailed features object description

Field Type Required Description
single_payout Boolean Yes Single payout API availability (always true for users with valid token)
batch_processing Boolean Yes Batch file processing support (always true)
bearer_auth Boolean Yes Bearer token authentication support (always true)
card_payouts Boolean Yes Card payouts availability (depends on client settings and presence of client_id/client_secret)
sbp_payouts Boolean Yes SBP payouts availability (depends on client settings and presence of sbp_client_id/sbp_client_secret)
file_download Boolean Yes File download permission for payout results (depends on user permissions)

Example Success Response

200HTTP 200 - Success Response
{
  "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 }
}

Example Error Response

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

Integration Examples

Python

Python with requests library
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()

# Usage
api = PayoutsAPI('your_token_here')
result = api.create_payout('ORDER_001', 100000, 'https://example.com/success')
print(result)

JavaScript/Node.js

Node.js with 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}`);
        }
    }
}

// Usage
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));

Error Handling

API uses standard HTTP status codes to indicate success or failure of requests.

Error Codes

HTTP Code Error Code Description
400 VALIDATION_ERROR Input data validation error
401 UNAUTHORIZED Invalid or missing Bearer token
403 PERMISSION_DENIED Insufficient permissions for operation
500 INTERNAL_ERROR Internal server error

Best Practices

Security

  • Use HTTPS - never send API tokens over unprotected connections
  • Store tokens securely - use environment variables
  • Token rotation - regularly update API tokens

Performance

  • Respect limits - don't exceed 30 requests per second
  • Use timeouts - set reasonable timeouts for HTTP requests
  • Retry logic - implement exponential backoff for retries

Reliability

  • Error handling - always check response codes
  • Idempotency - use unique orderNumber values
  • Logging - log all API requests and responses