Base URLhttps://api.slipstream.cash/api/v1/merchant
Merchant API · v1

Приём платежей через Slipstream

Accept payments with Slipstream

REST API для мерчантов: вы создаёте заявку, получаете реквизиты или ссылку на оплату и показываете их покупателю. Когда платёж подтверждён — Slipstream присылает подписанный вебхук. Поддерживаются приём (payin) и выплаты (payout) в рублях.

A REST API for merchants: you create a request, receive payment requisites or a payment link and show them to your customer. Once the payment is confirmed, Slipstream sends you a signed webhook. Both pay-ins and payouts in RUB are supported.

Base URLhttps://api.slipstream.cash/api/v1/merchant
i

Указанный адрес — тестовый контур. Адрес боевого API, API-ключ и HMAC-секрет выдаются менеджером при подключении. Во всех примерах ключи — заглушки (YOUR_MERCHANT_KEY, YOUR_HMAC_SECRET).

The address above is the test environment. The production URL, API key and HMAC secret are issued by your manager during onboarding. All keys in the examples are placeholders (YOUR_MERCHANT_KEY, YOUR_HMAC_SECRET).

Как это работает

How it works

1
Мерчант
Merchant
Создаёт заявку POST /requests
Creates a request POST /requests
2
Slipstream API
Подбирает реквизит под метод, банк и сумму
Picks a requisite for the method, bank and amount
3
Реквизиты / ссылка
Requisites / link
Приходят в ответе; вы показываете их покупателю
Returned in the response; you show them to the customer
4
Покупатель платит
Customer pays
Переводом на карту / по СБП или по ссылке; для PDF-методов вы присылаете чек
Card / SBP transfer or via link; for PDF methods you upload the receipt
5
Вебхук
Webhook
Confirmed или Canceled на ваш callback_url
Confirmed or Canceled to your callback_url

Эндпоинты

Endpoints

МетодMethodПутьPathНазначениеPurpose
POST/requestsСоздать заявку payin или payoutCreate a payin or payout request
POST/requests/simpleАлиас /requests (тот же обработчик и тело)Alias of /requests (same handler and body)
POST/payin/proofПриложить чек оплатыAttach a payment receipt
POST/payin/cancelОтменить payinCancel a payin
GET/payin/{public_id}Статус payinPayin status
GET/payout/{public_id}Статус payoutPayout status
GET/limitsАктуальные лимиты сумм по методамCurrent amount limits per method
POST/disputesОткрыть диспут по заявкеOpen a dispute on a request
GET/disputes/{dispute_id}Статус диспутаDispute status

Запросы и ответы — JSON в UTF-8 (кроме multipart-загрузки чека). Суммы передаются строкой в рублях с точкой: "5000.00". Успешный ответ — {"success": true, "data": {…}}, ошибка — {"success": false, "error": "…"}.

Requests and responses are UTF-8 JSON (except multipart receipt upload). Amounts are passed as a string in RUB with a dot: "5000.00". Success — {"success": true, "data": {…}}, error — {"success": false, "error": "…"}.

01Авторизация и подписьAuthentication & signing

Каждый запрос идентифицируется API-ключом и подписывается HMAC-SHA256 вашим секретом.

Every request is identified by your API key and signed with HMAC-SHA256 using your secret.

При подключении вы получаете две строки — они показываются один раз, храните их только на сервере:

During onboarding you receive two strings — they are shown once, keep them on your server only:

  • API-ключ (YOUR_MERCHANT_KEY) — передаётся в заголовке Authorization;
  • API key (YOUR_MERCHANT_KEY) — sent in the Authorization header;
  • HMAC-секрет (YOUR_HMAC_SECRET) — ключ подписи ваших запросов и наших вебхуков. Сам секрет в запросах не передаётся.
  • HMAC secret (YOUR_HMAC_SECRET) — the signing key for your requests and our webhooks. The secret itself is never sent.

Заголовки

Headers

ЗаголовокHeaderОписаниеDescription
AuthorizationобязательноrequiredBearer YOUR_MERCHANT_KEY
X-TimestampобязательноrequiredUnix-время в секундах. Допустимое расхождение с часами сервера — ±120 с (держите часы сервера синхронизированными по NTP).Unix time in seconds. Allowed clock skew — ±120 s (keep your server clock NTP-synced).
X-Signature-Versionрекомендуетсяrecommended2 — текущая версия подписи (см. ниже). Без заголовка сервер проверяет устаревшую подпись v1.2 — the current signature version (see below). Without the header the server checks the deprecated v1 signature.
X-Signatureобязательноrequiredhex HMAC-SHA256 от строки подписи (см. ниже)hex HMAC-SHA256 of the signing string (see below)
X-Idempotency-Keyдля POSTfor POSTОбязателен для всех POST. До 128 символов, уникален на одну бизнес-операцию. См. Идемпотентность.Required for every POST. Up to 128 chars, unique per business operation. See Idempotency.
Content-Typeдля POSTfor POSTapplication/json (или multipart/form-data для файлов чеков)(or multipart/form-data for receipt files)

Строка подписи (v2)

Signing string (v2)

Поля склеиваются через перевод строки \n (без завершающего перевода строки). Отправляйте заголовок X-Signature-Version: 2.

Fields are joined with a newline \n (no trailing newline). Send the header X-Signature-Version: 2.

signature v2
X-Signature = hex( HMAC_SHA256( YOUR_HMAC_SECRET,
    "v2"              + "\n" +
    timestamp         + "\n" +
    METHOD            + "\n" +
    path_with_query   + "\n" +
    idempotency_key   + "\n" +
    canonical_json ) )
  • v2 — литерал, версия формата;
  • v2 — a literal, the format version;
  • timestamp — то же значение, что в X-Timestamp;
  • timestamp — the same value as in X-Timestamp;
  • METHOD — GET / POST в верхнем регистре;
  • METHOD — GET / POST in upper case;
  • path_with_query — путь и query-строка ровно как в URL запроса, без домена: /api/v1/merchant/requests, /api/v1/merchant/payin/proof?public_id=PI-…. Отправляете с завершающим / — подписывайте тоже с ним;
  • path_with_query — the path and query string exactly as in the request URL, without host: /api/v1/merchant/requests, /api/v1/merchant/payin/proof?public_id=PI-…. If you send a trailing /, sign it too;
  • idempotency_key — значение X-Idempotency-Key; если заголовка нет (GET) — пустая строка;
  • idempotency_key — the X-Idempotency-Key value; empty string if there is no such header (GET);
  • canonical_json — тело JSON с рекурсивно отсортированными ключами, без пробелов. Для GET и для multipart-запросов — строка {}.
  • canonical_json — the JSON body with recursively sorted keys, no whitespace. For GET and multipart requests — the literal {}.
!

Сервер проверяет подпись по разобранному телу, сериализованному канонически, поэтому порядок ключей в отправленном теле не важен — важно отсортировать их при подписи. Проще всего отправлять ту же каноническую строку, что подписали. В Python используйте ensure_ascii=False, иначе кириллица превратится в \uXXXX и подпись не совпадёт.

The server verifies the signature against the parsed body serialized canonically, so key order in the sent body does not matter — what matters is sorting keys when signing. Easiest: send the exact canonical string you signed. In Python use ensure_ascii=False, otherwise Cyrillic becomes \uXXXX and the signature won't match.

i

Защита от повтора. Каждая подпись мутирующего запроса (POST) принимается один раз: повтор той же подписи в пределах окна → 401 Signature already used (replay). Сетевой ретрай безопасен: повторите запрос с тем же X-Idempotency-Key (он входит в подпись v2) — сервер вернёт сохранённый ответ первой попытки, операция второй раз не выполнится. Для новой операции — новый ключ и свежий X-Timestamp.

Replay protection. Each signature of a mutating (POST) request is accepted once: reusing the same signature within the window → 401 Signature already used (replay). Network retries are safe: resend the request with the same X-Idempotency-Key (it is part of the v2 signature) — the server returns the stored response of the first attempt and does not execute the operation twice. For a new operation use a new key and a fresh X-Timestamp.

sign.js
const crypto = require('crypto');

const API_KEY = 'YOUR_MERCHANT_KEY';
const HMAC_SECRET = 'YOUR_HMAC_SECRET';

// JSON with recursively sorted keys, no whitespace
function canonical(v) {
  const sort = (x) => Array.isArray(x) ? x.map(sort)
    : x && typeof x === 'object'
      ? Object.keys(x).sort().reduce((o, k) => (o[k] = sort(x[k]), o), {})
      : x;
  return JSON.stringify(sort(v ?? {}));
}

// path — path + query exactly as in the URL; idemKey — X-Idempotency-Key (POST) or ''
function signedHeaders(method, path, body, idemKey = '') {
  const ts = String(Math.floor(Date.now() / 1000));
  const payload = method === 'GET' ? '{}' : canonical(body);
  const msg = ['v2', ts, method, path, idemKey, payload].join('\n');
  const sig = crypto.createHmac('sha256', HMAC_SECRET).update(msg, 'utf8').digest('hex');
  const headers = {
    'Authorization': `Bearer ${API_KEY}`,
    'X-Timestamp': ts,
    'X-Signature-Version': '2',
    'X-Signature': sig,
    'Content-Type': 'application/json',
  };
  if (idemKey) headers['X-Idempotency-Key'] = idemKey;
  return headers;
}
sign.py
import hashlib, hmac, json, time

API_KEY = "YOUR_MERCHANT_KEY"
HMAC_SECRET = "YOUR_HMAC_SECRET"

def canonical(body) -> str:
    # sorted keys, no whitespace, keep UTF-8 as is
    return json.dumps(body or {}, sort_keys=True,
                      separators=(",", ":"), ensure_ascii=False)

