SafeMatch API

Публичное API платформы SafeMatch для P2P-обмена криптовалюты на фиат. Данный документ описывает все доступные методы для интеграции площадок с SafeMatch.

Базовый URL: https://api.safematch.pro

Содержание

  1. Аутентификация
  2. Управление заявками
  3. Апелляции
  4. Получение данных
  5. Скачивание чека
  6. WebSocket-уведомления
  7. Статусы заявок
  8. Общие коды ответов

1. Аутентификация

Все запросы к API (кроме /health) требуют аутентификации. Для аутентификации используются три обязательных заголовка:

ЗаголовокОписание
X-API-KeyВаш API-ключ, выданный при регистрации
X-TimestampТекущий UNIX-timestamp (секунды)
X-SignatureHMAC-SHA256 подпись запроса

Формирование подписи

Подпись формируется по следующему алгоритму:

  1. Составить строку для подписи: HTTP_МЕТОД + ПУТЬ + TIMESTAMP + ТЕЛО_ЗАПРОСА
    • HTTP_МЕТОД — метод запроса заглавными буквами (POST, GET, DELETE)
    • ПУТЬ — путь запроса (например, /orders)
    • TIMESTAMP — значение заголовка X-Timestamp
    • ТЕЛО_ЗАПРОСА — JSON-тело, сериализованное с отсортированными ключами и без пробелов (разделители: , и :). Для запросов без тела эта часть опускается
  2. Вычислить HMAC-SHA256 от полученной строки, используя ваш секретный ключ
  3. Результат передать в заголовке X-Signature в hex-формате

Пример (Python):

import hmac
import hashlib
import json
import time

api_key = "ваш-api-key"
secret_key = "ваш-secret-key"

method = "POST"
path = "/orders"
timestamp = str(int(time.time()))

body = {"side": "IN", "min_price": 90.0, "max_price": 95.0,
        "fiat": "RUB", "token": "USDT", "fiat_qty": 10000}
body_str = json.dumps(body, sort_keys=True, separators=(",", ":"))

message = method + path + timestamp + body_str
signature = hmac.new(secret_key.encode(), message.encode(), hashlib.sha256).hexdigest()

headers = {
    "X-API-Key": api_key,
    "X-Timestamp": timestamp,
    "X-Signature": signature,
    "Content-Type": "application/json"
}
Для загрузки файлов (например, чек в формате PDF) подпись формируется аналогично, но тело запроса в подпись не включается — используется только МЕТОД + ПУТЬ + TIMESTAMP.

2. Управление заявками

Сводная таблица

МетодПутьОписание
POST/ordersСоздание заявки (IN или OUT)
DELETE/orders/{order_id}Удаление заявки
POST/orders/{order_id}/receiptЗагрузка чека (PDF)
POST/orders/{order_id}/confirm-paymentПодтверждение получения оплаты
POST/orders/{order_id}/dispute-receiptОспаривание чека
POST/orders/{order_id}/cancel-searchОтмена поиска замены

POST /orders Создание заявки

Создаёт новую заявку на покупку (IN) или продажу (OUT) криптовалюты.

Тело запроса (IN — покупка криптовалюты):

{
  "side": "IN",
  "min_price": 90.0,
  "max_price": 95.0,
  "fiat": "RUB",
  "token": "USDT",
  "fiat_qty": 10000
}

Тело запроса (OUT — продажа криптовалюты):

{
  "side": "OUT",
  "min_price": 90.0,
  "max_price": 95.0,
  "fiat": "RUB",
  "token": "USDT",
  "fiat_qty": 50000,
  "max_payments": 3,
  "banks": [
    {
      "bank_name": "Сбербанк",
      "recipient_details": "2200 0000 0000 0000",
      "recipient_name": "Иван Иванов",
      "detail_type": "CARD",
      "priority": 1
    }
  ]
}
ПолеТипОбязательностьОписание
sidestringда"IN" (покупка) или "OUT" (продажа)
min_pricenumberдаМинимальная цена (курс)
max_pricenumberдаМаксимальная цена (курс)
fiatstringдаФиатная валюта (например, "RUB")
tokenstringдаКриптовалюта (например, "USDT")
fiat_qtynumberдаСумма в фиатной валюте
max_paymentsnumberтолько для OUTМаксимальное количество встречных платежей
banksarrayтолько для OUTСписок банковских реквизитов
client_dataobjectнетДанные клиента: name_ru, name_en, passport_series_number

Объект banks[]:

