Перейти к содержанию

Матчинг: перевод с чеком

Матчинг (иногда пишут «метчинг», англ. matching) — перевод на карту или по СБП, который провайдер зачисляет только по чеку плательщика. Плательщик переводит на выданные реквизиты, вы присылаете файл чека, провайдер сверяет его с поступлением и подтверждает оплату. Заявка устроена так же, как приём по карте и приём по СБП: тот же запрос, те же статусы, callback-и и правила повторов. Отличаются payment_method и шаг с чеком.

Перевод на карту Перевод на карту (матчинг) СБП СБП (матчинг)
payment_method card_transfer card_matching sbp sbp_matching
Что получает плательщик номер карты номер карты номер телефона номер телефона
Чек после перевода не нужен нужен не нужен нужен

Методы матчинга — отдельные методы договора: у них свои условия, подключает их менеджер. Метод, которого нет в договоре проекта, — 422 payment_not_covered.

Как проходит оплата

  1. Ваш сервер → APIPOST /api/v1/payments с payment_method=card_matching или sbp_matching
  2. API ⇢ Ваш сервер201: status=processing, requisite, holder_name
  3. Ваш сервер → ПлательщикРеквизиты, сумма, срок и просьба приложить чек
  4. ПлательщикПереводит и сохраняет чек (PDF или скриншот из приложения банка)
  5. Ваш сервер → APIPOST /api/v1/payments/{id}/receipt с файлом чека
  6. API ⇢ Ваш сервер201: чек принят, status=pending
  7. APIПередаёт чек провайдеру, провайдер сверяет оплату
  8. API → Ваш серверCallback: completed или canceled

Чек не меняет ни статус, ни сумму заявки: итог приходит обычным callback-ом. Без чека провайдер отменит заявку по сроку — придёт callback canceled.

Создать заявку

POST /api/v1/payments с payment_method: "card_matching" или "sbp_matching". Запрос подписывается так же, как для СБП, поля — те же, см. Приём по СБП → Поля запроса.

{
  "merchant_payment_id": "order-1005",
  "amount": "5000.00",
  "payment_method": "card_matching"
}

Ответ 201 Created — такой же, как у перевода на карту (у sbp_matching — как у СБП):

{
  "id": "3f1c2b9e-6a8d-4c4b-9a71-2c7f5d1e0a42",
  "merchant_payment_id": "order-1005",
  "status": "processing",
  "amount": 5000,
  "initial_amount": 5000,
  "currency": "RUB",
  "geo_code": "RU",
  "payment_method": "card_matching",
  "bank_code": null,
  "is_intrabank": false,
  "requisite": "2200123456789010",
  "requisite_bank": "Сбер",
  "holder_name": "Мария П.",
  "created_at": "2026-10-23T09:30:00Z",
  "updated_at": "2026-10-23T09:30:01Z"
}
  • requisite — номер карты (card_matching) или номер телефона (sbp_matching);
  • holder_name, requisite_bank — получатель и его банк;
  • id — понадобится для загрузки чека.

Что показать плательщику

Всё, что для карты или СБП: реквизит с кнопкой «Скопировать», получатель, ровно amount и обратный отсчёт срока. Дополнительно:

  • Загрузка чека. После перевода попросите плательщика приложить чек — PDF или скриншот из приложения банка, где видны сумма, дата и получатель.
  • Предупреждение. Без чека оплата не будет зачислена, а заявка отменится по сроку.

Прислать чек

POST {{base_url}}/api/v1/payments/{id}/receipt — загрузка чека заявки. Право токена payments:create, подпись обязательна всегда.

Тело multipart/form-data, ровно одно поле — файл receipt. Других полей нет
Файл JPG, PNG или PDF — тип проверяется по содержимому, а не по расширению
Размер файл до 5 МБ, тело до 5 МБ плюс 64 КБ — независимо от лимита тела проекта
Рекомендация файл не больше 200 КБ: часть провайдеров больший файл не принимает, и такой чек до провайдера не дойдёт
Подпись Content-Digest — SHA-256 точных байтов multipart-тела, как оно уходит в запрос
Сколько чеков один на заявку

Когда чек принимается:

  • метод заявки — card_matching или sbp_matching;
  • заявка не тестовая (is_test: false);
  • заявка в статусе processing, и реквизиты уже выданы.
POST {{base_url}}/api/v1/payments/3f1c2b9e-6a8d-4c4b-9a71-2c7f5d1e0a42/receipt HTTP/1.1
Authorization: Bearer nl_live_...
Content-Type: multipart/form-data; boundary=receipt-7d1f0c
Content-Digest: sha-256=:…:
X-Request-ID: 6a1e7c3b-2d4f-4b8a-9c0d-1e2f3a4b5c6d
X-Request-Nonce: 2c26b46b68ffc68ff99b453c1d304134
Signature-Input: sig1=(…);created=…;expires=…;keyid="ed25519-…";alg="ed25519"
Signature: sig1=:…:

--receipt-7d1f0c
Content-Disposition: form-data; name="receipt"; filename="чек.pdf"
Content-Type: application/pdf

<байты файла>
--receipt-7d1f0c--