def signed_headers(method: str, path: str, body=None, idem_key: str = "") -> dict:
    ts = str(int(time.time()))
    payload = "{}" if method == "GET" else canonical(body)
    msg = "\n".join(["v2", ts, method, path, idem_key, payload]).encode("utf-8")
    sig = hmac.new(HMAC_SECRET.encode(), msg, hashlib.sha256).hexdigest()
    headers = {
        "Authorization": f"Bearer {API_KEY}",
        "X-Timestamp": ts,
        "X-Signature-Version": "2",
        "X-Signature": sig,
        "Content-Type": "application/json",
    }
    if idem_key:
        headers["X-Idempotency-Key"] = idem_key
    return headers
sign.sh
TS=$(date +%s)
P="/api/v1/merchant/limits"
# v2\n{ts}\nGET\n{path}\n{idempotency_key — empty for GET}\n{}
SIG=$(printf 'v2\n%s\nGET\n%s\n\n{}' "$TS" "$P" \
  | openssl dgst -sha256 -hmac "YOUR_HMAC_SECRET" | awk '{print $NF}')

curl -s "https://api.slipstream.cash$P" \
  -H "Authorization: Bearer YOUR_MERCHANT_KEY" \
  -H "X-Timestamp: $TS" \
  -H "X-Signature-Version: 2" \
  -H "X-Signature: $SIG"

Подпись v1 (устаревшая)

Signature v1 (deprecated)

!

Устарела. Запросы без X-Signature-Version (или с X-Signature-Version: 1) проверяются по старой формуле. Она пока принимается, но не защищает query-строку и X-Idempotency-Key и будет отключена — переходите на v2. Повтор той же v1-подписи тоже отклоняется (401), кроме ретрая с уже использованным X-Idempotency-Key.

Deprecated. Requests without X-Signature-Version (or with X-Signature-Version: 1) are verified with the old formula. It is still accepted but does not protect the query string and X-Idempotency-Key, and it will be switched off — move to v2. Reusing the same v1 signature is rejected too (401), except for a retry with an already used X-Idempotency-Key.

signature v1 (deprecated)
X-Signature = hex( HMAC_SHA256( YOUR_HMAC_SECRET,
                 "{timestamp}.{METHOD}.{path}{canonical_json}" ) )   // path — without query string

Дополнительная защита

Additional protection

  • IP-allowlist. Если для вашего аккаунта заданы разрешённые IP, корректно подписанные запросы с других адресов получают 403 (адрес в ответе не раскрывается). Пустой список — доступ с любого IP.
  • IP allowlist. If allowed IPs are configured for your account, correctly signed requests from other addresses get 403 (the address is not echoed back). Empty list — any IP is allowed.
  • Перевыпуск. Ключ и секрет можно перевыпустить в кабинете мерчанта (раздел «Интеграция») или через менеджера. Старый ключ перестаёт работать сразу; новый секрет сразу используется и для подписи новых вебхуков.
  • Rotation. Key and secret can be rotated in the merchant cabinet (“Integration”) or via your manager. The old key stops working immediately; the new secret is used for new webhook signatures right away.

02Быстрый стартQuick start

Три шага от ключей до первого подтверждённого платежа.

Three steps from keys to the first confirmed payment.

  1. Проверьте доступ и методыCheck access and methods Вызовите GET /limits — это проверит подпись и покажет, какие методы вам подключены и доступны сейчас (available: true), и в каких пределах сумм. Call GET /limits — it verifies your signature and shows which methods are enabled and currently available for you (available: true) and their amount range.
  2. Создайте заявкуCreate a request POST /requests с методом, суммой и callback_url. В ответе — public_id и requisites (карта / телефон / ссылка). Покажите их покупателю. POST /requests with a method, amount and callback_url. The response contains public_id and requisites (card / phone / link). Show them to the customer.
  3. Примите вебхукReceive the webhook Проверьте X-Signature, найдите заказ по merchant_request_id / public_id и проведите его при Confirmed. Для методов *_check после оплаты отправьте чек через POST /payin/proof. Verify X-Signature, find the order by merchant_request_id / public_id and fulfil it on Confirmed. For *_check methods, upload the receipt via POST /payin/proof after payment.
quickstart.js — Node 18+
// signedHeaders(), canonical() — from the “Authentication” section
const HOST = 'https://api.slipstream.cash';

async function call(method, path, body, idemKey = '') {
  // v2: X-Idempotency-Key входит в подпись / is part of the signature
  const headers = signedHeaders(method, path, body, idemKey);
  const res = await fetch(HOST + path, {
    method, headers,
    body: method === 'POST' ? canonical(body) : undefined,
  });
  return res.json();
}

async function main() {
  const limits = await call('GET', '/api/v1/merchant/limits');
  console.log(limits.data.methods.filter((m) => m.available));

  const order = {
    merchant_request_id: 'order-10001',
    sub_direction: 'payin_simple',
    preferred_method: 'c2c',
    client_amount: '5000.00',
    client_bank: 'any',
    client_requisites: 'customer-42',
    callback_url: 'https://merchant.example.com/webhook',
  };
  const r = await call('POST', '/api/v1/merchant/requests', order, order.merchant_request_id);
  console.log(r.data.public_id, r.data.status, r.data.requisites);
}
main();

03Создание заявкиCreate a request

POSThttps://api.slipstream.cash/api/v1/merchant/requestsX-Idempotency-Key

Один эндпоинт для приёма (payin) и выплат (payout) — направление задаётся sub_direction. POST /requests/simple принимает то же тело и работает идентично.

One endpoint for pay-ins and payouts — direction is set by sub_direction. POST /requests/simple accepts the same body and behaves identically.

Параметры тела

Body parameters

ПолеFieldТипTypeОписаниеDescription
sub_directionenumобязательноrequiredПриём: payin_simple, payin_check, payin_split, payin_split_check. Выплата: payout_check, payout_split, payout_split_check. На обработку влияет только префикс payin/payout; суффиксы принимаются для совместимости. Нужен ли чек — определяет метод, а не суффикс.Pay-in: payin_simple, payin_check, payin_split, payin_split_check. Payout: payout_check, payout_split, payout_split_check. Only the payin/payout prefix affects processing; suffixes are accepted for compatibility. Whether a receipt is required is defined by the method, not the suffix.
preferred_methodstringобязательноrequiredКод метода: c2c, sbp, sbp_check, card_check, deeplink_sbp, deeplink_card, sim, nspk, account. Регистр не важен, есть алиасы — см. Методы оплаты. Метод должен быть подключён вашему аккаунту.Method code: c2c, sbp, sbp_check, card_check, deeplink_sbp, deeplink_card, sim, nspk, account. Case-insensitive, aliases available — see Payment methods. The method must be enabled for your account.
client_amountstringобязательноrequiredСумма в рублях: десятичная строка > 0, не более 2 знаков после точки — "5000", "5000.00". Запятая, экспонента и число вместо строки не принимаются. Максимум по умолчанию — 500 000.00.Amount in RUB: decimal string > 0, up to 2 fractional digits — "5000", "5000.00". Commas, exponent notation and numbers instead of strings are rejected. Default maximum — 500,000.00.
callback_urlurlобязательноrequiredКуда слать вебхуки по этой заявке. Только https:// на публичное доменное имя: IP-адреса, внутренние/локальные адреса и имена без точки отклоняются с 400. Редиректы (3xx) при доставке не выполняются — это ошибка доставки.Where to send webhooks for this request. https:// to a public domain name only: IP addresses, internal/local addresses and dotless names are rejected with 400. Redirects (3xx) are not followed on delivery — they count as a delivery failure.
client_requisitesstringобязательноrequiredPayout: реквизит получателя (номер карты, телефон, счёт) — на него будет сделан перевод. Payin: обязателен по схеме, но в обработке не используется — передайте реквизит или идентификатор плательщика.Payout: recipient requisite (card number, phone, account) — the transfer goes there. Payin: required by schema but not used in processing — pass the payer's requisite or identifier.
client_bankstringобязательно*required*Банк покупателя — код из справочника (sber, tinkoff…). Передаётся внешним исполнителям для подбора реквизита. any, пустая строка, none, null, - = любой банк.Customer's bank — a code from the reference (sber, tinkoff…). Passed to external executors for requisite selection. any, empty string, none, null, - = any bank.
client_bank_codestringобязательно*required*Альтернатива client_bank для совместимости. * — нужно хотя бы одно из двух полей. На подбор влияет только client_bank.Alternative to client_bank for compatibility. * — at least one of the two is required. Only client_bank affects selection.
merchant_request_idstring ≤128необязательноoptionalВаш ID заказа. Возвращается в ответе и во всех вебхуках. На уникальность не проверяется — от дублей защищает X-Idempotency-Key.Your order ID. Returned in the response and every webhook. Not checked for uniqueness — duplicates are prevented by X-Idempotency-Key.
client_full_namestringнеобязательноoptionalФИО плательщика. С ним сверяют поступление; часть исполнителей требует его — рекомендуем передавать.Payer's full name. The incoming transfer is matched against it; some executors require it — recommended.
client_additional_requisitesstringнеобязательноoptionalPayout: дополнительные данные получателя (например, банк / ФИО) — передаются исполнителю вместе с client_requisites.Payout: extra recipient details (e.g. bank / name) — passed to the executor together with client_requisites.
infostringнеобязательноoptionalПроизвольный комментарий; возвращается в ответе на создание.Free-text note; echoed in the create response.
merchant_client_idstring ≤128необязательноoptionalID вашего клиента. Обязателен только при customer_mode: "assigned".Your customer's ID. Required only with customer_mode: "assigned".
customer_mode"assigned"необязательноoptionalРежим «закреплённый клиент» (только payin и конкретный метод). Включается по согласованию с менеджером; без поля — обычный поток.“Assigned customer” mode (payin and an explicit method only). Enabled by agreement with your manager; omit for the regular flow.
customer_accessbooleanнеобязательноoptionalДля assigned: явное подтверждение, что клиент допущен к оплате. В этом режиме обязателен.For assigned: explicit assertion that the customer is allowed to pay. Required in this mode.
payments_count_totalint ≥1необязательноoptionalПринимается для совместимости, на обработку не влияет.Accepted for compatibility, does not affect processing.

