Приём платежей
API позволяет создать ссылку на оплату, узнать статус платежа и получать уведомления об изменении статуса на ваш сервер. Обмен данными — JSON по HTTPS.
- 1Выпустите ключВ кабинете, раздел «Интеграция».
- 2Укажите адресаCallback, success и fail URL в разделе «Профиль».
- 3Создайте платёжОтправьте покупателя по полученной ссылке payUrl.
Авторизация
Каждый запрос подписывается парой ключей из раздела «Интеграция». Секрет показывается один раз при выпуске ключа — храните его только на сервере и не передавайте в браузер или мобильное приложение.
X-Api-Key: pk_xxxxxxxxxxxxxxxx X-Api-Secret: <секрет ключа> Content-Type: application/json
При неверных или отключённых ключах API вернёт 401 с телом {"error":"unauthorized"}.
POST /payment/create
Создаёт платёж и возвращает ссылку payUrl, на которую нужно перенаправить покупателя.
| Параметр | Тип | Обяз. | Описание |
|---|---|---|---|
| orderId | string | да | Номер заказа в вашей системе, 1–128 символов. Уникален в рамках аккаунта. |
| amount | number | string | да | Сумма в рублях, до 2 знаков после точки: 1500, "1500.50". |
| currency | string | нет | Код валюты из 3 букв. По умолчанию — валюта аккаунта. |
| description | string | нет | Описание платежа. |
| payerEmail | string | нет | E-mail покупателя. |
| successUrl | string | нет | Куда вернуть покупателя после оплаты. По умолчанию — из профиля. |
| failUrl | string | нет | Куда вернуть покупателя при неудаче. По умолчанию — из профиля. |
curl -X POST https://merchant.1processing.dad/api/v1/payment/create \
-H "X-Api-Key: pk_xxxxxxxxxxxxxxxx" \
-H "X-Api-Secret: <секрет>" \
-H "Content-Type: application/json" \
-d '{
"orderId": "order-10045",
"amount": "1500.00",
"description": "Заказ №10045"
}'{
"id": "cm3x0k2ab0001qz8l4f7d9e2a",
"orderId": "order-10045",
"status": "PENDING",
"amount": "150000",
"currency": "RUB",
"payUrl": "https://...",
"expiresAt": "2026-11-14T12:30:00.000Z",
"createdAt": "2026-11-14T12:00:00.000Z"
}- amount в ответах — строка в копейках:
"150000"= 1 500,00 ₽. - Идемпотентность. Повторный запрос с тем же
orderIdне создаёт новый платёж, а возвращает уже созданный. Безопасно повторять запрос при сетевых ошибках. - Таймаут. Формирование ссылки может занимать время — выставляйте таймаут HTTP-клиента не менее 180 секунд.
- Если в ответе
status: "FAILED"иpayUrl: null, ссылку выдать не удалось. Создайте новый платёж с другимorderId. - Сумма одного платежа ограничена лимитом аккаунта. При превышении вернётся ошибка 400.
GET /payment/status
Возвращает актуальный статус платежа. Укажите один из параметров:
| Параметр | Тип | Обяз. | Описание |
|---|---|---|---|
| orderId | string | * | Ваш номер заказа, переданный при создании. |
| id | string | * | Идентификатор платежа из ответа на создание. |
curl "https://merchant.1processing.dad/api/v1/payment/status?orderId=order-10045" \ -H "X-Api-Key: pk_xxxxxxxxxxxxxxxx" \ -H "X-Api-Secret: <секрет>"
{
"id": "cm3x0k2ab0001qz8l4f7d9e2a",
"orderId": "order-10045",
"status": "PAID",
"amount": "150000",
"currency": "RUB",
"payUrl": "https://...",
"paidAt": "2026-11-14T12:04:31.000Z",
"expiresAt": "2026-11-14T12:30:00.000Z",
"createdAt": "2026-11-14T12:00:00.000Z"
}Статусы платежа
PENDINGСсылка выдана, ожидаем оплатупромежуточныйPAIDПлатёж успешно оплаченфинальныйFAILEDПлатёж не прошёл или ссылку выдать не удалосьфинальныйEXPIREDИстёк срок жизни ссылки, оплата не поступилафинальныйCANCELLEDПлатёж отменёнфинальныйREFUNDEDСредства возвращены покупателюфинальный- Финальный статус больше не меняется — опрос можно прекращать.
- Рекомендуем полагаться на вебхуки, а опрос использовать как резерв — не чаще одного раза в 10–15 секунд на платёж.
Вебхуки
Когда платёж переходит в финальный статус, мы отправляем POST на Callback URL, указанный в разделе «Профиль» личного кабинета.
payment.paidПлатёж оплаченpayment.failedПлатёж не прошёлpayment.expiredИстёк срок оплатыpayment.cancelledПлатёж отменёнpayment.refundedВозврат средствContent-Type: application/json User-Agent: 1Processing-Webhook/1 X-Webhook-Id: <идентификатор уведомления> X-Webhook-Event: payment.paid X-Webhook-Signature: sha256=<hex>
{
"event": "payment.paid",
"transactionId": "cm3x0k2ab0001qz8l4f7d9e2a",
"orderId": "order-10045",
"status": "PAID",
"amount": "150000",
"currency": "RUB",
"paidAt": "2026-11-14T12:04:31.000Z",
"createdAt": "2026-11-14T12:00:00.000Z"
}- Ответ. Верните любой код
2xxв течение 15 секунд. Иначе доставка считается неуспешной. - Повторы. До 8 попыток с нарастающими интервалами: 10 с, 30 с, 2 мин, 5 мин, 15 мин, 1 ч, 3 ч.
- Дубли. При повторах
X-Webhook-Idне меняется. Обрабатывайте уведомления идемпотентно — по пареtransactionId+event. - Платёж, созданный сразу со статусом
FAILED, уведомление не порождает.
Проверка подписи
Подпись — HMAC-SHA256 от сырого тела запроса с секретом подписи из раздела «Профиль». Считайте подпись до разбора JSON и сравнивайте в постоянном времени.
import crypto from "node:crypto";
import express from "express";
const SECRET = process.env.WEBHOOK_SECRET; // whsec_...
const app = express();
app.post("/payments/notify", express.raw({ type: "application/json" }), (req, res) => {
const expected = "sha256=" + crypto.createHmac("sha256", SECRET).update(req.body).digest("hex");
const got = req.get("X-Webhook-Signature") || "";
const ok = got.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(got), Buffer.from(expected));
if (!ok) return res.status(401).end();
const event = JSON.parse(req.body.toString("utf8"));
// обработайте event.orderId / event.status
res.status(200).end();
});<?php
$secret = getenv('WEBHOOK_SECRET');
$body = file_get_contents('php://input');
$expected = 'sha256=' . hash_hmac('sha256', $body, $secret);
$got = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
if (!hash_equals($expected, $got)) {
http_response_code(401);
exit;
}
$event = json_decode($body, true);
// обработайте $event['orderId'] / $event['status']
http_response_code(200);import hmac, hashlib, os
from flask import Flask, request, abort
SECRET = os.environ["WEBHOOK_SECRET"].encode()
app = Flask(__name__)
@app.post("/payments/notify")
def notify():
body = request.get_data()
expected = "sha256=" + hmac.new(SECRET, body, hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, request.headers.get("X-Webhook-Signature", "")):
abort(401)
event = request.get_json()
# обработайте event["orderId"] / event["status"]
return "", 200Ошибки
При ошибке API возвращает JSON вида {"error": "описание"}.
400Неверные параметры запроса или превышен лимит суммы401Не переданы или неверны ключи, ключ отключён404Платёж не найден5xxВременная ошибка — повторите запрос с тем же orderId