Подписывайте те же байты, что отправляете. Удобнее всего собрать multipart-тело самому, с известным boundary, посчитать по нему подпись и отправить тело как есть. Пример на Python с функцией sign_request из готовых функций подписи:

import os
import secrets
import urllib.request

from sign import load_private_key, sign_request

payment_id = "3f1c2b9e-6a8d-4c4b-9a71-2c7f5d1e0a42"
url = os.environ["BASE_URL"].rstrip("/") + f"/api/v1/payments/{payment_id}/receipt"

with open("receipt.pdf", "rb") as f:
    content = f.read()
boundary = "receipt-" + secrets.token_hex(8)
body = (
    f"--{boundary}\r\n"
    'Content-Disposition: form-data; name="receipt"; filename="receipt.pdf"\r\n'
    "Content-Type: application/pdf\r\n\r\n"
).encode() + content + f"\r\n--{boundary}--\r\n".encode()

with open(os.environ["SIGNING_KEY_FILE"], "rb") as f:
    key = load_private_key(f.read())
headers = sign_request("POST", url, body, key, os.environ["SIGNING_KEY_ID"])
headers["Authorization"] = "Bearer " + os.environ["API_TOKEN"]
headers["Content-Type"] = f"multipart/form-data; boundary={boundary}"

request = urllib.request.Request(url, data=body, headers=headers, method="POST")
with urllib.request.urlopen(request, timeout=30) as response:
    print(response.status, response.read().decode())

Ответ

201 Created — чек принят и передаётся провайдеру:

{
  "payment_id": "3f1c2b9e-6a8d-4c4b-9a71-2c7f5d1e0a42",
  "status": "pending",
  "file_name": "чек.pdf",
  "sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
  "created_at": "2026-10-23T09:41:00Z"
}
Поле Что значит
payment_id id заявки
status доставка чека провайдеру: pending, sent, failed — см. ниже
file_name имя файла; оно очищается, расширение приводится к содержимому
sha256 SHA-256 файла, hex
created_at когда чек принят, UTC

Повтор безопасен. Тот же файл ещё раз (тот же sha256) — 200 OK с уже принятым чеком. Если ответа не было (таймаут, обрыв), отправьте тот же файл с новыми nonce и подписью. Другой файл, когда чек уже есть, — 409 payment_receipt_exists.

Ошибки

HTTP error Когда Что делать
400 invalid_payment_receipt Тело не multipart/form-data, нет файла receipt, есть другое поле или поле повторяется Исправить запрос
400 attachment_type_not_allowed Файл по содержимому не JPG, PNG и не PDF Прислать JPG, PNG или PDF
404 payment_not_found Заявки нет, она другого проекта или id не UUID Проверить id
409 payment_receipt_not_allowed Чек сейчас не принимается, причина — в reason (таблица ниже) По причине
409 payment_receipt_exists У заявки уже есть другой чек Второй чек не нужен; статус — GET …/receipt
409 attachment_limit_reached У заявки уже 20 файлов Связаться с поддержкой
409 request_replayed Этот X-Request-Nonce уже был Повторить с новым nonce и подписью
413 request_too_large Тело больше 5 МБ плюс 64 КБ или файл больше 5 МБ Уменьшить файл

Общие ошибки (401, 403, 429, 500, 503) — как у остальных запросов, см. Статусы и ошибки.

{"error": "payment_receipt_not_allowed", "reason": "payment_not_processing"}
reason Почему
not_matching_method Метод заявки — не card_matching и не sbp_matching: чек не нужен
test_payment Заявка тестовая — чеки к тестовым заявкам не принимаются
payment_not_processing Заявка уже закрыта (не processing)
requisites_not_issued Реквизиты ещё не выданы

Если заявка уже закрылась canceled, а плательщик оплатил, — это не чек матчинга, а апелляция: POST /api/v1/payments/{id}/disputes.

Статус чека

GET {{base_url}}/api/v1/payments/{id}/receipt — чек заявки и его доставка провайдеру. Право payments:read; подпись — только если её требует политика проекта (signature_required). Ответ 200 — тот же объект, что при загрузке. Ошибки: 404 payment_not_found — такой заявки в проекте нет, 404 payment_receipt_not_found — у заявки нет чека.

Статусы чека

status Что значит
pending Чек принят, передаём провайдеру (при сбое связи — с повторами)
sent Провайдер принял чек
failed Провайдер не принял чек; сотрудники отправят его ещё раз

Статус чека — это только доставка файла. Оплачена ли заявка, говорит статус заявки и callback.

Статусы и результат

Статусы заявки, callback-и и опрос — такие же, как у СБП: Статусы и Как узнать результат.

  • Провайдер подтвердил оплату по чеку — callback completed. Сумма в amount может отличаться от initial_amount, если оплату подтвердили на другую сумму.
  • Чек не прислали или оплата не подтвердилась до срока — callback canceled.

Песочница

Тестовые заявки (is_test: true) с методами матчинга создаются и закрываются, как в песочнице: исход задаёт сумма. Чек к тестовой заявке не принимается — 409 payment_receipt_not_allowed с reason: "test_payment". Так можно проверить разбор ошибки загрузки чека.

Смотрите также