Запрос

Request

bash
# body is already canonical: keys sorted, no whitespace
BODY='{"callback_url":"https://merchant.example.com/webhook","client_amount":"5000.00","client_bank":"tinkoff","client_full_name":"Иван Иванов","client_requisites":"customer-42","merchant_request_id":"order-10001","preferred_method":"c2c","sub_direction":"payin_simple"}'
TS=$(date +%s)
P="/api/v1/merchant/requests"
IDEM="order-10001"
SIG=$(printf 'v2\n%s\nPOST\n%s\n%s\n%s' "$TS" "$P" "$IDEM" "$BODY" | openssl dgst -sha256 -hmac "YOUR_HMAC_SECRET" | awk '{print $NF}')

curl -s -X POST "https://api.slipstream.cash$P" \
  -H "Authorization: Bearer YOUR_MERCHANT_KEY" \
  -H "X-Timestamp: $TS" \
  -H "X-Signature-Version: 2" \
  -H "X-Signature: $SIG" \
  -H "X-Idempotency-Key: $IDEM" \
  -H "Content-Type: application/json" \
  --data "$BODY"
create.js
// signedHeaders(), canonical() — see “Authentication”
const path = '/api/v1/merchant/requests';
const body = {
  merchant_request_id: 'order-10001',
  sub_direction: 'payin_simple',
  preferred_method: 'c2c',
  client_amount: '5000.00',
  client_bank: 'tinkoff',
  client_full_name: 'Иван Иванов',
  client_requisites: 'customer-42',
  callback_url: 'https://merchant.example.com/webhook',
};

const res = await fetch('https://api.slipstream.cash' + path, {
  method: 'POST',
  headers: signedHeaders('POST', path, body, body.merchant_request_id), // v2: key is signed
  body: canonical(body),
});
const { success, data, error } = await res.json();
if (!success) throw new Error(error);
if (!data.requisites) { /* no requisite found — see “Requisites & links” */ }
create.py
import requests  # signed_headers(), canonical() — see “Authentication”

path = "/api/v1/merchant/requests"
body = {
    "merchant_request_id": "order-10001",
    "sub_direction": "payin_simple",
    "preferred_method": "c2c",
    "client_amount": "5000.00",
    "client_bank": "tinkoff",
    "client_full_name": "Иван Иванов",
    "client_requisites": "customer-42",
    "callback_url": "https://merchant.example.com/webhook",
}
headers = signed_headers("POST", path, body, body["merchant_request_id"])  # v2: key is signed

r = requests.post("https://api.slipstream.cash" + path,
                  data=canonical(body).encode("utf-8"), headers=headers, timeout=30)
resp = r.json()
if not resp["success"]:
    raise RuntimeError(resp["error"])
print(resp["data"]["public_id"], resp["data"].get("requisites"))

Ответ 200

Response 200

json
{
  "success": true,
  "data": {
    "kind": "payin",
    "public_id": "PI-3f9a1c7e5b2d4a60",
    "merchant_request_id": "order-10001",
    "status": "Working",
    "created_at": "2026-09-23T08:15:02.114Z",
    "rub_amount": "5000.00",
    "usdt_amount": "51.35135135",
    "rate": "92.5000",
    "rate_with_commission": "87.8750",
    "requisites": {
      "method": "c2c",
      "type": "card",
      "card_number": "2200123412341234",
      "phone": null,
      "account": null,
      "bik": null,
      "bank": "tinkoff",
      "bank_name": "Т-Банк",
      "holder": "Иван П.",
      "link": null,
      "payment_url": null,
      "expires_at": "2026-09-23T08:35:02.114Z"
    },
    "instant_match": { "attempted": true, "matched": false }
  }
}
ПолеFieldОписаниеDescription
kindpayin | payout
public_idID заявки в Slipstream: PI-… для payin, PO-… для payout. Используйте во всех следующих вызовах.Slipstream request ID: PI-… for payin, PO-… for payout. Use it in all subsequent calls.
merchant_request_idВаш ID (если передан).Your ID (if provided).
statusСтатус на момент ответа — см. Статусы.Status at response time — see Statuses.
infoЭхо вашего info (нет, если не передан).Echo of your info (absent if not sent).
created_atВремя создания, ISO 8601 UTC.Creation time, ISO 8601 UTC.
rub_amountСумма заявки в рублях.Request amount in RUB.
usdt_amountСумма к зачислению в USDT по курсу, зафиксированному при создании, за вычетом вашей комиссии. Пустая строка, если курс недоступен.Amount to be credited in USDT at the rate fixed at creation, net of your commission. Empty string if the rate is unavailable.
rateКурс RUB/USDT без комиссии (справочно).RUB/USDT rate without commission (for reference).
rate_with_commissionЭффективный курс: rate × (1 − комиссия).Effective rate: rate × (1 − commission).
requisitesРеквизиты для покупателя (только payin). Отсутствует, если реквизит не найден. Пока заявка открыта, те же реквизиты отдаёт GET /payin/{public_id}. См. Реквизиты и ссылки.Requisites for the customer (payin only). Absent if no requisite was found. While the request is open, the same requisites are returned by GET /payin/{public_id}. See Requisites & links.
instant_matchСлужебная информация о мгновенном сведении со встречной заявкой: attempted, matched, опционально payout_public_id.Internal info about instant matching with a counter request: attempted, matched, optional payout_public_id.

04Примеры по методамExamples by method

Тело запроса и типичный ответ для каждого метода. Заголовки и подпись — как в разделе Авторизация.

Request body and a typical response for each method. Headers and signing — as in Authentication.

Перевод с карты на карту. Покупатель получает номер карты, банк и имя держателя.
Card-to-card transfer. The customer receives a card number, bank and holder name.
request
{
  "merchant_request_id": "order-c2c-1",
  "sub_direction": "payin_simple",
  "preferred_method": "c2c",
  "client_amount": "5000.00",
  "client_bank": "sber",
  "client_full_name": "Иван Иванов",
  "client_requisites": "customer-42",
  "callback_url": "https://merchant.example.com/webhook"
}
response 200
{
  "success": true,
  "data": {
    "kind": "payin",
    "public_id": "PI-3f9a1c7e5b2d4a60",
    "merchant_request_id": "order-c2c-1",
    "status": "Working",
    "created_at": "2026-09-23T08:15:02.114Z",
    "rub_amount": "5000.00",
    "usdt_amount": "51.35135135",
    "rate": "92.5000",
    "rate_with_commission": "87.8750",
    "requisites": {
      "method": "c2c",
      "type": "card",
      "card_number": "2200123412341234",
      "phone": null,
      "account": null,
      "bik": null,
      "bank": "sber",
      "bank_name": "Сбер",
      "holder": "Иван П.",
      "link": null,
      "payment_url": null,
      "expires_at": "2026-09-23T08:35:02.114Z"
    },
    "instant_match": { "attempted": true, "matched": false }
  }
}
Перевод по номеру телефона через СБП. Покупатель получает телефон и банк получателя — переводить нужно именно в этот банк. Телефон всегда приходит в phone (type: "sbp") в формате +7XXXXXXXXXX.
Transfer by phone number via SBP (Faster Payments). The customer receives a phone number and the recipient bank — the transfer must go to that bank. The phone always arrives in phone (type: "sbp"), formatted as +7XXXXXXXXXX.
request
{
  "merchant_request_id": "order-sbp-1",
  "sub_direction": "payin_simple",
  "preferred_method": "sbp",
  "client_amount": "3200.00",
  "client_bank": "any",
  "client_full_name": "Иван Иванов",
  "client_requisites": "customer-42",
  "callback_url": "https://merchant.example.com/webhook"
}
response 200
{
  "success": true,
  "data": {
    "kind": "payin",
    "public_id": "PI-8c21d0e94ab37f15",
    "merchant_request_id": "order-sbp-1",
    "status": "Working",
    "created_at": "2026-09-23T08:20:44.901Z",
    "rub_amount": "3200.00",
    "usdt_amount": "32.86486486",
    "rate": "92.5000",
    "rate_with_commission": "87.8750",
    "requisites": {
      "method": "sbp",
      "type": "sbp",
      "card_number": null,
      "phone": "+79001234567",
      "account": null,
      "bik": null,
      "bank": "tinkoff",
      "bank_name": "Т-Банк",
      "holder": "Мария С.",
      "link": null,
      "payment_url": null,
      "expires_at": "2026-09-23T08:40:44.901Z"
    },
    "instant_match": { "attempted": true, "matched": false }
  }
}
СБП с обязательным PDF-чеком. Реквизиты выдаёт внешний исполнитель — поэтому status может остаться Waiting; телефон — в phone. После оплаты обязательно пришлите PDF-чек через POST /payin/proof — без него платёж не будет засчитан. Так же работает card_check (карта + PDF).
SBP with a mandatory PDF receipt. Requisites come from an external executor — so status may stay Waiting; the phone is in phone. After payment you must upload the PDF receipt via POST /payin/proof — without it the payment will not be credited. card_check (card + PDF) works the same way.
request
{
  "merchant_request_id": "order-sbpcheck-1",
  "sub_direction": "payin_check",
  "preferred_method": "sbp_check",
  "client_amount": "7500.00",
  "client_bank": "sber",
  "client_full_name": "Иван Иванов",
  "client_requisites": "customer-42",
  "callback_url": "https://merchant.example.com/webhook"
}
response 200
{
  "success": true,
  "data": {
    "kind": "payin",
    "public_id": "PI-5e0b7a3c91f24d88",
    "merchant_request_id": "order-sbpcheck-1",
    "status": "Waiting",
    "created_at": "2026-09-23T08:31:10.377Z",
    "rub_amount": "7500.00",
    "usdt_amount": "77.02702702",
    "rate": "92.5000",
    "rate_with_commission": "87.8750",
    "requisites": {
      "method": "sbp_check",
      "type": "sbp",
      "card_number": null,
      "phone": "+79007654321",
      "account": null,
      "bik": null,
      "bank": "sber",
      "bank_name": "Сбербанк",
      "holder": "Алексей К.",
      "link": null,
      "payment_url": null,
      "expires_at": "2026-09-23T08:51:10.377Z"
    },
    "instant_match": { "attempted": true, "matched": false }
  }
}
Оплата по ссылке через СБП. Вместо реквизитов — ссылка в link (дублируется в payment_url), type: "link": отправьте покупателя по ссылке (редирект или QR). Алиасы метода: Deeplink, Link.
Pay-by-link via SBP. Instead of requisites you get a link in link (duplicated in payment_url), type: "link": send the customer to it (redirect or QR). Method aliases: Deeplink, Link.
request
{
  "merchant_request_id": "order-dl-sbp-1",
  "sub_direction": "payin_simple",
  "preferred_method": "deeplink_sbp",
  "client_amount": "2500.00",
  "client_bank": "any",
  "client_requisites": "customer-42",
  "callback_url": "https://merchant.example.com/webhook"
}
response 200
{
  "success": true,
  "data": {
    "kind": "payin",
    "public_id": "PI-a7d44e1f0c9b2356",
    "merchant_request_id": "order-dl-sbp-1",
    "status": "Waiting",
    "created_at": "2026-09-23T08:40:05.012Z",
    "rub_amount": "2500.00",
    "usdt_amount": "25.67567567",
    "rate": "92.5000",
    "rate_with_commission": "87.8750",
    "requisites": {
      "method": "deeplink_sbp",
      "type": "link",
      "card_number": null,
      "phone": null,
      "account": null,
      "bik": null,
      "bank": null,
      "bank_name": null,
      "holder": null,
      "link": "https://pay.example.com/f/9Qx2LmA7",
      "payment_url": "https://pay.example.com/f/9Qx2LmA7",
      "expires_at": "2026-09-23T09:00:05.012Z"
    },
    "instant_match": { "attempted": true, "matched": false }
  }
}
Оплата картой по ссылке. Ответ такой же, как у Deeplink СБП, — покупателю нужен только link.
Card payment via link. The response is the same as for Deeplink SBP — the customer only needs link.
request
{
  "merchant_request_id": "order-dl-card-1",
  "sub_direction": "payin_simple",
  "preferred_method": "deeplink_card",
  "client_amount": "4100.00",
  "client_bank": "any",
  "client_requisites": "customer-42",
  "callback_url": "https://merchant.example.com/webhook"
}
response 200
{
  "success": true,
  "data": {
    "kind": "payin",
    "public_id": "PI-2b9f60c3d815ea47",
    "merchant_request_id": "order-dl-card-1",
    "status": "Waiting",
    "created_at": "2026-09-23T08:44:51.640Z",
    "rub_amount": "4100.00",
    "usdt_amount": "42.10810810",
    "rate": "92.5000",
    "rate_with_commission": "87.8750",
    "requisites": {
      "method": "deeplink_card",
      "type": "link",
      "card_number": null,
      "phone": null,
      "account": null,
      "bik": null,
      "bank": null,
      "bank_name": null,
      "holder": null,
      "link": "https://pay.example.com/f/Hk3vT0pZ",
      "payment_url": "https://pay.example.com/f/Hk3vT0pZ",
      "expires_at": "2026-09-23T09:04:51.640Z"
    },
    "instant_match": { "attempted": true, "matched": false }
  }
}
i

