protopays · API

Создание платежа

RUB collect: реквизит в data.requisite. Текущий статус можно опрашивать через GET /payments/status; финальный результат — в webhook.

POST https://api.protopays.io/api/v1/payments

Параметры тела (JSON)

Мерчант — из заголовков, не из тела. Подпись — от байт JSON ниже.

ПолеТипОбяз.Описание
orderIdstringдаВаш id заказа, до 255 (trim). Повтор с тем же `orderId` и методом — тот же платёж.
amountnumber | stringдаСумма, минимум 1. В валюте RUB; в ответе может быть строка с 2 дробными.
currencystringдаСейчас: только RUB.
callbackUristring (URL)даHTTPS URL для POST webhook о смене статуса, до 2048 симв.
methodstringдаМетод RUB collect: sbp | card (как `payment_type` в других API).
payerobjectнетОпц.: метаданные плательщика. Все поля необязательны; при передаче сохраняются на платеже (в ответе create не возвращаются). userId, userIp — привязка к пользователю; type — ftd | std | trusted; payments.successful / payments.expired — неотрицательные целые.

Заголовки запроса

ПолеТипОбяз.Описание
Content-TypestringдаДолжен быть application/json.
X-Merchant-Key-IdstringдаПубличный key_id строки API-ключа в кабинете.
Signaturestring (hex)даHMAC-SHA256 от байт тела JSON (UTF-8) в нижнем hex; ключ HMAC — сырой секрет ключа (только для расчёта, не в HTTP).

Подробнее: аутентификация.

Примеры запроса

curl

curl -X POST 'https://api.protopays.io/api/v1/payments' \
  -H 'Content-Type: application/json' \
  -H 'X-Merchant-Key-Id: <KEY_ID>' \
  -H 'Signature: <SIGNATURE>' \
  -d '{
    "orderId": "order-001",
    "amount": "1000",
    "currency": "RUB",
    "callbackUri": "https://example.com/hooks/protopays",
    "method": "sbp",
    "payer": {
      "userId": "u-4095",
      "userIp": "188.11.55.10",
      "type": "trusted",
      "payments": {
        "successful": 5,
        "expired": 1
      }
    }
  }'

PHP (cURL + hash_hmac)

Base URL, <SECRET>, <KEY_ID> из кабинета. Один и тот же $body — в HMAC и в тело.

<?php
$base = rtrim("https://api.protopays.io", '/');
$keyId = '<KEY_ID>';
$secret = '<SECRET>';

$payload = [
    'orderId' => 'order-001',
    'amount' => '1000',
    'currency' => 'RUB',
    'callbackUri' => 'https://example.com/hooks/protopays',
    'method' => 'sbp',
    'payer' => [
        'userId' => 'u-4095',
        'userIp' => '188.11.55.10',
        'type' => 'trusted',
        'payments' => [
            'successful' => 5,
            'expired' => 1,
        ],
    ],
];
$body = json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
$signature = hash_hmac('sha256', $body, $secret);

$ch = curl_init("{$base}/api/v1/payments");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json',
        'X-Merchant-Key-Id: ' . $keyId,
        'Signature: ' . $signature,
    ],
    CURLOPT_POSTFIELDS => $body,
]);
echo curl_exec($ch);

Ответ (успех)

200, корень: message + data. «Обяз.» — в нормальном сценарии ожидаемо; часть полей может быть null.

ПолеТипОбяз.Описание
messagestringдаКорень. Сообщение о результате (часто `Payment created`).
idstring (UUID)даВ `data`. Публичный id (callback, appeal, и т.д.).
orderIdstringдаВ `data`. Тот же `orderId`, что в запросе.
statusstringдаВ `data`. Текущий статус; значения — в OpenAPI.
amountstringдаВ `data`. Сумма строкой (RUB с двумя десятичными).
currencystringдаВ `data`. RUB.
requisiteobject | nullнетВ `data`. Снимок реквизита: `value`, `holder`, `bank` — если выдали; иначе ключа нет или сценарий иной.
expiresAtstring | nullдаВ `data`, ключ всегда. ISO 8601; `null` если нет срока резерва / сделки.
{
  "message": "Payment created",
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "orderId": "order-001",
    "status": "pending",
    "amount": "1000.00",
    "currency": "RUB",
    "requisite": {
      "value": "+79991234567",
      "holder": "И. Иванов",
      "bank": "Пример банк"
    },
    "expiresAt": "2026-04-20T15:30:00+00:00"
  }
}