ПолеТипОписание
bank_namestringНазвание банка
recipient_detailsstringРеквизиты получателя (номер карты или телефон)
recipient_namestringИмя получателя
detail_typestringТип реквизитов: "CARD" или "PHONE_NUMBER"
prioritynumberПриоритет (1 — наивысший)

Успешный ответ:

{
  "id": "a1b2c3d4-...",
  "side": "IN",
  "min_price": 90.0,
  "max_price": 95.0,
  "fiat": "RUB",
  "token": "USDT",
  "fiat_qty": 10000,
  "max_payments": null,
  "banks": null,
  "status": "waiting",
  "created_at": "2026-03-09T12:00:00"
}

Возможные ошибки:

ОшибкаПричина
Недостаточно средств для заморозкиНа счёте недостаточно криптовалюты для создания OUT-заявки
Недостаточно средств для комиссииНа счёте недостаточно средств для покрытия комиссии по IN-заявке
Торговля запрещенаТорговля заблокирована для данного аккаунта. Обратитесь к администратору
Превышен лимит апелляцийСлишком много апелляций в истории. Создание заявок временно заблокировано
Превышен лимит отменСлишком высокий процент отмен. Создание заявок заблокировано
Некорректная ценаУказано неверное значение цены

DELETE /orders/{order_id} Удаление заявки

Удаляет вашу заявку. Удаление возможно только для заявок в статусе «Ожидание сопоставления».

Параметры:

ПараметрТипГдеОписание
order_idstringпутьID заявки

Успешный ответ:

{
  "id": "a1b2c3d4-...",
  "result": "success"
}

Возможные ошибки:

ОшибкаПричина
Заявка не найденаЗаявка с указанным ID не существует
Нет доступаВы не являетесь создателем этой заявки
Нельзя удалить заявку в апелляцииЗаявка находится в процессе рассмотрения апелляции
Неверный статус заявкиЗаявку можно удалить только в статусе «Ожидание сопоставления»

POST /orders/{order_id}/receipt Загрузка чека

Загружает PDF-файл чека об оплате для IN-заявки (покупка). После загрузки заявка переходит в статус «Ожидание подтверждения» — продавец должен подтвердить получение средств.

Формат запроса: multipart/form-data

Параметры:

ПараметрТипГдеОписание
order_idstringпутьID заявки
payment_methodnumberqueryПриоритет выбранного банка (из списка реквизитов продавца)
receipt_filefileтелоPDF-файл чека

Успешный ответ:

{
  "id": "a1b2c3d4-...",
  "result": "success"
}

Возможные ошибки:

ОшибкаПричина
Заявка не найденаЗаявка с указанным ID не существует
Нет доступаВы не являетесь создателем этой заявки
Неверный статус заявкиЗагрузка чека возможна только в статусах «Ожидание оплаты», «Ожидание ручной проверки», «Ожидание нового чека»
Указанный банк не найденУказан несуществующий приоритет банка
Пустой файлЗагружен пустой файл чека

POST /orders/{order_id}/confirm-payment Подтверждение получения оплаты

Создатель OUT-заявки (продавец) подтверждает, что получил фиатный перевод от покупателя. После подтверждения заявка покупателя завершается, криптовалюта зачисляется покупателю.

Параметры:

ПараметрТипГдеОписание
order_idstringпутьID IN-заявки, по которой подтверждается получение оплаты

Успешный ответ:

{
  "id": "a1b2c3d4-...",
  "result": "success"
}

Возможные ошибки:

ОшибкаПричина
Заявка не найденаIN-заявка с указанным ID не существует
Это не IN-заявкаУказанная заявка не является заявкой на покупку
Заявка не сопоставленаIN-заявка ещё не была сопоставлена с вашей OUT-заявкой
Нет доступаПодтверждение доступно только создателю OUT-заявки
Неверный статус заявкиIN-заявка должна быть в статусе «Ожидание подтверждения»

POST /orders/{order_id}/dispute-receipt Оспаривание чека

Создатель OUT-заявки (продавец) не подтверждает получение оплаты по загруженному чеку. Автоматически создаётся апелляция для разбирательства.

Параметры:

ПараметрТипГдеОписание
order_idstringпутьID IN-заявки, по которой оспаривается чек

Тело запроса:

{
  "reason": "check_not_confirmed",
  "description": "Оплата не поступила на указанный счёт"
}
ПолеТипОбязательностьОписание
reasonstringдаПричина оспаривания
descriptionstringнетДополнительное пояснение