Значения usdt_amount / rate в примерах посчитаны для курса 92.50 и комиссии 5% — у вас будут свои. Реквизиты и ссылки в примерах вымышлены.

usdt_amount / rate in the examples assume a 92.50 rate and 5% commission — yours will differ. Requisites and links in the examples are fictional.

05Методы оплатыPayment methods

Метод передаётся в preferred_method. Использовать можно только методы, подключённые вашему аккаунту — список и текущие суммы смотрите в GET /limits.

The method is passed in preferred_method. Only methods enabled for your account can be used — see the list and current amounts via GET /limits.

c2c
К2К
Card-to-card
Номер карты, банк, держатель. Чек не нужен.
Card number, bank, holder. No receipt needed.
sbp
СБП
SBP
Телефон + банк получателя. Чек не нужен.
Phone + recipient bank. No receipt needed.
sbp_check
СБП (PDF)
SBP (PDF)
Телефон + банк. Обязателен PDF-чек.
Phone + bank. PDF receipt required.
card_check
Карта (PDF)
Card (PDF)
Номер карты. Обязателен PDF-чек.
Card number. PDF receipt required.
deeplink_sbp
Deeplink СБП
Deeplink SBP
Ссылка на оплату payment_url.
Payment link payment_url.
deeplink_card
Deeplink Карта
Deeplink Card
Ссылка на оплату картой payment_url.
Card payment link payment_url.
КодCodeНазваниеNameЧто получает покупательWhat the customer getsЧекReceipt
c2cК2КCard-to-cardcard_number, bank, holderне нуженno
sbpСБПSBPphone*, bank, holderне нуженno
sbp_checkСБП (PDF)SBP (PDF)phone*, bank, holderPDF обязателенPDF required
card_checkКарта (PDF)Card (PDF)card_number, bank, holderPDF обязателенPDF required
deeplink_sbpDeeplink СБПSBPpayment_urlне нуженno
deeplink_cardDeeplink КартаCardpayment_urlне нуженno
simSIMтелефон* + оператор (банки sim_*)phone* + carrier (sim_* banks)не нуженno
accountСчётBank accountaccount, bik, bankне нуженno
nspkNSPK (QR)ссылка / QR в payment_urllink / QR in payment_urlне нуженno

* Телефон может прийти в phone или в card_number — в зависимости от исполнителя. sim, account, nspk подключаются по запросу.

* The phone may arrive in phone or in card_number depending on the executor. sim, account, nspk are enabled on request.

Алиасы

Aliases

Для совместимости с интеграциями предыдущей версии Slipstream принимаются имена (регистр не важен):

For compatibility with previous Slipstream integrations the following names are accepted (case-insensitive):

ПереданоSentМетодMethod
Cardc2c
SBPsbp
Deeplink, Linkdeeplink_sbp
Allall — служебное значение, не рекомендуется: передавайте конкретный метод.all — service value, not recommended: pass a concrete method.

06Реквизиты и ссылкиRequisites & links

Реквизиты для оплаты приходят в объекте requisites — в ответе на создание заявки и в GET /payin/{public_id}, пока заявка открыта. Формат один и тот же независимо от того, кто выдал реквизит.

Payment requisites come in the requisites object — in the create response and in GET /payin/{public_id} while the request is open. The format is the same regardless of who issued the requisite.

ПолеFieldТипTypeОписаниеDescription
methodstringКод метода заявки (c2c, sbp, sbp_check, deeplink_sbp, …).Request method code (c2c, sbp, sbp_check, deeplink_sbp, …).
typestringКак платить: card — по номеру карты, sbp — по телефону, account — по счёту, link — по ссылке.How to pay: card — by card number, sbp — by phone, account — by account, link — via link.
card_numberstring | nullНомер карты. Гарантированно заполнен при type: "card"; телефон сюда не попадает.Card number. Guaranteed when type: "card"; a phone never goes here.
phonestring | nullТелефон для СБП / SIM в формате +7XXXXXXXXXX. Гарантированно заполнен при type: "sbp".Phone for SBP / SIM, formatted +7XXXXXXXXXX. Guaranteed when type: "sbp".
accountstring | nullНомер счёта (type: "account").Account number (type: "account").
bikstring | nullБИК банка для перевода по счёту.Bank BIC for account transfers.
bankstring | nullБанк получателя: код из справочника, если сопоставился; иначе — как пришло от исполнителя.Recipient bank: a reference code when matched; otherwise as received from the executor.
bank_namestring | nullНазвание банка для показа покупателю (как пришло).Bank name to show the customer (as received).
holderstring | nullИмя получателя.Recipient name.
linkstring | nullСсылка на оплату (deeplink / платёжная форма / QR). Гарантированно заполнена при type: "link".Payment link (deeplink / payment form / QR). Guaranteed when type: "link".
payment_urlstring | nullТо же, что link (оставлено для совместимости).Same as link (kept for compatibility).
expires_atstring | nullДо какого момента реквизит действителен, ISO 8601 UTC.Requisite valid until, ISO 8601 UTC.
✓

Что показывать покупателю — по type: link → отправьте по ссылке link; sbp → phone; card → card_number; account → account/bik. Вместе с bank_name, holder и точной суммой rub_amount.

What to show the customer — by type: link → send them to link; sbp → phone; card → card_number; account → account/bik. Together with bank_name, holder and the exact rub_amount.

!

Нет requisites в ответе = под этот метод/банк/сумму сейчас нет свободного реквизита. Заявка остаётся Waiting и будет автоматически отменена по истечении срока жизни. Рекомендуем сразу отменить её через POST /payin/cancel и предложить покупателю другой метод или сумму.

No requisites in the response = no free requisite for this method/bank/amount right now. The request stays Waiting and is auto-canceled when its lifetime ends. We recommend canceling it right away via POST /payin/cancel and offering another method or amount.

Повторно получить реквизиты можно через GET /payin/{public_id} — пока заявка открыта (Waiting/Working/Processing) и реквизит выдан. После Confirmed/Canceled там requisites: null. Если потерялся ответ на создание, можно также повторить тот же POST /requests с тем же X-Idempotency-Key и телом (см. Идемпотентность).

Requisites can be re-fetched via GET /payin/{public_id} while the request is open (Waiting/Working/Processing) and a requisite has been issued. After Confirmed/Canceled it returns requisites: null. If the create response was lost you can also repeat the same POST /requests with the same X-Idempotency-Key and body (see Idempotency).

07Чеки (proof)Receipts (proof)

POSThttps://api.slipstream.cash/api/v1/merchant/payin/proofX-Idempotency-Key

Приложить чек об оплате к заявке. Для sbp_check и card_check — обязательно (только PDF); для остальных методов — по желанию, помогает при спорных платежах.

