Как подключиться к Reptiloid P2P Gateway
Полное руководство по интеграции. От регистрации до первого платежа — без помощи поддержки.
Введение
Что такое Reptiloid P2P Gateway?
Reptiloid — это платёжный шлюз для приёма платежей через P2P-обмен. Ваши клиенты платят в рублях (переводом на карту, через СБП и другие методы), а вы получаете средства в USDT на баланс мерчанта.
Как это работает:
- Вы создаёте платёж через API — система находит трейдера
- Клиент получает реквизиты для оплаты (номер карты, СБП и т.д.)
- Клиент переводит деньги — трейдер подтверждает получение
- Вам начисляются USDT на баланс, вы получаете webhook-уведомление
Две среды работы
Система имеет две полностью изолированные среды:
Sandbox (тестовая)
Для разработки и тестирования. Тестовые ключи, тестовые платежи. Начинайте здесь.
https://sandbox.reptiloid.vgProduction (боевая)
Для реальных платежей. Боевые ключи, реальные деньги. Только после успешного тестирования.
https://reptiloid.vghttps://secure-payments.stБыстрая интеграция
REST API + HMAC-SHA256 подпись. Готовые примеры на Python, JS, PHP, curl.
Безопасность
API Key + Secret Key + подпись каждого запроса. HTTPS обязателен.
Webhook уведомления
Автоматические уведомления о статусе. 8 уровней retry. Подпись callback.
Шаг 1: Регистрация в Sandbox
Для начала работы зарегистрируйте аккаунт мерчанта в тестовой среде (Sandbox).
Откройте страницу регистрации
Перейдите по ссылке: https://sandbox.reptiloid.vg/merchant/register
Заполните форму
Укажите логин, email, название компании и пароль. Все поля обязательны.
Дождитесь одобрения
Администратор проверит заявку и активирует ваш аккаунт. В sandbox это обычно происходит быстро.
Войдите в личный кабинет
После одобрения войдите на https://sandbox.reptiloid.vg/auth с вашими данными.
Шаг 2: Получение API-ключей
Где найти ключи
После одобрения аккаунта вам будут выданы два ключа. Они доступны в личном кабинете мерчанта в разделе «Настройки» или «API».
| Ключ | Формат | Назначение |
|---|---|---|
| API Key (публичный) | pk_live_XXXXXX |
Передаётся в заголовке X-Api-Key каждого запроса |
| Secret Key (секретный) | sk_live_XXXXXX |
Используется для генерации HMAC-SHA256 подписи. Никогда не передаётся в запросах! |
| Merchant ID | merch_XXXXXX |
Ваш уникальный идентификатор в системе |
Как использовать ключи
POST /api/v1/invoice/create HTTP/1.1
Host: sandbox.reptiloid.vg
Content-Type: application/json
X-Api-Key: pk_live_ваш_api_ключ
{
"merchant_id": "merch_ваш_id",
"order_id": "order_001",
"amount": 1000,
"currency": "RUB",
"callback_url": "https://your-site.com/webhook",
"sign": "hmac_sha256_подпись"
}
• Не передавайте Secret Key в заголовках или параметрах запроса
• Не коммитьте ключи в Git-репозиторий
• Все запросы к API должны идти только с вашего бэкенда (сервер-сервер)
Шаг 3: Создание тестового платежа
Эндпоинт
POST /api/v1/invoice/create
Создаёт инвойс на оплату и возвращает ссылку для перенаправления клиента на страницу оплаты.
Параметры запроса (Body JSON)
| Параметр | Тип | Обяз. | Описание |
|---|---|---|---|
merchant_id | string | * | Ваш ID мерчанта |
order_id | string | * | Уникальный ID заказа в вашей системе |
amount | number | * | Сумма к оплате в рублях (мин. 100) |
currency | string | — | Валюта (по умолчанию «RUB») |
user_id | string | — | ID пользователя в вашей системе |
callback_url | string | * | URL для webhook уведомлений |
description | string | — | Описание платежа |
payment_method | string | — | Метод: card, sbp, sim, qr_code, mono_bank, sng_sbp, sng_card |
sign | string | * | HMAC-SHA256 подпись (см. раздел Безопасность) |
Примеры кода
curl -X POST https://sandbox.reptiloid.vg/api/v1/invoice/create \
-H "Content-Type: application/json" \
-H "X-Api-Key: pk_live_ваш_api_ключ" \
-d '{
"merchant_id": "merch_abc123",
"order_id": "order_001",
"amount": 1000,
"currency": "RUB",
"callback_url": "https://your-site.com/webhook",
"description": "Оплата заказа #001",
"sign": "вычисленная_hmac_подпись"
}'
import requests
import hmac
import hashlib
API_KEY = "pk_live_ваш_api_ключ"
SECRET_KEY = "sk_live_ваш_секретный_ключ"
BASE_URL = "https://sandbox.reptiloid.vg" # Для тестов
# === Генерация подписи ===
def generate_signature(data: dict, secret_key: str) -> str:
SIGN_FIELDS = ['merchant_id', 'order_id', 'amount', 'currency',
'user_id', 'callback_url']
sign_data = {}
for k, v in data.items():
if k not in SIGN_FIELDS or v is None:
continue
if isinstance(v, float) and v == int(v):
v = int(v)
sign_data[k] = v
sorted_params = sorted(sign_data.items())
sign_string = '&'.join(f"{k}={v}" for k, v in sorted_params)
sign_string += secret_key
return hmac.new(
secret_key.encode('utf-8'),
sign_string.encode('utf-8'),
hashlib.sha256
).hexdigest()
# === Создание платежа ===
data = {
"merchant_id": "merch_abc123",
"order_id": "order_001",
"amount": 1000,
"currency": "RUB",
"callback_url": "https://your-site.com/webhook",
"description": "Оплата заказа #001"
}
data["sign"] = generate_signature(data, SECRET_KEY)
response = requests.post(
f"{BASE_URL}/api/v1/invoice/create",
json=data,
headers={"X-Api-Key": API_KEY}
)
result = response.json()
print(result)
# Ответ:
# {
# "status": "success",
# "payment_id": "inv_20250315_A1B2C3D4",
# "payment_url": "https://sandbox.reptiloid.vg/select-operator/inv_20250315_A1B2C3D4",
# "details": {
# "original_amount": 1000,
# "total_amount": 1012, # с маркером
# "marker": 12,
# "amount_usdt": 12.97,
# "expires_at": "2025-03-15T13:30:00+00:00"
# }
# }
# Перенаправьте клиента на payment_url
print(f"Ссылка для оплаты: {result['payment_url']}")
const crypto = require('crypto');
const axios = require('axios');
const API_KEY = 'pk_live_ваш_api_ключ';
const SECRET_KEY = 'sk_live_ваш_секретный_ключ';
const BASE_URL = 'https://sandbox.reptiloid.vg'; // Для тестов
// === Генерация подписи ===
function generateSignature(data, secretKey) {
const SIGN_FIELDS = ['merchant_id', 'order_id', 'amount', 'currency',
'user_id', 'callback_url'];
const signData = {};
for (const [k, v] of Object.entries(data)) {
if (!SIGN_FIELDS.includes(k) || v === null || v === undefined) continue;
signData[k] = (typeof v === 'number' && v === Math.floor(v))
? Math.floor(v) : v;
}
const sorted = Object.entries(signData).sort(([a], [b]) => a.localeCompare(b));
let signString = sorted.map(([k, v]) => `${k}=${v}`).join('&');
signString += secretKey;
return crypto.createHmac('sha256', secretKey)
.update(signString, 'utf8')
.digest('hex');
}
// === Создание платежа ===
async function createPayment() {
const data = {
merchant_id: 'merch_abc123',
order_id: 'order_001',
amount: 1000,
currency: 'RUB',
callback_url: 'https://your-site.com/webhook',
description: 'Оплата заказа #001'
};
data.sign = generateSignature(data, SECRET_KEY);
const response = await axios.post(
`${BASE_URL}/api/v1/invoice/create`,
data,
{ headers: { 'X-Api-Key': API_KEY } }
);
console.log(response.data);
// Перенаправьте клиента на response.data.payment_url
}
createPayment();
<?php
$apiKey = 'pk_live_ваш_api_ключ';
$secretKey = 'sk_live_ваш_секретный_ключ';
$baseUrl = 'https://sandbox.reptiloid.vg'; // Для тестов
// === Генерация подписи ===
function generateSignature(array $data, string $secretKey): string {
$signFields = ['merchant_id', 'order_id', 'amount', 'currency',
'user_id', 'callback_url'];
$signData = [];
foreach ($data as $k => $v) {
if (!in_array($k, $signFields) || $v === null) continue;
if (is_float($v) && $v == intval($v)) $v = intval($v);
$signData[$k] = $v;
}
ksort($signData);
$signString = http_build_query($signData, '', '&');
$signString .= $secretKey;
return hash_hmac('sha256', $signString, $secretKey);
}
// === Создание платежа ===
$data = [
'merchant_id' => 'merch_abc123',
'order_id' => 'order_001',
'amount' => 1000,
'currency' => 'RUB',
'callback_url' => 'https://your-site.com/webhook',
'description' => 'Оплата заказа #001'
];
$data['sign'] = generateSignature($data, $secretKey);
$ch = curl_init("$baseUrl/api/v1/invoice/create");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($data),
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
"X-Api-Key: $apiKey"
],
CURLOPT_RETURNTRANSFER => true,
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
echo "Payment URL: " . $response['payment_url'];
?>
Ответ сервера
{
"status": "success",
"payment_id": "inv_20250315_A1B2C3D4",
"payment_url": "https://sandbox.reptiloid.vg/select-operator/inv_20250315_A1B2C3D4",
"details": {
"type": "waiting",
"message": "Ожидание реквизитов. Откройте страницу оплаты.",
"original_amount": 1000,
"total_amount": 1012,
"marker": 12,
"amount_usdt": 12.97,
"expires_at": "2025-03-15T13:30:00+00:00"
}
}
payment_url возвращает ссылку на домене https://secure-payments.st (отдельный домен для платёжных страниц). На Sandbox — https://sandbox.reptiloid.vg. Перенаправляйте клиента на полученный payment_url без изменений.total_amount = amount + marker. Клиент должен перевести именно total_amount.Проверка статуса платежа
GET /api/v1/invoice/status?order_id=order_001
Дополнительные параметры: merchant_id (опционально, берётся из API-ключа), sign (опционально).
# Проверка по order_id
response = requests.get(
f"{BASE_URL}/api/v1/invoice/status",
params={"order_id": "order_001"},
headers={"X-Api-Key": API_KEY}
)
# Или по payment_id
response = requests.get(
f"{BASE_URL}/api/v1/invoice/status",
params={"payment_id": "inv_20250315_A1B2C3D4"},
headers={"X-Api-Key": API_KEY}
)
Статусы платежа
| Статус | Описание |
|---|---|
waiting_requisites | Ожидание выбора метода оплаты |
pending | Ожидает оплаты клиентом |
paid | Клиент отметил оплату, ожидает подтверждения трейдера |
completed | Платёж завершён, USDT зачислен |
expired | Платёж истёк (не оплачен вовремя) |
cancelled | Платёж отменён |
disputed | Открыт спор по платежу |
failed | Ошибка при обработке платежа |
Шаг 4: Настройка Webhook
Что такое Webhook?
Webhook — это автоматическое HTTP-уведомление (POST-запрос), которое система отправляет на ваш сервер при изменении статуса платежа. Это основной способ получения информации о результате оплаты.
Как указать URL: передайте callback_url при создании платежа. На этот URL будут приходить все уведомления по данному платежу.
Какие события приходят
| Статус | Когда приходит | Дополнительные поля |
|---|---|---|
pending | Найден трейдер, клиенту показаны реквизиты | — |
paid | Клиент отметил что оплатил | paid_at |
completed | Трейдер подтвердил получение средств | Бухгалтерские данные (см. ниже) |
expired | Платёж истёк | reason, expired_at |
cancelled | Платёж отменён | reason, cancelled_at |
disputed | Открыт спор | reason, disputed_at, disputed_by |
Формат Webhook (пример для completed)
// POST на ваш callback_url
// Content-Type: application/json
// Все временные метки в московском времени (UTC+3)
{
"order_id": "DEMO_123",
"payment_id": "inv_20260320_A1B2C3D4",
"status": "completed",
"amount": 2000, // сумма запроса (= original_amount_rub)
"amount_usdt": 23.45, // общая сумма сделки (USDT)
// === Бухгалтерские данные (только для completed) ===
"original_amount_rub": 2000, // сумма, которую запросил мерчант (RUB)
"client_paid_rub": 2298, // сколько клиент фактически заплатил (RUB)
"merchant_received_usdt": 18.61, // чистая сумма мерчанту (USDT)
"merchant_received_rub": 1600, // чистая сумма мерчанту (RUB)
"commission_percent": 20, // процент комиссии
"commission_usdt": 4.84, // комиссия (USDT)
"commission_rub": 400, // комиссия (RUB)
"base_rate": 85.3, // базовый курс платформы из payout_settings (USDT/RUB)
"trader_rate": 98, // курс трейдера (USDT/RUB)
"trade_id": "trd_abc12345",
"completed_at": "2026-03-20T07:12:01+03:00",
"timestamp": "2026-03-20T07:12:01+03:00",
"sign": "a1b2c3d4e5f6..."
}
original_amount_rub, client_paid_rub, merchant_received_*, commission_*, base_rate, trader_rate) присутствуют только в статусе completed• Все временные метки в московском времени (UTC+3)
•
amount = original_amount_rub — сумма, запрошенная мерчантом•
client_paid_rub — фактическая сумма от клиента (включая маркер)•
base_rate — базовый курс платформы из payout_settings (Rapira)•
trader_rate — курс трейдера, по которому клиент фактически платит
Обработка Webhook (пример)
import hmac, hashlib
from flask import Flask, request, jsonify
app = Flask(__name__)
SECRET_KEY = "sk_live_ваш_секретный_ключ"
def verify_webhook(payload: dict, secret_key: str) -> bool:
"""Проверка HMAC-подписи webhook"""
SIGN_FIELDS = ['order_id', 'payment_id', 'status',
'amount', 'amount_usdt', 'timestamp']
provided_sign = payload.get("sign", "")
sign_data = {}
for k, v in payload.items():
if k not in SIGN_FIELDS or k == 'sign' or v is None:
continue
if isinstance(v, float) and v == int(v):
v = int(v)
sign_data[k] = v
sorted_params = sorted(sign_data.items())
sign_string = '&'.join(f"{k}={v}" for k, v in sorted_params)
sign_string += secret_key
expected_sign = hmac.new(
secret_key.encode('utf-8'),
sign_string.encode('utf-8'),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected_sign, provided_sign)
@app.route('/webhook', methods=['POST'])
def handle_webhook():
payload = request.json
# 1. Проверяем подпись
if not verify_webhook(payload, SECRET_KEY):
return jsonify({"status": "error"}), 403
# 2. Обрабатываем статус
status = payload["status"]
order_id = payload["order_id"]
if status == "completed":
amount = payload["amount"]
amount_usdt = payload["amount_usdt"]
# Зачислить средства пользователю
print(f"Заказ {order_id} оплачен: {amount} RUB / {amount_usdt} USDT")
# credit_user(order_id, amount)
elif status == "expired":
print(f"Заказ {order_id} истёк")
elif status == "cancelled":
print(f"Заказ {order_id} отменён")
# 3. Обязательно вернуть {"status": "ok"} и HTTP 200
return jsonify({"status": "ok"})
const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.json());
const SECRET_KEY = 'sk_live_ваш_секретный_ключ';
function verifyWebhook(payload, secretKey) {
const SIGN_FIELDS = ['order_id', 'payment_id', 'status',
'amount', 'amount_usdt', 'timestamp'];
const providedSign = payload.sign || '';
const signData = {};
for (const [k, v] of Object.entries(payload)) {
if (!SIGN_FIELDS.includes(k) || k === 'sign' || v == null) continue;
signData[k] = (typeof v === 'number' && v === Math.floor(v))
? Math.floor(v) : v;
}
const sorted = Object.entries(signData).sort(([a], [b]) => a.localeCompare(b));
let signString = sorted.map(([k, v]) => `${k}=${v}`).join('&');
signString += secretKey;
const expectedSign = crypto.createHmac('sha256', secretKey)
.update(signString, 'utf8')
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expectedSign), Buffer.from(providedSign)
);
}
app.post('/webhook', (req, res) => {
const payload = req.body;
if (!verifyWebhook(payload, SECRET_KEY)) {
return res.status(403).json({ status: 'error' });
}
if (payload.status === 'completed') {
console.log(`Заказ ${payload.order_id} оплачен: ${payload.amount} RUB`);
// creditUser(payload.order_id, payload.amount);
}
res.json({ status: 'ok' });
});
app.listen(3000);
<?php
$secretKey = 'sk_live_ваш_секретный_ключ';
$payload = json_decode(file_get_contents('php://input'), true);
// Проверка подписи
$signFields = ['order_id', 'payment_id', 'status',
'amount', 'amount_usdt', 'timestamp'];
$signData = [];
foreach ($payload as $k => $v) {
if (!in_array($k, $signFields) || $k === 'sign' || $v === null) continue;
if (is_float($v) && $v == intval($v)) $v = intval($v);
$signData[$k] = $v;
}
ksort($signData);
$signString = http_build_query($signData, '', '&') . $secretKey;
$expectedSign = hash_hmac('sha256', $signString, $secretKey);
if (!hash_equals($expectedSign, $payload['sign'] ?? '')) {
http_response_code(403);
echo json_encode(['status' => 'error']);
exit;
}
// Обработка
if ($payload['status'] === 'completed') {
// Зачислить средства
error_log("Заказ {$payload['order_id']} оплачен: {$payload['amount']} RUB");
}
echo json_encode(['status' => 'ok']);
?>
Политика повторных попыток
Ваш сервер должен вернуть HTTP 200 с {"status": "ok"}. Если ответ не получен, система повторяет отправку:
| Попытка | Задержка |
|---|---|
| 1 | 1 минута |
| 2 | 5 минут |
| 3 | 15 минут |
| 4 | 1 час |
| 5 | 2 часа |
| 6 | 4 часа |
| 7 | 12 часов |
| 8 (последняя) | 24 часа |
GET /api/v1/invoice/status в качестве fallback.Дополнительные эндпоинты
Список способов оплаты
GET /api/v1/invoice/payment-methods
Возвращает список доступных способов оплаты для вашего мерчанта. Список зависит от настроенных комиссий и активных методов.
curl -X GET "https://sandbox.reptiloid.vg/api/v1/invoice/payment-methods" \ -H "X-Api-Key: pk_test_ваш_ключ"
Пример ответа:
{
"status": "success",
"payment_methods": [
{"id": "card", "name": "Банковская карта", "description": "Visa/MasterCard/МИР"},
{"id": "sbp", "name": "СБП", "description": "Система быстрых платежей"},
{"id": "qiwi", "name": "QIWI", "description": "QIWI Кошелёк"},
{"id": "yoomoney", "name": "ЮMoney", "description": "ЮMoney кошелёк"},
{"id": "mobile", "name": "Мобильный банк", "description": "Перевод через приложение банка"},
{"id": "sim", "name": "Мобильный счёт", "description": "Пополнение SIM"},
{"id": "mono_bank", "name": "Monobank", "description": "Украина"},
{"id": "sng_sbp", "name": "СБП СНГ", "description": "Казахстан, Беларусь"},
{"id": "sng_card", "name": "Карта СНГ", "description": "Банки СНГ"},
{"id": "qr_code", "name": "QR-код", "description": "Сканирование QR"}
]
}
Список транзакций
GET /api/v1/invoice/transactions
Получить список всех транзакций мерчанта с фильтрацией и пагинацией.
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
status | string | — | Фильтр по статусу (created, pending, paid, completed, expired, cancelled, failed) |
limit | int | 50 | Количество записей (макс. 50) |
offset | int | 0 | Смещение для пагинации |
curl -X GET "https://sandbox.reptiloid.vg/api/v1/invoice/transactions?status=completed&limit=10&offset=0" \ -H "X-Api-Key: pk_test_ваш_ключ"
Пример ответа:
{
"status": "success",
"data": {
"transactions": [
{
"id": "inv_20260320_A1B2C3D4",
"external_order_id": "order_001",
"status": "completed",
"original_amount_rub": 2000,
"amount_rub": 2000,
"amount_usdt": 23.45,
"created_at": "2026-03-20T07:00:00+00:00",
"paid_at": "2026-03-20T07:05:00+00:00"
}
],
"total": 1,
"limit": 10,
"offset": 0
}
}
Статистика мерчанта
GET /api/v1/invoice/stats
Статистика по транзакциям за выбранный период. Включает объёмы, конверсию и информацию о rate limits.
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
period | string | today | Период: today, week или month |
curl -X GET "https://sandbox.reptiloid.vg/api/v1/invoice/stats?period=week" \ -H "X-Api-Key: pk_test_ваш_ключ"
Пример ответа:
{
"status": "success",
"data": {
"period": "week",
"period_start": "2026-03-13T00:00:00",
"summary": {
"total_invoices": 150,
"paid": 120,
"pending": 10,
"failed": 20
},
"volume": {
"total_rub": 500000.00,
"total_usdt": 5882.35,
"average_amount_rub": 4166.67
},
"conversion_rate": 80.0,
"rate_limits": {
"create": {"limit": 30, "remaining": 28, "reset_in": 45},
"status": {"limit": 60, "remaining": 58, "reset_in": 45},
"transactions": {"limit": 30, "remaining": 30, "reset_in": 60}
}
}
}
White-Label API
Что такое White-Label?
White-Label API позволяет мерчанту отображать весь процесс оплаты на своём собственном сайте, без перенаправления клиента на платёжную страницу Reptiloid. Мерчант получает список операторов (трейдеров), показывает их клиенту, принимает выбор и отображает реквизиты — всё в своём интерфейсе.
POST /create как обычно2. Запрашиваете список операторов через
GET /{invoice_id}/operators3. Клиент выбирает оператора — вызываете
POST /{invoice_id}/select-operator4. Показываете клиенту реквизиты для оплаты
5. Клиент оплатил — вызываете
POST /{invoice_id}/mark-paid6. Ожидаете webhook о подтверждении
Получить список операторов
GET /api/v1/invoice/{invoice_id}/operators
Возвращает список доступных операторов (трейдеров) для данного инвойса. Мерчант отображает этот список на своём сайте.
curl -X GET "https://sandbox.reptiloid.vg/api/v1/invoice/{invoice_id}/operators" \
-H "X-Api-Key: pk_test_ваш_ключ"
Пример ответа:
{
"status": "success",
"invoice_id": "inv_20260320_A1B2C3D4",
"amount_rub": 2000,
"exchange_rate": 85.3,
"operators": [
{
"trader_id": "trd_001",
"nickname": "Трейдер",
"rating": 100,
"payment_methods": ["card", "sbp"],
"avg_response_time": 120
}
]
}
Выбрать оператора
POST /api/v1/invoice/{invoice_id}/select-operator
Клиент выбрал оператора — мерчант отправляет этот запрос и получает реквизиты для оплаты, которые показывает клиенту на своём сайте.
Параметры тела запроса (JSON):
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
trader_id | string | Да | ID оператора из списка |
payment_method | string | Да | Выбранный метод оплаты (card, sbp и т.д.) |
curl -X POST "https://sandbox.reptiloid.vg/api/v1/invoice/{invoice_id}/select-operator" \
-H "X-Api-Key: pk_test_ваш_ключ" \
-H "Content-Type: application/json" \
-d '{
"trader_id": "trd_001",
"payment_method": "card"
}'
Пример ответа:
{
"status": "success",
"trade_id": "trd_abc12345",
"operator": {
"nickname": "Трейдер",
"rating": 100
},
"payment": {
"method": "card",
"amount": 2000,
"requisites": {
"type": "card",
"bank": "Сбербанк",
"number": "2200 **** **** 1234",
"holder": "IVAN PETROV"
}
},
"expires_at": "2026-03-20T07:30:00+00:00",
"time_limit_minutes": 30
}
Отметить оплату
POST /api/v1/invoice/{invoice_id}/mark-paid
Клиент нажал «Я оплатил» на вашем сайте — отправьте этот запрос, чтобы уведомить трейдера. После этого ожидайте webhook с подтверждением (completed) или спором (disputed).
curl -X POST "https://sandbox.reptiloid.vg/api/v1/invoice/{invoice_id}/mark-paid" \
-H "X-Api-Key: pk_test_ваш_ключ"
Пример ответа:
{
"status": "success",
"message": "Payment marked as paid"
}
Чат по сделке
Мерчант может читать и отправлять сообщения в чат сделки (например, при спорах или уточнениях).
Получить сообщения
GET /api/v1/invoice/{invoice_id}/messages
curl -X GET "https://sandbox.reptiloid.vg/api/v1/invoice/{invoice_id}/messages" \
-H "X-Api-Key: pk_test_ваш_ключ"
Отправить сообщение
POST /api/v1/invoice/{invoice_id}/messages
curl -X POST "https://sandbox.reptiloid.vg/api/v1/invoice/{invoice_id}/messages" \
-H "X-Api-Key: pk_test_ваш_ключ" \
-H "Content-Type: application/json" \
-d '{"message": "Клиент оплатил, проверьте пожалуйста"}'
Управление спорами
Что такое спор?
Спор (dispute) открывается когда одна из сторон считает, что оплата не была выполнена корректно. Мерчант может открывать споры и общаться с администрацией через API.
Список споров
GET /api/v1/invoice/disputes
Получить все сделки мерчанта со статусом спора. Можно фильтровать по статусу.
| Параметр | Тип | Описание |
|---|---|---|
status | string | Фильтр: disputed, completed, cancelled. Без фильтра — все три. |
curl -X GET "https://sandbox.reptiloid.vg/api/v1/invoice/disputes?status=disputed" \ -H "X-Api-Key: pk_test_ваш_ключ"
Пример ответа:
{
"status": "success",
"data": [
{
"trade_id": "trd_abc12345",
"payment_id": "inv_20260320_A1B2C3D4",
"order_id": "order_001",
"status": "disputed",
"amount_rub": 2000,
"client_amount_rub": 2298,
"amount_usdt": 23.45,
"disputed_at": "2026-03-20T08:00:00+00:00",
"disputed_by": "merchant:m_001",
"dispute_reason": "Клиент оплатил, но трейдер не подтверждает",
"dispute_resolved_at": null,
"dispute_resolution": null,
"created_at": "2026-03-20T07:00:00+00:00"
}
],
"total": 1
}
Открыть спор
POST /api/v1/invoice/dispute/open
Открыть спор по сделке. Можно указать trade_id, payment_id или order_id для идентификации. Спор можно открыть только по сделкам в статусе paid или pending.
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
trade_id | string | Одно из трёх | ID сделки |
payment_id | string | Одно из трёх | ID платежа (инвойса) |
order_id | string | Одно из трёх | Внешний ID заказа мерчанта |
reason | string | Нет | Причина открытия спора |
curl -X POST "https://sandbox.reptiloid.vg/api/v1/invoice/dispute/open" \
-H "X-Api-Key: pk_test_ваш_ключ" \
-H "Content-Type: application/json" \
-d '{
"order_id": "order_001",
"reason": "Клиент оплатил, но трейдер не подтверждает"
}'
Пример ответа:
{
"status": "success",
"data": {
"trade_id": "trd_abc12345",
"status": "disputed",
"reason": "Клиент оплатил, но трейдер не подтверждает",
"disputed_at": "2026-03-20T08:00:00+00:00"
}
}
Сообщения в споре
GET /api/v1/invoice/dispute/messages
Получить все сообщения чата по спору. Идентификация через trade_id, payment_id или order_id.
curl -X GET "https://sandbox.reptiloid.vg/api/v1/invoice/dispute/messages?order_id=order_001" \ -H "X-Api-Key: pk_test_ваш_ключ"
Пример ответа:
{
"status": "success",
"data": {
"trade_id": "trd_abc12345",
"trade_status": "disputed",
"messages": [
{
"id": "msg_001",
"sender_type": "system",
"sender_id": "system",
"content": "Спор открыт мерчантом! Причина: ...",
"created_at": "2026-03-20T08:00:00+00:00"
},
{
"id": "msg_002",
"sender_type": "merchant",
"sender_id": "merchant:m_001",
"content": "Клиент предоставил чек оплаты",
"created_at": "2026-03-20T08:01:00+00:00"
}
],
"total": 2
}
}
Отправить сообщение в спор
POST /api/v1/invoice/dispute/message
Отправить сообщение в чат спора. Доступно для сделок в статусе disputed, paid или completed.
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
trade_id / payment_id / order_id | string | Одно из трёх | Идентификатор сделки |
message | string | Да | Текст сообщения |
curl -X POST "https://sandbox.reptiloid.vg/api/v1/invoice/dispute/message" \
-H "X-Api-Key: pk_test_ваш_ключ" \
-H "Content-Type: application/json" \
-d '{
"order_id": "order_001",
"message": "Прикрепляю скриншот оплаты от клиента"
}'
Пример ответа:
{
"status": "success",
"data": {
"message_id": "msg_003",
"trade_id": "trd_abc12345",
"created_at": "2026-03-20T08:05:00+00:00"
}
}
Rate Limits
Ограничения на количество запросов
Все API-эндпоинты имеют ограничения на количество запросов в минуту (per merchant). При превышении лимита возвращается ошибка 429 RATE_LIMIT_EXCEEDED с указанием времени до сброса.
| Эндпоинт | Лимит (в минуту) |
|---|---|
POST /create | 30 запросов |
GET /status | 60 запросов |
GET /transactions | 30 запросов |
| Остальные эндпоинты | 60 запросов |
HTTP 429{"status": "error", "code": "RATE_LIMIT_EXCEEDED", "message": "Превышен лимит запросов. Повторите через N сек."}
GET /stats — поле rate_limits.Шаг 5: Полное тестирование
Чек-лист тестирования
Перед переходом в Production вы обязаны протестировать все сценарии в Sandbox:
- Создание платежа — вызовите
POST /create, убедитесь что получаетеpayment_url - Проверка статуса — вызовите
GET /status, убедитесь что получаете актуальный статус - Получение webhook — убедитесь что ваш сервер получает POST-запрос на
callback_url - Проверка подписи — убедитесь что
signв webhook проходит верификацию на вашей стороне - Корректность данных — проверьте что
order_id,amount,statusсовпадают с ожидаемыми - Обработка expired — проверьте как ваша система реагирует на истёкший платёж
- Обработка cancelled — проверьте отмену платежа
- Обработка disputed — проверьте открытие спора
- Дублирование webhook — убедитесь что повторный webhook не приводит к двойному зачислению
Демо-магазин
🏫 Демонстрационный магазин
Демо-магазин — это готовый интерактивный пример интеграции с Reptiloid Invoice API. Он позволяет вам пройти весь процесс приёма платежа — от подключения API-ключей до получения webhook-уведомления — прямо в браузере, без написания кода.
Это лучший способ понять, как работает система, прежде чем писать собственную интеграцию. Демо-магазин доступен только в Sandbox-среде.
Что демонстрирует демо-магазин
Демо-магазин наглядно показывает каждый этап интеграции с полной прозрачностью — вы видите все API-запросы, ответы, подписи и webhook-уведомления в реальном времени.
Подключение к API
Введите свои API Key, Secret Key и Merchant ID — система проверит подключение и покажет доступные методы оплаты.
Создание платежа
Укажите сумму, демо-магазин сгенерирует HMAC-подпись, отправит запрос к Invoice API и покажет полный запрос/ответ в API-логе.
HMAC-подпись
Детальный разбор процесса подписи: какие поля берутся, как формируется строка, какой результат — всё прозрачно.
Страница оплаты
Клиент переходит на payment_url, выбирает метод оплаты, получает реквизиты и оплачивает. Полный цикл оплаты.
Webhook-уведомления
Все webhook-и отображаются в реальном времени с полным payload, статусом, подписью и бухгалтерскими данными.
Баланс и история
Отслеживайте баланс мерчанта (RUB и USDT), историю всех платежей и их статусы в одном интерфейсе.
Как пользоваться демо-магазином
Откройте демо-магазин
Перейдите на sandbox.reptiloid.vg/demo
Введите API-ключи
Вставьте ваши тестовые API Key (pk_live_...), Secret Key (sk_live_...) и Merchant ID. Эти ключи доступны в личном кабинете мерчанта в разделе «API Интеграция».
Подключитесь
Нажмите «Подключиться» — система проверит ваши ключи и установит соединение. В API-логе вы увидите запрос и ответ.
Создайте тестовый платёж
Введите сумму (мин. 100 ₽) и нажмите «Создать платёж». В API-логе отобразится: генерация HMAC-подписи, POST-запрос к /api/v1/invoice/create и ответ с payment_url.
Оплатите (как клиент)
Откроется страница оплаты. Выберите метод, получите реквизиты трейдера и совершите перевод. Отметьте оплату.
Наблюдайте результат
После подтверждения трейдером в разделе «Webhook» появится уведомление со статусом completed, бухгалтерскими данными (комиссия, курс, чистая сумма) и подписью. Баланс обновится автоматически.
Что показывает API-лог
Каждое действие в демо-магазине отображается в API-логе в реальном времени:
| Тип записи | Цвет | Что показывает |
|---|---|---|
| REQUEST | Синий | Исходящий HTTP-запрос (метод, URL, заголовки, тело) |
| SIGNATURE | Жёлтый | Процесс генерации HMAC-SHA256 подписи (поля, строка, результат) |
| RESPONSE | Зелёный / Красный | Ответ сервера (HTTP-код, данные). Зелёный для 2xx, красный для ошибок. |
Каждую запись можно развернуть кликом, чтобы увидеть полные данные: заголовки, тело запроса и полный ответ сервера.
Типичные ошибки
Ошибки при интеграции и их решения
INVALID_API_KEY (401)
Причина: неверный или отсутствующий API ключ в заголовке X-Api-Key
Решение: проверьте что ключ скопирован полностью, без пробелов. Убедитесь что используете ключ от правильной среды (sandbox / production).
INVALID_SIGNATURE (400)
Причина: HMAC-подпись не совпадает с ожидаемой
Решение:
• Проверьте что Secret Key правильный
• Проверьте порядок полей (должны быть отсортированы по алфавиту)
• Проверьте что float значения без дробной части конвертируются в int (1000.0 → 1000)
• Проверьте что Secret Key добавляется в конец строки (без &)
Не приходит Webhook
Возможные причины:
• callback_url недоступен из интернета (проверьте файрвол)
• Сервер возвращает не HTTP 200 (проверьте логи)
• Сервер отвечает, но не {"status": "ok"} (будут retry)
• HTTPS сертификат невалидный на вашем callback URL
• Таймаут ответа (сервер думает дольше 30 секунд)
DUPLICATE_ORDER_ID (400)
Причина: заказ с таким order_id уже существует
Решение: каждый order_id должен быть уникальным. Используйте UUID или инкрементальные ID из вашей системы.
MERCHANT_MISMATCH (400)
Причина: merchant_id в теле запроса не соответствует API ключу
Решение: убедитесь что merchant_id и X-Api-Key принадлежат одному и тому же мерчанту.
INVALID_AMOUNT (400)
Причина: сумма меньше минимальной
Решение: минимальная сумма платежа — 100 RUB. Проверьте что amount ≥ 100.
Все коды ошибок API
| HTTP | Код | Описание |
|---|---|---|
| 401 | INVALID_API_KEY | Неверный API ключ |
| 400 | INVALID_SIGNATURE | Неверная HMAC подпись |
| 400 | MERCHANT_MISMATCH | Merchant ID не соответствует API ключу |
| 403 | MERCHANT_TRAFFIC_DISABLED | Трафик мерчанта отключён |
| 400 | DUPLICATE_ORDER_ID | Заказ с таким order_id уже существует |
| 400 | INVALID_AMOUNT | Сумма меньше минимальной (100 RUB) |
| 400 | INVALID_PAYMENT_METHOD | Недопустимый метод оплаты |
| 400 | MISSING_IDENTIFIER | Не указан order_id или payment_id |
| 404 | NOT_FOUND | Платёж не найден |
| 400 | ALREADY_DISPUTED | Спор уже открыт |
| 429 | RATE_LIMIT_EXCEEDED | Превышен лимит запросов |
| 404 | TRADE_NOT_FOUND | Сделка не найдена или не принадлежит мерчанту |
| 400 | INVALID_STATUS | Невозможно выполнить операцию при текущем статусе |
| 400 | EMPTY_MESSAGE | Сообщение не может быть пустым |
| 400 | CANNOT_MESSAGE | Нельзя отправить сообщение при текущем статусе сделки |
| 400 | INVALID_CALLBACK_URL | Недопустимый формат callback URL |
Безопасность
Проверка HMAC-подписи
Каждый запрос к API и каждый входящий webhook подписаны HMAC-SHA256. Это гарантирует что запрос не был подделан.
Алгоритм создания подписи для запросов:
Берём поля для подписи
merchant_id, order_id, amount, currency, user_id, callback_url
Убираем null-значения
Поля со значением null или undefined исключаются
Сортируем по ключу (алфавит)
Результат: amount=1000&callback_url=...¤cy=RUB&merchant_id=...&order_id=...
Добавляем Secret Key в конец
...&order_id=order_001sk_live_ваш_секрет (без разделителя &)
Вычисляем HMAC-SHA256
Ключ — secret_key, сообщение — полученная строка. Результат — 64-символьный hex.
Поля для подписи Webhook (входящего):
order_id, payment_id, status, amount, amount_usdt, timestamp
Правила хранения ключей
✅ Правильно
- Хранить в переменных окружения (
.env) - Использовать vault / secrets manager
- Ограничить доступ к ключам
- Ротировать ключи при утечке
❌ Неправильно
- Хардкодить в исходном коде
- Коммитить в Git-репозиторий
- Использовать на фронтенде
- Передавать в URL или логах
HTTPS рекомендуется
Все запросы к API и callback URL рекомендуется выполнять по HTTPS. Система принимает как HTTP, так и HTTPS для callback_url, однако для безопасности настоятельно рекомендуется использовать HTTPS с валидным SSL-сертификатом.
Переход в Production
Пошаговый план перехода
Завершите тестирование в Sandbox
Убедитесь что все сценарии из чек-листа (раздел 10) пройдены успешно.
Свяжитесь с администратором
Запросите перевод в Production. Администратор проверит вашу интеграцию и создаст боевой аккаунт.
Получите Production-ключи
Вам будут выданы новые pk_live_... и sk_live_... ключи для боевой среды.
Переключите Base URL
Замените в вашем коде:
// Было (sandbox): BASE_URL = "https://sandbox.reptiloid.vg" // Стало (production): BASE_URL = "https://reptiloid.vg"
Замените API-ключи
Обновите API_KEY и SECRET_KEY на production-версии.
Проведите первый реальный платёж
Сделайте тестовый платёж на минимальную сумму (100 RUB) чтобы убедиться что всё работает.
URL среды
API Base URLs
| Среда | Base URL | Пример |
|---|---|---|
| Sandbox | https://sandbox.reptiloid.vg/api/v1/invoice |
POST .../invoice/create |
| Production | https://reptiloid.vg/api/v1/invoice |
POST .../invoice/create |
Reptiloid P2P Gateway — Документация v3.0
Sandbox · Production · Docs