Вы отправляете ссылку QR-кода и сумму — мы оплачиваем её со своего шлюза и списываем эквивалент с вашего баланса в USDT. Комиссия за платёж — 0%.
POST /v1/payments со ссылкой QR.GET /v1/rate, предварительный расчёт — в
POST /v1/quote. Отдельной комиссии за платёж нет: стоимость услуги уже
заложена в курс.
API-ключ выдаёт бот @ExpressPay_robot — раздел «API для бизнеса». Ключ показывается один раз, хранится только его хеш. Ключ даёт право тратить ваш баланс, поэтому храните его как пароль и не кладите в клиентский код.
Authorization: Bearer ep_live_1a2b3c4d_xxxxxxxxxxxxxxxxxxxxxxxx
Проверить ключ:
curl https://api.exppay.net/v1/ping \
-H "Authorization: Bearer $EXPRESSPAY_KEY"
{"ok": true, "partner_id": "prt_a1b2c3d4e5f6", "mode": "live", "api_version": "1.0"}
Заголовок Idempotency-Key обязателен: по нему мы отличаем повтор запроса
от второго платежа. Сгенерируйте его сами (UUID подойдёт) и используйте один и тот же
ключ при всех повторах одного и того же платежа.
curl https://api.exppay.net/v1/payments \
-H "Authorization: Bearer $EXPRESSPAY_KEY" \
-H "Idempotency-Key: 3f1c9a2e-7b44-4c1e-9c3a-2a1f5f0d9e77" \
-H "Content-Type: application/json" \
-d '{
"qr_url": "https://qr.nspk.ru/AS1A0000000000000000000000000001",
"amount_rub": "1450.00",
"external_id": "order-4412"
}'
{
"id": "pay_9f3c1a2b4d5e",
"object": "payment",
"mode": "live",
"status": "succeeded",
"status_detail": null,
"external_id": "order-4412",
"recipient": "ООО «Ромашка»",
"amount_rub": "1450.00",
"amount_usdt": "17.330692",
"rate": "83.6666",
"currency": "RUB",
"settlement_currency": "USDT",
"created_at": "2026-09-15T10:22:31.481920+00:00",
"settled_at": "2026-09-15T10:22:48.113044+00:00",
"error": null,
"metadata": {}
}
amount_mismatch, если они разошлись. Это защищает вас от оплаты подменённого
QR-кода.
Платёж не всегда завершается мгновенно. Если в ответе status равен
processing, дождитесь вебхука или опросите статус:
curl https://api.exppay.net/v1/payments/pay_9f3c1a2b4d5e \
-H "Authorization: Bearer $EXPRESSPAY_KEY"
Источник истины — всегда GET /v1/payments/{id}. Подробнее о статусах —
в разделе Платежи.
$ch = curl_init('https://api.exppay.net/v1/payments');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('EXPRESSPAY_KEY'),
'Idempotency-Key: ' . $orderUuid,
'Content-Type: application/json',
],
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode([
'qr_url' => $qrUrl,
'amount_rub' => '1450.00',
'external_id' => $orderId,
]),
]);
$payment = json_decode(curl_exec($ch), true);
import os, uuid, httpx
r = httpx.post(
"https://api.exppay.net/v1/payments",
headers={
"Authorization": f"Bearer {os.environ['EXPRESSPAY_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={"qr_url": qr_url, "amount_rub": "1450.00", "external_id": order_id},
timeout=120,
)
payment = r.json()
if r.status_code != 200:
raise RuntimeError(payment["error"]["code"])
const res = await fetch("https://api.exppay.net/v1/payments", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.EXPRESSPAY_KEY}`,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({ qr_url: qrUrl, amount_rub: "1450.00", external_id: orderId }),
});
const payment = await res.json();
Idempotency-Key или запросите статус.
Тестовый ключ (ep_test_…) работает с теми же адресами, но платежи не уходят
в банк. Исход задаётся копейками суммы — это единственный способ проверить редкие ветки,
не рискуя деньгами:
| Сумма заканчивается на | Что произойдёт |
|---|---|
,01 | отказ, средства возвращаются на тестовый баланс |
,02 | неизвестный исход: processing, через 30 секунд — успех |
,03 | расхождение данных QR (qr_changed) |
| прочее | успех |