Attach a payment receipt to a request. Mandatory for sbp_check and card_check (PDF only); optional for other methods — helps with disputed payments.

Вариант 1 — JSON (base64)

Option 1 — JSON (base64)

ПолеFieldОписаниеDescription
public_idобязательноrequiredID заявкиRequest ID
file_nameобязательноrequiredИмя файла, до 200 символовFile name, up to 200 chars
mime_typeобязательноrequiredapplication/pdf, image/png, image/jpeg, image/webp, image/heic
file_base64обязательноrequiredСодержимое файла в base64 (префикс data:…;base64, допустим)File content in base64 (a data:…;base64, prefix is allowed)
noteнеобязательноoptionalКомментарий, до 1000 символовComment, up to 1000 chars
!

Лимит JSON-тела — 256 КБ: через base64 проходят файлы примерно до 180 КБ. Для больших файлов используйте multipart (до 10 МБ).

The JSON body limit is 256 KB: base64 fits files up to roughly 180 KB. Use multipart for larger files (up to 10 MB).

request
{
  "public_id": "PI-5e0b7a3c91f24d88",
  "file_name": "receipt.pdf",
  "mime_type": "application/pdf",
  "file_base64": "JVBERi0xLjQKJcfsj6IK...",
  "note": "order-sbpcheck-1"
}
response 200
{
  "success": true,
  "data": {
    "proof_id": "1842",
    "public_id": "PI-5e0b7a3c91f24d88",
    "status": "pending",
    "file_name": "receipt.pdf",
    "file_size": 48213,
    "created_at": "2026-09-23T08:36:12.508Z",
    "forwarded": true
  }
}

Вариант 2 — multipart/form-data

Option 2 — multipart/form-data

Файлы — в поле receipts (до 5 файлов по 10 МБ), public_id — полем формы или в query ?public_id=, опционально note. Подпись для multipart считается от тела {}.

Files go into the receipts field (up to 5 files × 10 MB), public_id — as a form field or ?public_id= query, optional note. The signature for multipart is computed over the body {}.

bash
TS=$(date +%s)
P="/api/v1/merchant/payin/proof"
SIG=$(printf '%s' "$TS.POST.$P{}" | openssl dgst -sha256 -hmac "YOUR_HMAC_SECRET" | awk '{print $NF}')

curl -s -X POST "https://api.slipstream.cash$P" \
  -H "Authorization: Bearer YOUR_MERCHANT_KEY" \
  -H "X-Timestamp: $TS" -H "X-Signature: $SIG" \
  -H "X-Idempotency-Key: proof-PI-5e0b7a3c91f24d88-1" \
  -F "public_id=PI-5e0b7a3c91f24d88" \
  -F "receipts=@receipt.pdf;type=application/pdf"
response 200
{
  "success": true,
  "data": {
    "attached": 1,
    "receipts": [ { "id": "1843", "filename": "receipt.pdf" } ],
    "public_id": "PI-5e0b7a3c91f24d88",
    "forwarded": true
  }
}

Правила и ответы

Rules and responses

  • Для sbp_check / card_check принимается только PDF, файл проверяется по сигнатуре %PDF — переименованная картинка вернёт 400.
  • For sbp_check / card_check PDF only is accepted; the file is checked for the %PDF signature — a renamed image returns 400.
  • Чек можно приложить в любом статусе, кроме Canceled (→ 409, в т.ч. для истёкшей заявки). Можно отправить несколько чеков.
  • A receipt can be attached in any status except Canceled (→ 409, including expired requests). Multiple receipts are allowed.
  • forwarded: true — чек передан исполнителю и принят; null — передача не требуется (чек сохранён у нас для проверки).
  • forwarded: true — the receipt was passed to the executor and accepted; null — forwarding not required (stored with us for review).
  • 424 — чек сохранён, но исполнитель его отклонил. Исправьте файл и повторите с новым X-Idempotency-Key.
  • 424 — the receipt is saved but the executor rejected it. Fix the file and retry with a new X-Idempotency-Key.
  • Сам по себе чек не подтверждает платёж: решение принимают оператор или исполнитель, результат придёт вебхуком.
  • A receipt alone does not confirm the payment: the operator or executor decides, the result arrives by webhook.
response 424
{
  "success": false,
  "error": "Receipts were saved on our side, but provider rejected them: invalid receipt. Please retry.",
  "attached": 1,
  "receipts": [ { "id": "1844", "filename": "receipt.pdf" } ]
}

08Статус заявкиRequest status

GEThttps://api.slipstream.cash/api/v1/merchant/payin/{public_id}
GEThttps://api.slipstream.cash/api/v1/merchant/payout/{public_id}

GET подписывается от тела {}; путь для подписи — с public_id, например /api/v1/merchant/payin/PI-3f9a1c7e5b2d4a60. Чужая заявка или не то направление → 404.

GET is signed over the body {}; the signed path includes public_id, e.g. /api/v1/merchant/payin/PI-3f9a1c7e5b2d4a60. Someone else's request or the wrong direction → 404.

response 200 — payin, открытаopen
{
  "success": true,
  "data": {
    "public_id": "PI-3f9a1c7e5b2d4a60",
    "status": "Working",
    "rub_amount": "5000.00",
    "actual_amount": null,
    "amount_mismatch": false,
    "usdt_amount": "51.35135135",
    "rate": "92.5000",
    "rate_with_commission": "87.8750",
    "requisites": {
      "method": "c2c",
      "type": "card",
      "card_number": "2200123412341234",
      "phone": null,
      "account": null,
      "bik": null,
      "bank": "tinkoff",
      "bank_name": "Т-Банк",
      "holder": "Иван П.",
      "link": null,
      "payment_url": null,
      "expires_at": "2026-09-23T08:35:02.114Z"
    },
    "expires_at": "2026-09-23T08:35:02.114Z",
    "linked_requests": []
  }
}
response 200 — payin, закрыта с другой суммойclosed with a different amount
{
  "success": true,
  "data": {
    "public_id": "PI-3f9a1c7e5b2d4a60",
    "status": "Confirmed",
    "rub_amount": "5000.00",
    "actual_amount": "4700.00",
    "amount_mismatch": true,
    "usdt_amount": "51.35135135",
    "rate": "92.5000",
    "rate_with_commission": "87.8750",
    "requisites": null,
    "expires_at": null,
    "linked_requests": []
  }
}
ПолеFieldОписаниеDescription
rub_amountСумма заявки (номинал) в рублях.Request (nominal) amount in RUB.
actual_amountФактически оплаченная сумма, если при подтверждении она отличалась от rub_amount; иначе null.Actually paid amount if it differed from rub_amount at confirmation; otherwise null.
amount_mismatchtrue, если actual_amount отличается от rub_amount.true if actual_amount differs from rub_amount.
requisitesТолько payin. Реквизиты в едином формате, пока заявка открыта и реквизит выдан; null — реквизит ещё не выдан или заявка закрыта (Confirmed/Canceled).Payin only. Requisites in the unified format while the request is open and a requisite has been issued; null — not issued yet or the request is closed (Confirmed/Canceled).
expires_atТолько payin. Срок жизни открытой заявки, ISO 8601 UTC; для закрытой — null.Payin only. Lifetime of an open request, ISO 8601 UTC; null once closed.

Ответ для payout — public_id, status, rub_amount, actual_amount, amount_mismatch, usdt_amount, rate, rate_with_commission (без requisites, expires_at и linked_requests).

The payout response has public_id, status, rub_amount, actual_amount, amount_mismatch, usdt_amount, rate, rate_with_commission (no requisites, expires_at or linked_requests).

Статусы

Statuses

СтатусStatusЗначениеMeaningФинальныйFinal
WaitingЗаявка создана. Реквизит мог быть уже выдан внешним исполнителем (смотрите requisites в ответе на создание или в GET) — либо не найден.Request created. A requisite may already have been issued by an external executor (see requisites in the create response or in GET) — or none was found.нетno
WorkingРеквизит назначен, ожидается оплата и её подтверждение.Requisite assigned, awaiting payment and its confirmation.нетno
ConfirmedПлатёж подтверждён, средства зачислены. Можно выдавать товар.Payment confirmed, funds credited. Safe to fulfil the order.даyes
CanceledОтменена вами, оператором, исполнителем или истёк срок жизни.Canceled by you, an operator, the executor, or the lifetime expired.да*yes*
ProcessingТолько в режиме customer_mode: "assigned": реквизит ещё запрашивается у исполнителя.Only in customer_mode: "assigned": the requisite is still being requested from the executor.нетno
*

Заявка, отменённая по истечении срока, может позже перейти в Confirmed, если оплата всё-таки поступила и была подтверждена («позднее подтверждение»). Вы получите второй вебхук — обрабатывайте Confirmed после Canceled корректно. Заявку, отменённую через API (вами), оператором или исполнителем, подтвердить уже нельзя.

A request canceled due to expiry may later become Confirmed if the payment actually arrived and was confirmed (“late confirmation”). You will receive a second webhook — handle Confirmed after Canceled correctly. A request canceled via API (by you), by an operator or by the executor can no longer be confirmed.

переходыtransitions
Waiting ──► Working ──► Confirmed
   │           │
   └───────────┴──► Canceled ──(late confirm, expiry only)──► Confirmed

09ОтменаCancel

POSThttps://api.slipstream.cash/api/v1/merchant/payin/cancelX-Idempotency-Key

Отменить payin, пока он в статусе Waiting или Working. Отмена payout через API не поддерживается.

Cancel a payin while it is Waiting or Working. Payout cancellation via API is not supported.

request
{ "public_id": "PI-3f9a1c7e5b2d4a60" }
response 200
{ "success": true, "data": { "public_id": "PI-3f9a1c7e5b2d4a60", "status": "Canceled" } }
  • Заявка в финальном статусе → 409 Cannot cancel request in terminal status Confirmed (или Canceled).
  • Request in a final status → 409 Cannot cancel request in terminal status Confirmed (or Canceled).
  • Статус изменился в момент отмены → 409 Request state changed, cannot cancel — запросите статус.
  • Status changed during cancellation → 409 Request state changed, cannot cancel — query the status.
  • После успешной отмены на callback_url приходит вебхук Canceled, реквизит освобождается; если реквизит выдал внешний исполнитель, ему также отправляется запрос на отмену.
  • After a successful cancel a Canceled webhook is sent to callback_url, the requisite is released; if the requisite came from an external executor, a cancel request is sent to it as well.
