Developer API
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
- Log into your account
- Go to Settings → API
- Click "Create API Token"
- Copy the generated token
- Store the token securely
Using the Token
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
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
{
"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
{
"result": {
"error": "VALIDATION_ERROR",
"message": "urls.returnUrl is required; amount must be positive"
}
}
Payout Lifecycle
- Registration - API creates payout with status
uploaded
- Details Entry - user goes to
payoutUrl
to enter recipient details - Processing - status changes to
created
, thenprocessing
- Completion - final status
success
,failed
, orcancelled
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
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
{
"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
{
"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
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
{
"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:
- Source data: take the raw HTTP request body exactly as it was sent
- JSON normalization: apply JSON minify to the request body (remove spaces, line breaks, tabs)
- Secret key: use the secret generated in webhook settings
- Hashing algorithm: apply HMAC-SHA256 to the normalized JSON using the secret
- Result format: get a hexadecimal string and add the
sha256=
prefix - 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
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
{
"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
{
"result": {
"error": "UNAUTHORIZED",
"message": "Invalid or missing Bearer token"
}
}
Integration Examples
Python
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
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