Silicon Souk — Merchant API
Платформа
Silicon Souk — сервис по обработке и проведению платежей. Мы поддерживаем как PayIn, так и PayOut по всем методам в перечисленных ниже регионах.
Проекты и ключи
У мерчанта есть один или несколько проектов. Каждый запрос валидируется и сопоставляется с проектом по приватному API-ключу проекта — этого подписанного ключа достаточно; валюту, окружение и методы мы читаем уже из самого проекта.
Вы получаете public_key и private_key. Private key не передаётся в теле запроса — только в виде хеша sign. Для GET-статуса, client-status и загрузки чеков отправляйте private key в заголовке X-Api-Key поверх HTTPS.
card | sbp | account | ibanПодпись запроса
Для create / reject передайте sign = SHA256(order_id:public_key:private_key) (hex, lowercase). Мы аутентифицируем мерчанта, проверяем IP-whitelist (если настроен) и сопоставляем заявку с проектом.
Production: заголовок X-Body-Signature обязателен для каждого запроса Merchant API, включая GET и multipart-загрузку чеков. Это hex в нижнем регистре: HMAC-SHA256(private_key, "v1|METHOD|PATH|RAW_BODY"). RAW_BODY — точная последовательность байтов, отправленная по сети; для GET это пустая строка байтов. Нельзя канонизировать или повторно сериализовать JSON.
import hashlib
def merchant_sign(order_id: str, public_key: str, private_key: str) -> str:
return hashlib.sha256(f"{order_id}:{public_key}:{private_key}".encode()).hexdigest()
def standart_sign(order_id: str, public_key: str, private_key: str) -> str:
return hashlib.sha256(f"{order_id}:{public_key}:{private_key}:callback".encode()).hexdigest()import hmac
def body_hmac(private_key: str, method: str, path: str, raw_body: bytes) -> str:
message = b"v1|" + method.upper().encode() + b"|" + path.encode() + b"|" + raw_body
return hmac.new(private_key.encode(), message, "sha256").hexdigest()POST /create_payin
Создание заявки PayIn. При успехе — HTTP 200 с реквизитами, которые надо показать клиенту. Финальный статус (successful, cancelled, failed, rejected_*) приходит коллбэком.
Если реквизиты не удалось выдать в течение ~10 секунд — отвечаем 503 с "error": "overloading requisite". Не считайте заказ активным, попробуйте позже с новым order_id.
| Поле | Тип | Описание | |
|---|---|---|---|
| order_id | string | Обязательно | Ваш id заказа, уникален на мерчанта. |
| payment_method | enum | Обязательно | card | sbp | account | iban. |
| fiat_amount | string | Обязательно | Сумма как строка, напр. "15000.00". |
| fiat_currency | string | Обязательно | ISO-код, напр. "RUB". |
| bank | string | Обязательно | Банк-получатель. Каноническое имя из справочника банков (например, "Сбербанк"). Строго регистронезависимо; английские алиасы («Sberbank») отклоняются. |
| sign | string | Обязательно | SHA256(order_id:public_key:private_key) hex. |
| success_callback_url | url | Обязательно | URL, куда придёт коллбэк об успехе. |
| error_callback_url | url | Необязательно | URL для коллбэков ошибок/отмен. |
| timeout | int (мин) | Необязательно | Время жизни заявки в минутах. |
| customer | string | Необязательно | Ваш id клиента (свободный формат). |
| order_description | string | Необязательно | Произвольное описание. |
POST https://ssouk.org/applications/v1/create_payin
Content-Type: application/json
{
"order_id": "ORD-1001",
"payment_method": "card",
"fiat_amount": "15000.00",
"fiat_currency": "RUB",
"bank": "Сбербанк",
"timeout": 900,
"sign": "<sha256_hex>",
"success_callback_url": "https://merchant.example/cb/success",
"error_callback_url": "https://merchant.example/cb/error",
"customer": "user-42",
"order_description": "Deposit #1001"
}HTTP/1.1 200 OK
{
"ok": true,
"internal_transaction_id": "TRX-20260528-120000-A1B2C3",
"order_id": "ORD-1001",
"payment_method": "card",
"fiat_amount": "15000.00",
"fiat_currency": "RUB",
"sum_transaction": "15000.00",
"currency": "RUB",
"usdt_amount": "158.7301",
"merchant_spent_usdt": "160.1234",
"exchange_rate": "94.50",
"number_card": "4276123456785678",
"phone_number": null,
"number_account": null,
"iban_number": null,
"bank": "Сбербанк",
"full_name": "IVAN I.",
"sign": "<response_signature>"
}HTTP/1.1 503
{ "ok": false, "error": "overloading requisite" }POST /reject_payin
Отмена открытой PayIn-заявки. Допустимо, пока заявка не successful и не отклонена. Мы снимаем холд с вашего баланса.
| Поле | Тип | Описание | |
|---|---|---|---|
| order_id | string | Обязательно | id заказа на нашей стороне. |
| standart_sign | string | Обязательно | SHA256(order_id:public_key:private_key:callback) hex. |
POST https://ssouk.org/applications/v1/reject_payin
Content-Type: application/json
{
"order_id": "ORD-1001",
"standart_sign": "<sha256_hex>"
}HTTP/1.1 200 OK
{ "ok": true }POST /set_client_status_payin
Передайте нам, что сказал клиент о платеже: payment_confirmed — оплатил, payment_rejected — отказался. Мы используем это вместе с банковским чеком для финализации заказа.
| Поле | Тип | Описание | |
|---|---|---|---|
| order_id | string | Обязательно | id заказа. |
| status | enum | Обязательно | "payment_confirmed" или "payment_rejected". |
POST https://ssouk.org/applications/v1/set_client_status_payin
X-Api-Key: <private_key>
Content-Type: application/json
{
"order_id": "ORD-1001",
"status": "payment_confirmed"
}HTTP/1.1 200 OK
{
"ok": true,
"order_id": "ORD-1001",
"status_from_client": "payment_confirmed"
}GET /status_payin/{order_id}
Опрос текущего статуса PayIn-заявки в любой момент.
GET https://ssouk.org/applications/v1/status_payin/ORD-1001
X-Api-Key: <private_key>HTTP/1.1 200 OK
{
"ok": true,
"internal_transaction_id": "TRX-1001",
"order_id": "ORD-1001",
"type": "pay_in",
"status": "successful",
"fiat_amount": "15000.00",
"usdt_amount": "158.7301",
"merchant_spent_usdt": "160.1234",
"fiat_currency": "RUB",
"exchange_rate": "94.50",
"payment_method": "card",
"created_at": "2026-05-28T12:00:00Z",
"updated_at": "2026-05-28T12:15:00Z",
"number_card": "4276123456785678",
"phone_number": null,
"number_account": null,
"iban_number": null,
"full_name": "IVAN I.",
"bank": "Сбербанк",
"cheque_urls": null
}POST /create_payout
Создание PayOut-заявки. Мы холдим баланс мерчанта, обрабатываем выплату и присылаем финальный коллбэк с результатом. Поле с реквизитом получателя зависит от payment_method — см. тело запроса ниже.
| Поле | Тип | Описание | |
|---|---|---|---|
| order_id | string | Обязательно | Уникален на мерчанта. |
| payment_method | enum | Обязательно | card | sbp | account | iban. |
| fiat_amount | string | Обязательно | Сумма как строка. |
| fiat_currency | string | Обязательно | ISO-код. |
| bank | string | Обязательно | Банк получателя. Каноническое имя из справочника банков (например, "Т-Банк"). |
| number_card | string | Обязательно | Обязательно при payment_method=card. |
| phone_number | string | Обязательно | Обязательно при payment_method=sbp. Формат +7 (900) 123-45-67 тоже принимаем. |
| number_account | string | Обязательно | Обязательно при payment_method=account. |
| iban_number | string | Обязательно | Обязательно при payment_method=iban. |
| bik | string | Необязательно | БИК банка получателя. |
| full_name | string | Необязательно | ФИО получателя. |
| sign | string | Обязательно | SHA256(order_id:public_key:private_key) hex. |
| success_callback_url | url | Обязательно | URL коллбэка об успехе. |
| error_callback_url | url | Обязательно | URL коллбэка ошибки. |
| timeout | int (мин) | Необязательно | Время жизни заявки. |
| customer | string | Необязательно | Ваш id клиента. |
| order_description | string | Необязательно | Произвольное описание. |
POST https://ssouk.org/applications/v1/create_payout
Content-Type: application/json
{
"order_id": "WD-2002",
"payment_method": "sbp",
"fiat_amount": "5000.00",
"fiat_currency": "RUB",
"bank": "Т-Банк",
"phone_number": "79001234567",
"full_name": "IVAN IVANOV",
"sign": "<sha256_hex>",
"success_callback_url": "https://merchant.example/cb/success",
"error_callback_url": "https://merchant.example/cb/error"
}HTTP/1.1 200 OK
{
"ok": true,
"internal_transaction_id": "TRX-20260528-120100-B2C3D4",
"fiat_amount": "5000.00",
"fiat_currency": "RUB",
"usdt_amount": "52.9101",
"merchant_spent_usdt": "53.5670",
"exchange_rate": "94.50",
"payment_method": "sbp",
"reject_callback_url": "https://merchant.example/cb/error"
}POST /reject_payout
Отмена PayOut, пока заявка не successful и не отклонена. Мы снимаем холд с вашего баланса.
| Поле | Тип | Описание | |
|---|---|---|---|
| order_id | string | Обязательно | id заказа на нашей стороне. |
| standart_sign | string | Обязательно | SHA256(order_id:public_key:private_key:callback) hex. |
POST https://ssouk.org/applications/v1/reject_payout
Content-Type: application/json
{
"order_id": "WD-2002",
"standart_sign": "<sha256_hex>"
}HTTP/1.1 200 OK
{ "ok": true }POST /set_client_status_payout (необязательно)
Необязательно. Используйте этот запрос, только если хотите вручную зафиксировать у себя реакцию клиента на выплату. Заявка финализируется и без него.
| Поле | Тип | Описание | |
|---|---|---|---|
| order_id | string | Обязательно | id заказа. |
| status | enum | Обязательно | "payment_confirmed" или "payment_rejected". |
POST https://ssouk.org/applications/v1/set_client_status_payout
X-Api-Key: <private_key>
Content-Type: application/json
{
"order_id": "WD-2002",
"status": "payment_confirmed"
}HTTP/1.1 200 OK
{
"ok": true,
"order_id": "WD-2002",
"status_from_client": "payment_confirmed"
}GET /status_payout/{order_id}
Опрос текущего статуса PayOut-заявки в любой момент.
GET https://ssouk.org/applications/v1/status_payout/WD-2002
X-Api-Key: <private_key>HTTP/1.1 200 OK
{
"ok": true,
"internal_transaction_id": "TRX-2002",
"order_id": "WD-2002",
"type": "pay_out",
"status": "successful",
"fiat_amount": "5000.00",
"usdt_amount": "52.9101",
"merchant_spent_usdt": "53.5670",
"fiat_currency": "RUB",
"exchange_rate": "94.50",
"payment_method": "sbp",
"created_at": "2026-05-28T12:01:00Z",
"updated_at": "2026-05-28T12:05:00Z",
"number_card": null,
"phone_number": "79001234567",
"number_account": null,
"iban_number": null,
"full_name": "IVAN IVANOV",
"bank": "Т-Банк",
"cheque_urls": [
"https://ssouk.org/applications/v1/receipts/9b2c8b1e-1234-4bcd-8ef0-000000000001"
]
}GET /get_balance_payin / GET /get_balance_payout
Текущий свободный + захолдированный баланс по каждому проекту. Полезно для дашбордов и предварительной проверки перед крупным PayOut.
GET https://ssouk.org/applications/v1/get_balance_payin
X-Api-Key: <private_key>
GET https://ssouk.org/applications/v1/get_balance_payout
X-Api-Key: <private_key>HTTP/1.1 200 OK
{
"ok": true,
"type": "pay_in",
"balance": "10240.5500",
"hold_balance": "320.0000",
"available": "9920.5500",
"currency": "USDT",
"projects": [
{
"id": "9b2c8b...",
"name": "RUB / card",
"balance": "10240.5500",
"hold_balance": "320.0000"
}
]
}Исходящие коллбэки
POST JSON на success_callback_url / error_callback_url. Проверяйте подпись standart_sign = SHA256(order_id:public_key:private_key:callback). Ответьте HTTP 2xx — любой другой ответ считается ошибкой доставки, мы повторим с экспоненциальной задержкой (до 10 попыток). В каждом коллбэке приходит полный снимок заявки: order_id, internal_transaction_id, type, status, fiat_amount/fiat_currency, usdt_amount, merchant_spent_usdt, exchange_rate, payment_method, created_at/updated_at, реквизитные поля (number_card, phone_number, number_account, iban_number), full_name, bank. Для PayOut дополнительно cheque_urls (legacy массив URL) и receipts (типизированные объекты: id, url, file_name, content_type, size_bytes, uploaded_at, check_status, source). Изменение суммы. Если по заявке администратор изменил сумму, во все последующие коллбэки по этой заявке добавляются четыре поля: old_fiat_amount, new_fiat_amount, old_usdt_amount, new_usdt_amount. old_* — самая первая сумма заявки (не переписывается при повторных правках), new_* совпадает с текущими fiat_amount / usdt_amount в этом же теле. Наша комиссия (merchant_spent_usdt) пересчитывается по новой сумме и приезжает в этом же payload.
POST https://merchant.example/cb/success
Content-Type: application/json
{
"order_id": "ORD-1001",
"internal_transaction_id": "TRX-1001",
"standart_sign": "<callback_sign>",
"type": "pay_in",
"status": "successful",
"fiat_amount": "15000.00",
"usdt_amount": "158.7301",
"merchant_spent_usdt": "160.1234",
"fiat_currency": "RUB",
"exchange_rate": "94.50",
"payment_method": "card",
"number_card": "4276123456785678",
"bank": "Сбербанк",
"full_name": "IVAN I.",
"created_at": "2026-05-28T12:00:00+00:00",
"updated_at": "2026-05-28T12:15:00+00:00"
}В каждом коллбэке отправляем HTTP-заголовок X-Body-Signature — HMAC-SHA256 от тела запроса с вашим private_key. Поле standart_sign в теле подписывает только order_id; X-Body-Signature подписывает весь JSON, включая fiat_amount, status, receipts[]. Проверка не обязательна, но рекомендуется.
import hmac, hashlib, json
def verify(body_bytes: bytes, header_value: str, private_key: str) -> bool:
payload = json.loads(body_bytes)
canonical = json.dumps(payload, sort_keys=True, separators=(",", ":")).encode()
msg = b"cb|v1|" + canonical
expected = hmac.new(private_key.encode(), msg, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, (header_value or "").lower())Значение — hex в нижнем регистре. Каноникализация тела: json.dumps(payload, sort_keys=True, separators=(",", ":")) с префиксом cb|v1|.
Диспуты
Если по PayIn у нас всё «оплачено», но мерчант сообщает, что клиент не получил деньги (или наоборот) — открывается диспут. Деньги остаются захолдированы на вашем счёте до решения.
Если указан error_callback_url, мы пришлём коллбэк со status: "dispute", чтобы ваш бэкофис среагировал автоматически. Альтернатива — связаться с нашей поддержкой и передать internal_transaction_id плюс доказательства.
По итогу диспута холд либо списывается (статус переходит в successful), либо возвращается (статус становится cancelled); в обоих случаях приходит финальный коллбэк.
POST https://merchant.example/cb/error
Content-Type: application/json
{
"order_id": "ORD-1001",
"internal_transaction_id": "TRX-1001",
"standart_sign": "<callback_sign>",
"type": "pay_in",
"status": "dispute",
"fiat_amount": "15000.00",
"fiat_currency": "RUB",
"payment_method": "card",
"created_at": "2026-05-28T12:00:00+00:00",
"updated_at": "2026-05-28T13:30:00+00:00"
}POST /upload_receipt
После оплаты можно загрузить банковский чек: multipart /upload_receipt с X-Api-Key, поля order_id + file (PDF/PNG/JPG до 1 МБ).
POST https://ssouk.org/applications/v1/upload_receipt
X-Api-Key: <private_key>
Content-Type: multipart/form-data
order_id=ORD-1001
file=@receipt.pdfHTTP/1.1 200 OK
{ "ok": true, "url": "https://...your-stored-receipt..." }Маппинг банков
Поле bank — каноническое имя банка получателя. Сравнение нечувствительно к регистру и пробелам по краям. Если банк не распознан, заявка отклоняется с HTTP 400 {"ok": false, "message": "Incorrect bankname", "code": "incorrect_bankname"}.
Загрузка справочника…
HTTP/1.1 400 Bad Request
{
"ok": false,
"message": "Incorrect bankname",
"code": "incorrect_bankname",
"bank": "NotARealBank",
"fiat_currency": "RUB"
}Маппинг валют
Список валют, поддерживаемых в системе, и их отображаемых символов. Значение поля fiat_currency в запросах должно совпадать с колонкой «Код» (регистр не важен). Таблица синхронизирована с разделом «Валюты» в админ-панели — при изменении там она обновляется здесь автоматически.
Загрузка справочника…
Справочник HTTP-ошибок
Каждый провал — один и тот же JSON в проде. Ниже точные строки, которые вернёт бэкенд (не локализуются): грепайте на своей стороне ровно то, что здесь напечатано.
400 — {"ok":false,"message":"Access denied. Invalid method."}
400 — {"ok":false,"message":"Incorrect bankname","code":"incorrect_bankname","bank":"…","fiat_currency":"…"}
400 — {"ok":false,"message":"Cannot reject successful application"}
400 — {"ok":false,"message":"Application already rejected"}
400 — {"ok":false,"message":"Unsupported payment_method: <value>"}
400 — {"ok":false,"message":"X-Merchant-Pub header required"}
400 — {"ok":false,"message":"empty file"}
400 — {"ok":false,"message":"file_too_large"}
400 — {"ok":false,"message":"unsupported file type: <content-type>"}
400 — {"ok":false,"message":"content_does_not_match_type"}
401 — {"ok":false,"message":"Unauthorized. X-Api-Key required"}
401 — {"ok":false,"message":"Unauthorized. Invalid X-Api-Key"}
401 — {"ok":false,"message":"Unauthorized. Invalid signature."}
401 — {"ok":false,"message":"Unauthorized. X-Body-Signature required."}
401 — {"ok":false,"message":"Unauthorized. Body signature mismatch."}
401 — {"ok":false,"message":"Unauthorized. Cannot verify body."}
401 — {"ok":false,"message":"Unauthorized. Replay of signed request rejected."}
402 — {"ok":false,"code":"insufficient_balance","message":"Недостаточно средств на балансе. Пополните баланс и повторите запрос.","message_en":"Insufficient balance. Top up your project balance and retry.","required_usdt":"…"}
403 — {"ok":false,"message":"blocked_merchant"}
403 — {"ok":false,"message":"Access denied. IP address is not allowed."}
403 — {"ok":false,"message":"ip_blocked"}
403 — {"ok":false,"message":"not your receipt"}
404 — {"ok":false,"message":"application not found"}
404 — {"ok":false,"message":"merchant_not_found"}
404 — {"ok":false,"message":"receipt not found"}
409 — {"ok":false,"message":"Application with id [<order_id>] already in work"}
410 — {"ok":false,"message":"file no longer available"}
413 — {"ok":false,"message":"request_entity_too_large"}
422 — {"ok":false,"message":"Invalid request","errors":[{"type","loc","msg"},…]}
422 — {"ok":false,"message":"Invalid fiat_amount: '<value>'"}
429 — {"ok":false,"message":"rate_limited"}
429 — {"ok":false,"message":"rate_limited_per_merchant"}
503 — {"ok":false,"error":"overloading requisite"}
503 — {"ok":false,"message":"replay_store_unavailable"}Статусы заявок в коллбэках
Жизненный цикл: pending → processing → successful. Негативные исходы: rejected_gate (несовпадение проекта/суммы), rejected_merchant (вы отменили), rejected_timeout (нет реквизитов), cancelled (отмена администратором), failed (ошибка обработки), dispute (на разборе — см. раздел Диспуты).
Песочница
Выберите эндпоинт и сценарий ответа — увидите пример тела запроса, который мы бы отправили, и пример JSON-ответа, который вернётся в этом сценарии.
{
"order_id": "ORD-SANDBOX-1",
"payment_method": "card",
"fiat_amount": "1500.00",
"fiat_currency": "RUB",
"bank": "Сбербанк",
"timeout": 900,
"success_callback_url": "https://merchant.example/cb/success",
"error_callback_url": "https://merchant.example/cb/error",
"customer": "user-42",
"sign": "<sha256_hex>"
}Выберите эндпоинт и сценарий, чтобы увидеть пример ответа.