Допустимые причины (reason): check_not_confirmed

Успешный ответ:

{
  "appeal_id": "appeal-uuid-...",
  "order_id": "out-order-uuid-...",
  "reason": "check_not_confirmed",
  "status": "waiting_confirmation",
  "created_at": "2026-03-09T12:00:00"
}

Возможные ошибки:

ОшибкаПричина
Недопустимая причинаУказана причина, отсутствующая в списке допустимых
Заявка не найденаIN-заявка с указанным ID не существует
Это не IN-заявкаУказанная заявка не является заявкой на покупку
Нет доступаОспаривание доступно только создателю OUT-заявки
Неверный статус заявкиIN-заявка должна быть в статусе «Ожидание подтверждения»
Заявка уже в апелляцииПо данной заявке уже создана апелляция

POST /orders/{order_id}/cancel-search Отмена поиска замены

Если один из IN-ордеров в вашей OUT-заявке был отменён, система автоматически ищет замену. Этот метод позволяет отменить поиск замены и продолжить с текущими IN-заявками.

Параметры:

ПараметрТипГдеОписание
order_idstringпутьID OUT-заявки

Успешный ответ:

{
  "id": "a1b2c3d4-...",
  "result": "success"
}

Возможные ошибки:

ОшибкаПричина
Заявка не найденаЗаявка с указанным ID не существует
Только для OUT-заявокОтмена поиска доступна только для заявок на продажу
Нет доступаВы не являетесь создателем этой заявки
Неверный статус заявкиЗаявка должна быть в статусе «Поиск замены»

3. Апелляции

POST /appeals Создание апелляции

Создаёт апелляцию по завершённой заявке. Доступно для обоих участников сделки (создатель IN и создатель OUT).

Тело запроса:

{
  "order_id": "a1b2c3d4-...",
  "reason": "no_money_in_account",
  "description": "Средства не поступили на счёт в течение 2 часов"
}
ПолеТипОбязательностьОписание
order_idstringдаID заявки, по которой создаётся апелляция
reasonstringдаПричина апелляции (из списка допустимых)
descriptionstringнетПодробное описание проблемы

Допустимые причины для IN-заявок (покупка):

КодОписание
no_money_in_accountСредства не поступили на счёт
wrong_amountНеверная сумма
wrong_recipientНеверный получатель
payment_delayedЗадержка платежа

Допустимые причины для OUT-заявок (продажа):

КодОписание
no_crypto_receivedКриптовалюта не получена
wrong_crypto_amountНеверная сумма криптовалюты
transaction_failedОшибка транзакции
delayed_transferЗадержка перевода

Успешный ответ:

{
  "appeal_id": "appeal-uuid-...",
  "order_id": "a1b2c3d4-...",
  "reason": "no_money_in_account",
  "status": "completed",
  "created_at": "2026-03-09T12:00:00"
}

Возможные ошибки:

ОшибкаПричина
Заявка не найденаЗаявка с указанным ID не существует
Заявка уже в апелляцииПо данной заявке уже создана активная апелляция
Нет доступаВы не являетесь участником этой сделки
Заявка не завершенаАпелляции доступны только для завершённых заявок
Недопустимая причинаУказана причина, не входящая в список допустимых для данного типа заявки

4. Получение данных

GET /orders/{order_id} Данные заявки

Возвращает подробную информацию о заявке. Доступно только участникам сделки (создатель или контрагент).

Параметры:

ПараметрТипГдеОписание
order_idstringпутьID заявки

Успешный ответ:

{
  "id": "a1b2c3d4-...",
  "side": "IN",
  "user_side": "IN",
  "min_price": 90.0,
  "max_price": 95.0,
  "fiat_qty": 10000,
  "fiat": "RUB",
  "token": "USDT",
  "max_payments": null,
  "banks": [...],
  "created_at": 1741510800,
  "matched_at": 1741510860,
  "status": "waiting_payment",
  "creator_id": 1,
  "contr_id": 2,
  "rate": 92.5,
  "in_orders_data": null,
  "out_order_id": "out-uuid-...",
  "receipt_data": null,
  "payment_method": null,
  "transfer_time": null,
  "crypto_amount": 108.1,
  "freezeed_crypto": null,
  "fee_collected": 0.0,
  "expected_fiat_qty": null,
  "filled_fiat_qty": null
}
ПолеОписание
idID заявки
sideСторона заявки: IN (покупка) или OUT (продажа)
user_sideВаша роль в этой сделке: IN или OUT
min_price, max_priceДиапазон цены (курса)
fiat_qtyСумма в фиатной валюте
fiat, tokenВалютная пара
banksСписок банковских реквизитов
created_atВремя создания (UNIX-timestamp)
matched_atВремя сопоставления (UNIX-timestamp)
statusТекущий статус заявки
rateИтоговый курс сделки
crypto_amountСумма в криптовалюте
receipt_dataДанные о загруженном чеке
transfer_timeВремя перевода в секундах (от сопоставления до загрузки чека)
appeal_dataДанные об апелляции (если есть)
fee_collectedУдержанная комиссия
expected_fiat_qtyОжидаемая сумма в фиате (для OUT)
filled_fiat_qtyПолученная сумма в фиате (для OUT)