!

Не отменяйте заявку, если покупатель уже мог перевести деньги: отменённую вами заявку подтвердить нельзя. В спорном случае дождитесь вебхука или откройте диспут.

Do not cancel a request if the customer may have already paid: a request you canceled cannot be confirmed. In doubtful cases wait for the webhook or open a dispute.

10Выплаты (payout)Payouts

Выплата создаётся тем же POST /requests с sub_direction вида payout_*. Реквизит получателя — в client_requisites (+ client_additional_requisites).

A payout is created with the same POST /requests using a payout_* sub_direction. The recipient requisite goes into client_requisites (+ client_additional_requisites).

request
{
  "merchant_request_id": "payout-777",
  "sub_direction": "payout_check",
  "preferred_method": "c2c",
  "client_amount": "12000.00",
  "client_bank": "sber",
  "client_requisites": "2200123412341234",
  "client_additional_requisites": "Иван Иванов",
  "client_full_name": "Иван Иванов",
  "callback_url": "https://merchant.example.com/webhook"
}
response 200
{
  "success": true,
  "data": {
    "kind": "payout",
    "public_id": "PO-1d7c9e20ab45f318",
    "merchant_request_id": "payout-777",
    "status": "Working",
    "created_at": "2026-09-23T09:02:17.221Z",
    "rub_amount": "12000.00",
    "usdt_amount": "126.48648648",
    "rate": "92.5000",
    "rate_with_commission": "90.6500",
    "instant_match": { "attempted": true, "matched": false }
  }
}

requisites для payout не возвращаются. Working — исполнитель назначен, Waiting — ещё нет. Итог приходит вебхуком payout.status.changed; статус — GET /payout/{public_id}. В примере комиссия на выплату — 2%.

requisites are not returned for payouts. Working — an executor is assigned, Waiting — not yet. The outcome arrives via the payout.status.changed webhook; status — GET /payout/{public_id}. The example assumes a 2% payout commission.

11ВебхукиWebhooks

Slipstream отправляет POST на callback_url заявки, когда payin получил реквизит и когда заявка переходит в финальный статус. Если callback_url не передан — вебхуки по заявке не отправляются.

Slipstream sends a POST to the request's callback_url when a payin gets its requisite and when the request reaches a final status. If no callback_url was provided, no webhooks are sent for the request.

Событие (event / X-Event)Event (event / X-Event)КогдаWhen
payin.requisites.issuedpayin получил реквизит для оплаты. Отправляется один раз на заявку. Реквизит может быть уже в ответе на создание — вебхук тогда дублирует его (удобно, если реквизит выдан позже, например в режиме Processing).A payin received its payment requisite. Sent once per request. The requisite may already be in the create response — then the webhook duplicates it (useful when the requisite is issued later, e.g. in Processing mode).
payin.status.changedpayin перешёл в Confirmed или Canceledpayin became Confirmed or Canceled
payout.status.changedpayout перешёл в Confirmed или Canceledpayout became Confirmed or Canceled
testТестовый вебхук из кабинета мерчанта (кнопка проверки интеграции). Подписывается так же, как боевые.Test webhook from the merchant cabinet (integration check button). Signed exactly like live webhooks.

Прочие промежуточные переходы (Waiting → Working) отдельным вебхуком не отправляются. Порядок доставки разных событий не гарантирован: ориентируйтесь на поле event и не откатывайте финальный статус назад по более позднему payin.requisites.issued.

Other intermediate transitions (Waiting → Working) are not sent as separate webhooks. Delivery order across events is not guaranteed: rely on the event field and never roll a final status back because of a later payin.requisites.issued.

Заголовки

Headers

headers
POST /webhook HTTP/1.1
Content-Type: application/json
X-Event: payin.status.changed
X-Delivery-Id: 9b2f6c1e-4d7a-4f0e-9a51-2c8e7d3b1f60
X-Timestamp: 1790154137
X-Signature-V2: 5e0c…a41f
X-Signature: 3b6f…e91a
ЗаголовокHeaderОписаниеDescription
X-EventИмя события (совпадает с полем event в теле).Event name (same as the event body field).
X-Delivery-IdUUID доставки. Одинаков для всех повторов одной доставки (и для ручной повторной отправки из кабинета) — используйте для дедупликации.Delivery UUID. Identical across all retries of one delivery (and for a manual resend from the cabinet) — use it for deduplication.
X-TimestampUnix-время отправки в секундах. Своё у каждой попытки.Send time, Unix seconds. Fresh on every attempt.
X-Signature-V2Подпись с timestamp (защищает от повтора) — см. ниже. Проверяйте именно её.Timestamped signature (replay-protected) — see below. Verify this one.
X-SignatureПереходный период: прежняя подпись без timestamp hex(HMAC_SHA256(secret, canonical_json(body))). После миграции мерчантов в этом заголовке будет та же подпись, что в X-Signature-V2.Transition period: the previous signature without timestamp hex(HMAC_SHA256(secret, canonical_json(body))). After merchants migrate, this header will carry the same value as X-Signature-V2.

Тело: payin.requisites.issued

Body: payin.requisites.issued

body
{
  "event": "payin.requisites.issued",
  "public_id": "PI-3f9a1c7e5b2d4a60",
  "merchant_request_id": "order-10001",
  "status": "Working",
  "kind": "payin",
  "method": "c2c",
  "rub_amount": "5000.00",
  "requisites": {
    "method": "c2c",
    "type": "card",
    "card_number": "2200123412341234",
    "phone": null,
    "account": null,
    "bik": null,
    "bank": "sber",
    "bank_name": "Сбербанк",
    "holder": "Иван И.",
    "link": null,
    "payment_url": null,
    "expires_at": "2026-09-23T09:17:17.221Z"
  },
  "expires_at": "2026-09-23T09:17:17.221Z",
  "sent_at": "2026-09-23T09:02:18.004Z"
}
ПолеFieldОписаниеDescription
statusТекущий статус заявки на момент выдачи: обычно Working, иногда Waiting.Request status at issue time: usually Working, sometimes Waiting.
methodКод метода оплаты.Payment method code.
rub_amountСумма заявки (номинал), RUB.Request (nominal) amount, RUB.
requisitesРеквизиты в едином формате — как в ответе на создание и в GET.Requisites in the unified format — same as in the create response and GET.
expires_atСрок жизни заявки, ISO 8601 UTC, или null.Request lifetime, ISO 8601 UTC, or null.
sent_atВремя отправки этой попытки, ISO 8601 UTC.Time this attempt was sent, ISO 8601 UTC.

Тело: payin.status.changed / payout.status.changed

Body: payin.status.changed / payout.status.changed

body — Confirmed
{
  "event": "payin.status.changed",
  "public_id": "PI-3f9a1c7e5b2d4a60",
  "status": "Confirmed",
  "merchant_request_id": "order-10001",
  "kind": "payin",
  "method": "c2c",
  "rub_amount": "5000.00",
  "actual_amount": "4900.00",
  "amount_mismatch": true,
  "completed_at": "2026-09-23T09:10:41.512Z",
  "canceled_at": null,
  "sent_at": "2026-09-23T09:10:41.873Z"
}
body — Canceled
{
  "event": "payout.status.changed",
  "public_id": "PO-1d7c9e20ab45f318",
  "status": "Canceled",
  "merchant_request_id": "payout-777",
  "kind": "payout",
  "method": "c2c",
  "rub_amount": "12000.00",
  "actual_amount": null,
  "amount_mismatch": false,
  "completed_at": null,
  "canceled_at": "2026-09-23T09:20:05.030Z",
  "sent_at": "2026-09-23T09:20:05.311Z"
}
ПолеFieldОписаниеDescription
eventpayin.status.changed | payout.status.changed
public_idID заявки в SlipstreamSlipstream request ID
statusConfirmed | Canceled
merchant_request_idВаш ID или null, если не передавалсяYour ID, or null if not provided
kindpayin | payout
methodКод метода оплаты.Payment method code.
rub_amountСумма заявки (номинал), RUB.Request (nominal) amount, RUB.
actual_amountФактически оплаченная сумма, если при подтверждении она отличалась от rub_amount; иначе null. Зачисление идёт по фактической сумме.Actually paid amount if it differed from rub_amount at confirmation; otherwise null. Settlement uses the actual amount.
amount_mismatchtrue, если actual_amount отличается от rub_amount.true if actual_amount differs from rub_amount.
completed_atВремя подтверждения (для Confirmed), иначе null.Confirmation time (for Confirmed), otherwise null.
canceled_atВремя отмены (для Canceled), иначе null.Cancellation time (for Canceled), otherwise null.
sent_atВремя отправки этой попытки, ISO 8601 UTC.Time this attempt was sent, ISO 8601 UTC.

Тело: test

Body: test

body
{
  "event": "test",
  "merchant_id": "42",
  "ts": "2026-09-23T09:00:00.000Z",
  "sent_at": "2026-09-23T09:00:00.000Z"
}

Проверка подписи

Signature verification

signature
X-Signature-V2 = hex( HMAC_SHA256( YOUR_HMAC_SECRET, X-Timestamp + "." + raw_body ) )
X-Signature    = hex( HMAC_SHA256( YOUR_HMAC_SECRET, raw_body ) )   // переходный период / transition period

Тело отправляется уже в каноническом виде (ключи отсортированы, без пробелов), поэтому подписывайте сырое тело запроса как есть — до парсинга JSON. Алгоритм проверки: (1) |now − X-Timestamp| ≤ 300 секунд, иначе отклонить — это защита от повторного воспроизведения; (2) посчитать HMAC от X-Timestamp + "." + raw_body и сравнить с X-Signature в константное время; (3) дедуплицировать по X-Delivery-Id. Часы сервера синхронизируйте по NTP.

