Silicon SoukMerchant API

Платформа

Silicon Souk — сервис по обработке и проведению платежей. Мы поддерживаем как PayIn, так и PayOut по всем методам в перечисленных ниже регионах.

Проекты и ключи

У мерчанта есть один или несколько проектов. Каждый запрос валидируется и сопоставляется с проектом по приватному API-ключу проекта — этого подписанного ключа достаточно; валюту, окружение и методы мы читаем уже из самого проекта.

Вы получаете public_key и private_key. Private key не передаётся в теле запроса — только в виде хеша sign. Для GET-статуса, client-status и загрузки чеков отправляйте private key в заголовке X-Api-Key поверх HTTPS.

payment_method
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.

Python
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()
X-Body-Signature
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_idstringОбязательноВаш id заказа, уникален на мерчанта.
payment_methodenumОбязательноcard | sbp | account | iban.
fiat_amountstringОбязательноСумма как строка, напр. "15000.00".
fiat_currencystringОбязательноISO-код, напр. "RUB".
bankstringОбязательноБанк-получатель. Каноническое имя из справочника банков (например, "Сбербанк"). Строго регистронезависимо; английские алиасы («Sberbank») отклоняются.
signstringОбязательноSHA256(order_id:public_key:private_key) hex.
success_callback_urlurlОбязательноURL, куда придёт коллбэк об успехе.
error_callback_urlurlНеобязательноURL для коллбэков ошибок/отмен.
timeoutint (мин)НеобязательноВремя жизни заявки в минутах.
customerstringНеобязательноВаш id клиента (свободный формат).
order_descriptionstringНеобязательноПроизвольное описание.
Тело запроса
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"
}
Ответ 200 OK
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>"
}
503
HTTP/1.1 503

{ "ok": false, "error": "overloading requisite" }

POST /reject_payin

Отмена открытой PayIn-заявки. Допустимо, пока заявка не successful и не отклонена. Мы снимаем холд с вашего баланса.

ПолеТипОписание
order_idstringОбязательноid заказа на нашей стороне.
standart_signstringОбязательно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>"
}
Ответ 200 OK
HTTP/1.1 200 OK
{ "ok": true }

POST /set_client_status_payin

Передайте нам, что сказал клиент о платеже: payment_confirmed — оплатил, payment_rejected — отказался. Мы используем это вместе с банковским чеком для финализации заказа.

ПолеТипОписание
order_idstringОбязательноid заказа.
statusenumОбязательно"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"
}
Ответ 200 OK
HTTP/1.1 200 OK

{
  "ok": true,
  "order_id": "ORD-1001",
  "status_from_client": "payment_confirmed"
}

GET /status_payin/{order_id}

Опрос текущего статуса PayIn-заявки в любой момент.

GET
GET https://ssouk.org/applications/v1/status_payin/ORD-1001
X-Api-Key: <private_key>
Ответ 200 OK
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_idstringОбязательноУникален на мерчанта.
payment_methodenumОбязательноcard | sbp | account | iban.
fiat_amountstringОбязательноСумма как строка.
fiat_currencystringОбязательноISO-код.
bankstringОбязательноБанк получателя. Каноническое имя из справочника банков (например, "Т-Банк").
number_cardstringОбязательноОбязательно при payment_method=card.
phone_numberstringОбязательноОбязательно при payment_method=sbp. Формат +7 (900) 123-45-67 тоже принимаем.
number_accountstringОбязательноОбязательно при payment_method=account.
iban_numberstringОбязательноОбязательно при payment_method=iban.
bikstringНеобязательноБИК банка получателя.
full_namestringНеобязательноФИО получателя.
signstringОбязательноSHA256(order_id:public_key:private_key) hex.
success_callback_urlurlОбязательноURL коллбэка об успехе.
error_callback_urlurlОбязательноURL коллбэка ошибки.
timeoutint (мин)НеобязательноВремя жизни заявки.
customerstringНеобязательноВаш id клиента.
order_descriptionstringНеобязательноПроизвольное описание.
Тело запроса
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"
}
Ответ 200 OK
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_idstringОбязательноid заказа на нашей стороне.
standart_signstringОбязательно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>"
}
Ответ 200 OK
HTTP/1.1 200 OK
{ "ok": true }

POST /set_client_status_payout (необязательно)

Необязательно. Используйте этот запрос, только если хотите вручную зафиксировать у себя реакцию клиента на выплату. Заявка финализируется и без него.

ПолеТипОписание
order_idstringОбязательноid заказа.
statusenumОбязательно"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"
}
Ответ 200 OK
HTTP/1.1 200 OK

{
  "ok": true,
  "order_id": "WD-2002",
  "status_from_client": "payment_confirmed"
}

GET /status_payout/{order_id}

Опрос текущего статуса PayOut-заявки в любой момент.

GET
GET https://ssouk.org/applications/v1/status_payout/WD-2002
X-Api-Key: <private_key>
Ответ 200 OK
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
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>
Ответ 200 OK
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.

callback body
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"
}
Заголовок X-Body-Signature

В каждом коллбэке отправляем HTTP-заголовок X-Body-Signature — HMAC-SHA256 от тела запроса с вашим private_key. Поле standart_sign в теле подписывает только order_id; X-Body-Signature подписывает весь JSON, включая fiat_amount, status, receipts[]. Проверка не обязательна, но рекомендуется.

Python
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); в обоих случаях приходит финальный коллбэк.

dispute callback
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 МБ).

multipart
POST https://ssouk.org/applications/v1/upload_receipt
X-Api-Key: <private_key>
Content-Type: multipart/form-data

order_id=ORD-1001
file=@receipt.pdf
Ответ 200 OK
HTTP/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 в проде. Ниже точные строки, которые вернёт бэкенд (не локализуются): грепайте на своей стороне ровно то, что здесь напечатано.

HTTP
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"}

Статусы заявок в коллбэках

Жизненный цикл: pendingprocessingsuccessful. Негативные исходы: 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>"
}
Пример ответа
Выберите эндпоинт и сценарий, чтобы увидеть пример ответа.