GET /orders Список заявок

Возвращает список ваших заявок с пагинацией, сортировкой и фильтрами.

Параметры (query):

ПараметрТипПо умолчаниюОписание
pagenumber1Номер страницы
page_sizenumber10Размер страницы (от 1 до 100)
sort_bystringcreated_atПоле сортировки: created_at, min_price, max_price, fiat_qty, crypto_amount
sort_orderstringdescПорядок сортировки: asc или desc
sidestringФильтр по стороне: IN или OUT
statusstringФильтр по статусу заявки

Успешный ответ:

{
  "orders": [
    {
      "id": "a1b2c3d4-...",
      "side": "IN",
      "status": "waiting",
      "fiat_qty": 10000,
      "fiat": "RUB",
      "token": "USDT",
      "created_at": 1741510800,
      ...
    }
  ],
  "total_count": 42,
  "page": 1,
  "page_size": 10,
  "total_pages": 5
}

5. Скачивание чека

GET /receipt/{receipt_id} Скачать PDF-чек

Возвращает PDF-файл чека по его идентификатору. Доступно только участникам сделки.

Параметры:

ПараметрТипГдеОписание
receipt_idstringпутьID чека (без расширения .pdf)

ID чека можно получить из поля receipt_data в данных заявки.

Ответ: PDF-файл (application/pdf).

Возможные ошибки:

ОшибкаПричина
Чек не найденЧек с указанным ID не существует
Нет доступаВы не являетесь участником сделки, к которой относится чек

6. WebSocket-уведомления

Для получения уведомлений в реальном времени подключитесь к WebSocket-сервису по адресу wss://ws.safematch.pro. Документация по подключению доступна через GET /ws/docs.

Типы уведомлений:

ТипОписание
order_createdЗаявка создана
order_matchedЗаявка сопоставлена — получены реквизиты контрагента
order_updatedДанные заявки обновлены (смена статуса или других параметров)
order_completedЗаявка успешно завершена
order_cancelledЗаявка отменена
order_supplementedК OUT-заявке добавлена новая встречная IN-заявка
balance_updatedБаланс изменён (зачисление, списание, заморозка, разморозка)

Каждое уведомление содержит актуальные данные по заявке, включая статус, реквизиты и прочие параметры.


7. Статусы заявок

СтатусПользовательское названиеОписание
waitingОжидание сопоставленияЗаявка размещена и ожидает встречную заявку
waiting_paymentОжидание оплатыIN-заявка сопоставлена, покупатель должен выполнить перевод и загрузить чек
waiting_paymentsОжидание поступленийOUT-заявка сопоставлена, продавец ожидает переводы от покупателей
waiting_confirmationОжидание подтвержденияЧек загружен, продавец должен подтвердить получение средств
waiting_manual_approveОжидание ручной проверкиЧек требует ручной проверки
waiting_new_receiptОжидание нового чекаНеобходимо загрузить новый чек
waiting_new_orderПоиск заменыСистема ищет новую встречную IN-заявку взамен отменённой
waiting_moderatorОжидание модератораЗаявка ожидает решения модератора
completedЗавершенаЗаявка успешно завершена, средства зачислены
cancelled_wrong_requisitesОтмененаЗаявка отменена из-за несоответствия реквизитов
in_appealВ апелляцииЗаявка находится в процессе рассмотрения апелляции

8. Общие коды ответов

КодОписание
200Запрос выполнен успешно
400Ошибка в запросе (неверные данные, неподходящий статус заявки)
401Ошибка аутентификации (неверный API-ключ, подпись или timestamp)
403Доступ запрещён (нет прав на данное действие)
404Ресурс не найден (заявка, чек)
500Внутренняя ошибка сервера