The body is already sent in canonical form (sorted keys, no whitespace), so sign the raw request body as-is — before parsing JSON. Verification: (1) |now − X-Timestamp| ≤ 300 seconds, otherwise reject — this is replay protection; (2) compute HMAC over X-Timestamp + "." + raw_body and compare with X-Signature in constant time; (3) deduplicate by X-Delivery-Id. Keep your server clock NTP-synced.

webhook.js
const crypto = require('crypto');
const express = require('express');
const app = express();
const SECRET = 'YOUR_HMAC_SECRET';
const WINDOW_SEC = 300;

// raw body: the signature is computed over the exact bytes we sent
app.post('/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
  const raw = req.body.toString('utf8');
  const ts = Number(req.get('X-Timestamp'));
  if (!Number.isFinite(ts) || Math.abs(Date.now() / 1000 - ts) > WINDOW_SEC) {
    return res.status(401).end(); // stale or missing timestamp — possible replay
  }
  const expected = Buffer.from(crypto.createHmac('sha256', SECRET)
    .update(`${ts}.${raw}`, 'utf8').digest('hex'));
  const got = Buffer.from(String(req.get('X-Signature-V2') || ''));
  if (got.length !== expected.length || !crypto.timingSafeEqual(got, expected)) {
    return res.status(401).end();
  }

  const deliveryId = req.get('X-Delivery-Id');
  if (await alreadyProcessed(deliveryId)) return res.status(200).json({ ok: true });

  const body = JSON.parse(raw);
  switch (body.event) {
    case 'payin.requisites.issued': await showRequisites(body.merchant_request_id, body.requisites); break;
    case 'payin.status.changed':
    case 'payout.status.changed':  await applyStatus(body.merchant_request_id, body.public_id, body.status, body.actual_amount); break;
  }
  await markProcessed(deliveryId);
  res.status(200).json({ ok: true });
});
webhook.py
import hashlib, hmac, json, time
from flask import Flask, request, abort

app = Flask(__name__)
SECRET = b"YOUR_HMAC_SECRET"
WINDOW_SEC = 300

@app.post("/webhook")
def webhook():
    raw = request.get_data()  # exact bytes as sent
    try:
        ts = int(request.headers.get("X-Timestamp", ""))
    except ValueError:
        abort(401)
    if abs(time.time() - ts) > WINDOW_SEC:
        abort(401)  # stale timestamp — possible replay
    expected = hmac.new(SECRET, f"{ts}.".encode() + raw, hashlib.sha256).hexdigest()
    if not hmac.compare_digest(expected, request.headers.get("X-Signature-V2", "")):
        abort(401)

    delivery_id = request.headers.get("X-Delivery-Id")
    if already_processed(delivery_id):
        return {"ok": True}, 200

    body = json.loads(raw)
    if body["event"] == "payin.requisites.issued":
        show_requisites(body.get("merchant_request_id"), body["requisites"])
    elif body["event"] in ("payin.status.changed", "payout.status.changed"):
        apply_status(body.get("merchant_request_id"), body["public_id"], body["status"], body.get("actual_amount"))
    mark_processed(delivery_id)
    return {"ok": True}, 200
!

Переход со старой подписи. Сейчас X-Signature — прежняя формула без timestamp (для совместимости), новая с timestamp приходит в X-Signature-V2. Переходите на проверку X-Signature-V2 по сырому телу и X-Timestamp: после миграции мерчантов X-Signature будет совпадать с ней.

Migrating from the old signature. For now X-Signature is the previous formula without timestamp (compatibility); the new timestamped one arrives in X-Signature-V2. Switch to verifying X-Signature-V2 over the raw body and X-Timestamp: once merchants migrate, X-Signature will equal it.

Доставка и повторы

Delivery and retries

  • Успех — любой HTTP-ответ 2xx в течение 10 секунд. Всё остальное (другой код, таймаут, ошибка соединения) — повтор.
  • Success — any 2xx HTTP response within 10 seconds. Anything else (other code, timeout, connection error) triggers a retry.
  • Всего до 5 попыток: сразу, затем примерно через 5 с, 30 с, 5 мин и 1 ч. После пятой неудачи доставка прекращается — сверяйте статус через GET /payin/{public_id}.
  • Up to 5 attempts in total: immediately, then after roughly 5 s, 30 s, 5 min and 1 h. After the fifth failure delivery stops — reconcile via GET /payin/{public_id}.
  • У всех повторов одной доставки одинаковые тело (кроме sent_at) и X-Delivery-Id; X-Timestamp и подпись — свежие на каждую попытку.
  • All retries of one delivery share the body (except sent_at) and X-Delivery-Id; X-Timestamp and the signature are fresh on every attempt.
  • Финальный вебхук записывается атомарно со сменой статуса и не теряется при сбоях на нашей стороне. Повторную отправку можно запустить вручную из кабинета мерчанта (с тем же X-Delivery-Id).
  • The final webhook is recorded atomically with the status change and is not lost on failures on our side. A resend can be triggered manually from the merchant cabinet (with the same X-Delivery-Id).
✓

Рекомендации. Отвечайте 200 быстро и обрабатывайте асинхронно. Обработчик должен быть идемпотентным: храните обработанные X-Delivery-Id, ищите заказ по своему ID (merchant_request_id) и сверяйте public_id. При сомнении — запросите актуальный статус через API.

Recommendations. Reply 200 quickly and process asynchronously. The handler must be idempotent: store processed X-Delivery-Id values, look up the order by your ID (merchant_request_id) and verify public_id. When in doubt, query the current status via API.

12ИдемпотентностьIdempotency

Все POST требуют X-Idempotency-Key — защита от двойного создания заявки при повторах и сетевых сбоях.

Every POST requires X-Idempotency-Key — protection against duplicate requests on retries and network failures.

СитуацияSituationРезультатResult
Новый ключNew keyЗапрос выполняется, ответ сохраняется за ключом.The request is executed, the response is stored under the key.
Тот же ключ + то же телоSame key + same bodyВозвращается сохранённый ответ (тот же HTTP-код и тело), повторного выполнения нет.The stored response is returned (same HTTP code and body), nothing is executed again.
Тот же ключ + другое телоSame key + different body409 Idempotency key reuse with different payload is not allowed
Первый запрос с этим ключом ещё выполняетсяFirst request with this key still in progress409 — подождите и повторитеwait and retry
Нет заголовка или длиннее 128Missing header or longer than 128400 X-Idempotency-Key is required
  • Ключ уникален в рамках вашего аккаунта. Тело сравнивается канонически — порядок ключей не важен.
  • The key is scoped to your account. Bodies are compared canonically — key order does not matter.
  • Ответы 4xx тоже сохраняются: исправив тело, используйте новый ключ.
  • 4xx responses are stored too: after fixing the body, use a new key.
  • Если получили 5xx или таймаут, повтор с тем же ключом может вернуть 409: первый запрос мог быть выполнен. Не создавайте новую заявку вслепую — сверьтесь с кабинетом или поддержкой.
  • If you got a 5xx or a timeout, retrying with the same key may return 409: the first request may have been executed. Do not blindly create a new request — check the cabinet or contact support.
i

merchant_request_id на уникальность не проверяется. Удобная практика — использовать его же как X-Idempotency-Key при создании заявки, а для чеков и отмены — производные ключи (cancel-<public_id>, proof-<public_id>-<n>).

merchant_request_id is not checked for uniqueness. A handy practice is to use it as X-Idempotency-Key when creating a request, and derived keys for receipts and cancel (cancel-<public_id>, proof-<public_id>-<n>).

13ЛимитыLimits

GEThttps://api.slipstream.cash/api/v1/merchant/limits

Актуальные min/max суммы по каждому методу для вашего аккаунта — считаются по реквизитам, которые прямо сейчас могут принять заявку. Значения меняются в течение дня: опрашивайте периодически (например, раз в минуту) и не показывайте покупателю методы с available: false.

Current min/max amounts per method for your account, computed from requisites that can accept a request right now. Values change during the day: poll periodically (e.g. once a minute) and hide methods with available: false from customers.

response 200
{
  "success": true,
  "data": {
    "currency": "RUB",
    "updatedAt": "2026-09-23T09:10:00.000Z",
    "methods": [
      { "code": "c2c", "label": "К2К", "available": true, "sources": 4,
        "min": 100000, "max": 15000000, "minRub": 1000, "maxRub": 150000 },
      { "code": "sbp", "label": "СБП", "available": true, "sources": 2,
        "min": 50000, "max": null, "minRub": 500, "maxRub": null },
      { "code": "deeplink_card", "label": "Deeplink Карта", "available": false, "sources": 0,
        "min": null, "max": null, "minRub": null, "maxRub": null }
    ]
  }
}
ПолеFieldОписаниеDescription
availableМетод подключён вам и сейчас есть хотя бы один доступный источник реквизитов.The method is enabled for you and at least one requisite source is available now.
min, maxВ копейках. max: null — без верхнего лимита на заявку (действует общий максимум API).In kopecks. max: null — no per-request upper limit (the global API maximum still applies).
minRub, maxRubТо же в рублях.Same in RUB.
sourcesКоличество доступных источников реквизитов.Number of available requisite sources.

В список входят все включённые в системе методы; неподключённые вам отдаются с available: false.

The list contains all methods enabled in the system; those not enabled for you come with available: false.

Технические лимиты API

Technical API limits

Максимальная сумма заявкиMax request amount500 000.00 RUB (по умолчанию)(default)
Частота запросовRequest rate120 запросов / 60 с с одного IP, иначе 429120 requests / 60 s per IP, otherwise 429
Окно X-TimestampX-Timestamp window±300 s
Размер JSON-телаJSON body size256 KB → 413
Чеки (multipart)Receipts (multipart)до 5 файлов × 10 МБup to 5 files × 10 MB
Срок жизни заявкиRequest lifetime10 минут (по умолчанию), затем автоотмена → Canceled10 minutes (default), then auto-cancel → Canceled

14ДиспутыDisputes

POSThttps://api.slipstream.cash/api/v1/merchant/disputesX-Idempotency-Key
GEThttps://api.slipstream.cash/api/v1/merchant/disputes/{dispute_id}

Покупатель утверждает, что оплатил, а заявка не подтверждена? Откройте диспут и приложите чек через POST /payin/proof к той же заявке.

The customer says they paid but the request isn't confirmed? Open a dispute and attach the receipt via POST /payin/proof to the same request.

request
{ "public_id": "PI-3f9a1c7e5b2d4a60", "reason": "Клиент оплатил 5000 ₽ в 11:42, чек приложен" }
response 200
{
  "success": true,
  "data": {
    "dispute_id": "57",
    "public_id": "PI-3f9a1c7e5b2d4a60",
    "status": "open",
    "reason": "Клиент оплатил 5000 ₽ в 11:42, чек приложен",
    "note": null,
    "resolved_at": null,
    "deadline_at": "2026-10-07T09:20:00.000Z",
    "created_at": "2026-09-23T09:20:00.000Z"
  }
}
  • reason — от 3 до 2000 символов. Срок рассмотрения — 14 дней (deadline_at).
  • reason — 3 to 2000 chars. Review deadline — 14 days (deadline_at).
  • Статусы: open → in_progress → won (платёж признан, заявка подтверждается — придёт вебхук Confirmed) или rejected.
  • Statuses: open → in_progress → won (payment accepted, the request is confirmed — a Confirmed webhook follows) or rejected.
  • По подтверждённой заявке диспут не открыть (409); на заявку может быть только один активный диспут (409).
  • No dispute on a confirmed request (409); only one active dispute per request (409).

15Коды ошибокError codes

Формат ошибки единый. Для ошибок валидации дополнительно приходит массив errors вида "поле: сообщение".

The error format is uniform. Validation errors additionally include an errors array of "field: message".

response 400
{
  "success": false,
  "error": "client_amount: client_amount must be a positive decimal string",
  "errors": [
    "client_amount: client_amount must be a positive decimal string"
  ]
}
HTTPПримеры errorerror examplesЧто делатьWhat to do
400<field>: …
(root): Either client_bank or client_bank_code is required
Метод «sbp» не подключён для этого мерчанта
client_amount exceeds max (500000.00 RUB)
X-Idempotency-Key is required
Этот метод требует чек в формате PDF
Исправьте запрос; повторяйте с новым ключом идемпотентности.Fix the request; retry with a new idempotency key.
401Authorization header is required
Invalid token
X-Timestamp is required
Timestamp is outside the allowed window
X-Signature is required
Invalid signature
Проверьте ключ, часы сервера (NTP), строку подписи.Check the key, server clock (NTP), signing string.
403Merchant is disabled
IP x.x.x.x не подтвержден для мерчанта.
CUSTOMER_ACCESS_DENIED, CUSTOMER_PAUSED
Свяжитесь с менеджером / добавьте IP.Contact your manager / add the IP.
404Request not found, Dispute not foundПроверьте public_id и направление (payin/payout).Check public_id and direction (payin/payout).
409Cannot cancel request in terminal status …
Request state changed, cannot cancel
Cannot attach proof to canceled request
Idempotency key reuse with different payload is not allowed
Запросите статус заявки; про ключ — см. Идемпотентность.Query the request status; for keys see Idempotency.
413Request body too large
file too large (…)
Уменьшите тело; для файлов используйте multipart.Reduce the body; use multipart for files.
424Receipts were saved on our side, but provider rejected them: …Чек сохранён, но отклонён исполнителем — проверьте файл и повторите с новым ключом.Receipt saved but rejected by the executor — check the file and retry with a new key.
429Too many requestsСнизьте частоту, повторите позже.Reduce the rate, retry later.
5xxInternal server errorВременная ошибка. Для создания заявки — не создавайте новую вслепую (см. Идемпотентность).Temporary error. For request creation — do not blindly create a new one (see Idempotency).

16Справочник банковBank reference

Коды для client_bank. Регистр не важен. any — любой банк. Список может расширяться; неизвестный код не вызывает ошибку, но может сузить подбор реквизита.

Codes for client_bank. Case-insensitive. any — any bank. The list may grow; an unknown code does not raise an error but may narrow requisite selection.

СберSbersber
Т-Банкtinkoff
Альфа-БанкAlfa-Bankalfa
ВТБVTBvtb
ПСБPSBpsb
СовкомбанкSovcombanksovcombank
Ozon БанкOzon Bankozon
Яндекс БанкYandex Bankyandex
WB БанкWB Bankwb
ПСКБPSKBpskb
Ренессанс БанкRenaissance Bankrenesans_bank
РокетбанкRocketbankrocket_bank
Банк Санкт-ПетербургBank Saint Petersburgbankspb
Банк ДОМ.РФDOM.RF Bankdomrf
Ак БарсAk Barsakbars
СевергазбанкSevergazbanksevergazbank
ГазэнергобанкGazenergobankgazenergobank
Банк ДолинскBank Dolinskbankdolinsk
БКС БанкBCS Bankbcs
СолидарностьSolidarnostsolidarnost
Русский СтандартRussian Standardrsb
ХайсHisehise
РайффайзенRaiffeisenraiffeisen
УралсибUralsiburalsib
ББР БанкBBR Bankbbr
РоссельхозбанкRosselkhozbankrosselkhoz
МТС БанкMTS Bankmts
Ингосстрах БанкIngosstrakh Bankingostrah
ОТП БанкOTP Bankotp
ЗенитZenitzenit
ЭтрансEtransetrans
Локо-БанкLoko-Banklocko
ЮMoneyYooMoneyyoomoney
НС БанкNS Banknskbl
ГазпромбанкGazprombankgazprombank
SIM БилайнSIM Beelinesim_beeline
SIM МТСSIM MTSsim_mts
SIM Теле2SIM Tele2sim_tele2

Коды sim_* — только для метода sim.

sim_* codes are for the sim method only.

17FAQ

Сколько живёт заявка?How long does a request live?

По умолчанию 10 минут с момента создания. Если за это время платёж не подтверждён, заявка автоматически переходит в Canceled и приходит вебхук. Если оплата всё же поступила позже, заявку могут подтвердить — придёт вебхук Confirmed.

By default 10 minutes from creation. If the payment is not confirmed in that time, the request is automatically set to Canceled and a webhook is sent. If the payment arrives later, the request can still be confirmed — a Confirmed webhook follows.

Покупатель перевёл не ту сумму — что будет?The customer paid a different amount — what happens?

При подтверждении фиксируется фактически полученная сумма. Если расхождение меньше 200 ₽ (по умолчанию) — заявка закрывается на исходную сумму; если больше — расчёт идёт по фактической сумме. Фактическая сумма возвращается в GET /payin/{public_id} и GET /payout/{public_id} в поле actual_amount с флагом amount_mismatch: true; rub_amount остаётся суммой заявки.

On confirmation the actually received amount is recorded. If the difference is under 200 RUB (default), the request closes at the original amount; otherwise settlement uses the actual amount. The actual amount is returned by GET /payin/{public_id} and GET /payout/{public_id} in actual_amount with amount_mismatch: true; rub_amount stays the request amount.

Можно ли повторно получить реквизиты?Can I fetch the requisites again?

Да: GET /payin/{public_id} возвращает requisites (в том же формате, что и при создании) и expires_at, пока заявка открыта. После Confirmed/Canceled — requisites: null. Ещё вариант — повторить тот же POST /requests с тем же X-Idempotency-Key и телом.

Yes: GET /payin/{public_id} returns requisites (same format as on create) and expires_at while the request is open. After Confirmed/Canceled — requisites: null. Alternatively, repeat the same POST /requests with the same X-Idempotency-Key and body.

В ответе нет requisites. Что делать?There's no requisites in the response. What now?

Сейчас нет свободного реквизита под этот метод/банк/сумму. Отмените заявку (POST /payin/cancel) и предложите покупателю другой метод или сумму; сверьтесь с GET /limits.

No free requisite for this method/bank/amount right now. Cancel the request (POST /payin/cancel) and offer another method or amount; check GET /limits.

Нужно ли присылать чек?Do I need to upload a receipt?

Для sbp_check и card_check — да, в PDF, иначе платёж не будет засчитан. Для остальных методов — нет, но чек ускоряет разбор спорных платежей.

For sbp_check and card_check — yes, as PDF, otherwise the payment is not credited. For other methods — no, but a receipt speeds up disputed cases.

Пришёл Canceled, а потом Confirmed. Это ошибка?I got Canceled and then Confirmed. Is that a bug?

Нет. Так выглядит позднее подтверждение: заявка истекла по времени, но оплата поступила и была подтверждена. Confirmed — окончательный результат.

No. That's a late confirmation: the request expired by time, but the payment arrived and was confirmed. Confirmed is the final outcome.

Вебхук не дошёл — как узнать статус?The webhook didn't arrive — how do I get the status?

Мы делаем до 5 попыток в течение примерно часа. Если ваш сервер был недоступен дольше — запросите GET /payin/{public_id} (или /payout/…) либо перешлите вебхук из кабинета. Рекомендуем периодически сверять «зависшие» заказы через API.

We make up to 5 attempts over roughly one hour. If your server was down longer, call GET /payin/{public_id} (or /payout/…) or resend the webhook from the cabinet. We recommend periodically reconciling “stuck” orders via API.

Чем отличаются /requests и /requests/simple?What's the difference between /requests and /requests/simple?

Сейчас ничем: это один обработчик с одинаковой схемой тела. /requests/simple оставлен для совместимости.

Nothing at the moment: it's the same handler with the same body schema. /requests/simple is kept for compatibility.

© Slipstream · Merchant API v1 Вопросы по интеграции — вашему менеджеру.Integration questions — contact your manager.