Skip to content

Latest commit

 

History

History
538 lines (420 loc) · 43.9 KB

API.ru.md

File metadata and controls

538 lines (420 loc) · 43.9 KB

Документация по интеграции Xcash API

Общие соглашения

  • Все пути не содержат / на конце, запрашивайте их как есть.
  • Тела запросов и ответов — JSON (кроме точки входа EPay); суммы всегда передаются строкой без лишних нулей в конце (например, "29.9", "100").
  • Время — ISO 8601 UTC, например 2026-06-02T12:00:00.123456Z.
  • chain — код сети в нижнем регистре, crypto — символ криптовалюты в верхнем регистре, currency — код фиатной валюты в верхнем регистре.

Адреса шлюза

Способ развёртывания API / страница оплаты Точка входа EPay Консоль
Самостоятельное размещение https://{SITE_DOMAIN} https://{SITE_DOMAIN}/epay/submit.php https://{SITE_DOMAIN}/{ADMIN_PATH} (если ADMIN_PATH не задан — корень сайта)
Официальное облако https://pay.xca.sh https://pay.xca.sh/epay/submit.php https://dash.xca.sh

Коды сетей

Сеть code Тип Нативная монета Chain ID Сеть
Ethereum ethereum EVM ETH 1 Основная
BNB Smart Chain bsc EVM BNB 56 Основная
Polygon PoS polygon EVM POL 137 Основная
Arbitrum One arbitrum-one EVM ETH 42161 Основная
Optimism optimism EVM ETH 10 Основная
Base base EVM ETH 8453 Основная
Avalanche C-Chain avalanche EVM AVAX 43114 Основная
Linea linea EVM ETH 59144 Основная
Scroll scroll EVM ETH 534352 Основная
Tron tron Tron TRX - Основная
Sepolia sepolia EVM ETH 11155111 Тестовая
Nile nile Tron TRX - Тестовая
Anvil Local anvil EVM ETH 31337 Локальная тестовая
  • Фактически доступные сети определяются включёнными в админ-панели; их можно получить через GET /v1/metadata.
  • Тестовые проекты могут использовать только тестовые/локальные сети, нетестовые — только основные; неподходящие сети для проекта недоступны.

Криптовалюты и фиатные валюты

  • Встроенные криптовалюты: USDT, USDC, DAI и нативные монеты сетей ETH, BNB, POL, TRX. Доступность в конкретной сети зависит от связки «валюта × сеть», включённой в админ-панели.
  • В Tron поддерживаются только USDT и нативный TRX (как для счетов, так и для депозитов).
  • Встроенные фиатные валюты (currency): USD, CNY, EUR, JPY, HKD, с учётом регистра.

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

Все интерфейсы /v1/* требуют подписи HMAC, кроме следующих публичных эндпоинтов: GET /v1/invoice/{sys_no}, GET /v1/metadata.

Учётные данные

Выдаются после создания проекта в консоли:

Поле Описание
appid Идентификатор проекта: XC- + 8 заглавных букв и цифр, например XC-A3BK7NMG
hmac_key Ключ подписи, 32 символа

Заголовки запроса

Header Описание
XC-Appid AppID проекта
XC-Timestamp Текущая Unix-метка времени (в секундах), расхождение с временем сервера не более 300 секунд
XC-Nonce Случайная строка, обязательна; не может повторяться для одного AppID в течение 300 секунд
XC-Signature Подпись, шестнадцатеричная строка в нижнем регистре
Content-Type application/json

Алгоритм подписи

message   = XC-Nonce + XC-Timestamp + request_body
signature = hex( HMAC-SHA256(key = hmac_key, msg = message) )
  • request_body — исходная строка тела запроса, которая фактически отправляется; после подписи её нельзя сериализовать повторно.
  • Для GET-запросов request_body — пустая строка "", параметры запроса в подписи не участвуют.
import hashlib, hmac, json, time, uuid
import requests

appid, hmac_key = "XC-A3BK7NMG", "your_hmac_key"
body = json.dumps({"out_no": "order-001", "title": "Premium", "currency": "USD", "amount": "29.99"},
                  separators=(",", ":"), ensure_ascii=False)
timestamp = str(int(time.time()))
nonce = uuid.uuid4().hex
signature = hmac.new(hmac_key.encode(), f"{nonce}{timestamp}{body}".encode(), hashlib.sha256).hexdigest()
headers = {"XC-Appid": appid, "XC-Timestamp": timestamp, "XC-Nonce": nonce,
           "XC-Signature": signature, "Content-Type": "application/json"}
# Отправляется ровно та строка body, что использовалась для подписи; encode лишь переводит её в байты UTF-8
# (с не-ASCII символами requests не может отправить str напрямую)
# Не используйте json=payload: requests сериализует заново (пробелы и экранирование отличаются), и подпись не сойдётся
requests.post(url, data=body.encode("utf-8"), headers=headers)
const crypto = require("crypto");
const hmacKey = "your_hmac_key";
const body = JSON.stringify({ out_no: "order-001", title: "Premium", currency: "USD", amount: "29.99" });
const timestamp = Math.floor(Date.now() / 1000).toString();
const nonce = crypto.randomUUID();
const signature = crypto.createHmac("sha256", hmacKey).update(`${nonce}${timestamp}${body}`).digest("hex");

Порядок проверок

Подписанные интерфейсы проверяются в следующем порядке, при первом несоответствии возвращается ошибка:

1001 неверный AppID → 1005 проект отключён → 1008 метка времени отсутствует или вне окна → 1004 проект не готов → 1002 IP не в белом списке → 1003 неверная подпись → 1000 отсутствует Nonce → 1009 повтор Nonce

Условия готовности проекта (если не выполнены — 1004, в detail перечислено недостающее):

  1. Есть хотя бы один включённый прямой адрес кошелька, либо настроен адрес сбора EVM / Tron;
  2. Если для типа сети режим приёма оплаты счетов — «смарт-контракт», для этого типа сети обязателен адрес сбора;
  3. Белый список IP не пуст (по умолчанию * разрешает всё);
  4. Адрес для уведомлений проекта (Webhook) не пуст.

Формат ответа

При успехе возвращается JSON с бизнес-данными. Бизнес-ошибки имеют единый формат:

{ "code": "1001", "message": "AppID无效", "detail": "" }
  • Тип ошибки определяйте по code; message локализуется по Accept-Language, не полагайтесь на его текст.
  • detail — дополнительная информация: строка или объект (при ошибке параметров — детали по каждому полю).
  • Ошибки уровня фреймворка — ресурс не найден 404, метод не разрешён 405, лимит запросов 429 и т. п. — имеют вид {"detail": "..."}.

Список интерфейсов

Метод Путь Описание Подпись Лимит
POST /v1/invoice Создание счёта Нужна 256/мин, по IP
GET /v1/invoice/{sys_no} Запрос счёта Не нужна 120/мин, по sys_no + IP
GET /v1/deposit/address Получение адреса депозита Нужна 60/мин, по appid + IP
GET /v1/metadata Метаданные сетей/валют Не нужна 256/мин, по IP
GET / POST /epay/submit.php Создание заказа EasyPay V1 EPay MD5 60/мин, по IP

Создание счёта

POST /v1/invoice

Создаёт счёт с ценой в фиатной валюте и возвращает pay_url страницы оплаты, где покупатель выбирает валюту и сеть и оплачивает.

Параметры запроса

Поле Тип Обязательно Описание
out_no string Да Номер заказа мерчанта, до 32 символов, уникален в пределах проекта (общее пространство имён с out_trade_no EPay)
title string Да Название, до 32 символов
currency string Да Фиатная валюта цены, например USD, CNY
amount string Да Сумма, от 0.01 до 1000000, не более 2 знаков после запятой (например, "10.000" считается 3 знаками и будет отклонено)
duration integer Нет Срок действия (минуты), от 5 до 30, по умолчанию 10
methods object Нет Ограничение способов оплаты в формате {"валюта": ["код сети", ...]}; если не передано, используются все доступные комбинации проекта
notify_url string Нет Адрес Webhook для этого счёта, приоритетнее адреса уведомлений проекта
return_url string Нет Адрес перехода со страницы оплаты после завершения платежа
{
  "out_no": "order-20260602-001",
  "title": "Premium Plan",
  "currency": "USD",
  "amount": "29.99",
  "duration": 15,
  "methods": { "USDT": ["ethereum", "tron"], "USDC": ["base"] },
  "notify_url": "https://merchant.example.com/xcash/webhook",
  "return_url": "https://merchant.example.com/payment/success"
}

Ответ (HTTP 201)

{
  "appid": "XC-A3BK7NMG",
  "sys_no": "INV2606028X7K2P9Q",
  "out_no": "order-20260602-001",
  "title": "Premium Plan",
  "currency": "USD",
  "amount": "29.99",
  "methods": { "USDT": ["ethereum", "tron"], "USDC": ["base"] },
  "chain": null,
  "crypto": null,
  "crypto_address": null,
  "pay_address": null,
  "pay_amount": null,
  "pay_url": "https://pay.xca.sh/pay/INV2606028X7K2P9Q",
  "started_at": "2026-06-02T12:00:00.123456Z",
  "created_at": "2026-06-02T12:00:00.123456Z",
  "expires_at": "2026-06-02T12:15:00.123456Z",
  "notify_url": "https://merchant.example.com/xcash/webhook",
  "return_url": "https://merchant.example.com/payment/success",
  "payment": null,
  "status": "waiting",
  "risk_level": null,
  "risk_score": null
}

Значения полей — как в запросе счёта; непереданные notify_url / return_url возвращаются пустой строкой ""; risk_level / risk_score см. в разделе AML-контроль рисков — у нового неоплаченного счёта оба равны null.

Правила

  • Идемпотентность: если out_no уже существует и title, currency, amount, notify_url, return_url полностью совпадают с исходным счётом, возвращается исходный счёт (HTTP 200); иначе — 1007.
  • methods: должно быть подмножеством доступных комбинаций проекта, иначе 5008; неизвестная валюта — 2001, неизвестная сеть — 2000. methods в ответе — итоговые действующие комбинации.
  • Автовыбор: если в итоге остаётся одна комбинация «валюта × сеть», она назначается сразу при создании, и в ответе уже заполнены chain, crypto, pay_address, pay_amount.
  • Лимит ожидающих оплаты: когда у проекта 100 счетов в статусе waiting, создание новых отклоняется (5009).
  • Сумма к оплате: покупатель должен заплатить ровно pay_amount. Она рассчитывается по курсу и может содержать «хвост», отличающий счета друг от друга, — не вычисляйте её самостоятельно из amount; зачисление происходит только если сумма в сети точно равна pay_amount.

Запрос счёта

GET /v1/invoice/{sys_no}

Публичный интерфейс без подписи — для опроса со страницы оплаты или со стороны покупателя. Не возвращает appid, out_no, notify_url, а также результат AML-проверки (чтобы плательщик не мог проверить, помечен ли адрес; результат риска см. в разделе AML-контроль рисков). Если счёта нет — 404.

Поле Тип Описание
sys_no string Системный номер: INV + 6 цифр даты (YYMMDD) + 8 заглавных букв и цифр
title string Название
currency string Фиатная валюта цены
amount string Сумма
methods object Доступные способы оплаты
chain string | null Текущая сеть, null если не выбрана
crypto string | null Текущая криптовалюта
crypto_address string | null Адрес контракта валюты в этой сети; для нативной монеты ""; null если не выбрана
pay_address string | null Адрес получения
pay_amount string | null Количество криптовалюты к оплате покупателем
pay_url string Адрес страницы оплаты
started_at string Время начала действия текущих платёжных инструкций; обновляется, когда покупатель меняет способ оплаты
created_at string Время создания
expires_at string Время истечения
return_url string Адрес перехода, "" если не задан; для заказов EPay после завершения — URL перехода с подписанными параметрами
payment object | null Сопоставленный перевод в сети, см. таблицу ниже
payment_uri string | null Платёжный URI EIP-681 для EVM-сетей; null для не-EVM или если сумму нельзя точно закодировать
evm_payment object | null Параметры оплаты в один клик через EVM-кошелёк {chain_id, to, value, data}; null, если неприменимо
tron_payment object | null Параметры оплаты в один клик через TronLink {is_native, to, contract, amount, fee_limit, is_testnet}; null, если неприменимо
status string waiting / completed / expired

Объект payment:

Поле Тип Описание
chain string Код сети
block integer Высота блока
hash string Хеш транзакции
from_address string Адрес отправителя
to_address string Адрес получателя
crypto string Криптовалюта
amount string Поступившая сумма
datetime string Время транзакции
status string confirming / confirmed
confirm_progress object {has_confirmed_count, need_confirmed_count, progress}, progress — целое от 0 до 100

Статусы:

  • waiting: ожидает оплаты. Если в сети уже есть подходящий перевод, но он не подтверждён, payment заполнен, а status остаётся waiting.
  • completed: подтверждён, финальный статус.
  • expired: истёк. Не финальный: если платёж попал в сеть до истечения и подтвердился после, счёт всё равно перейдёт в completed и будет отправлен Webhook.
  • Если стоимость счёта в долларах ниже «порога быстрого подтверждения» проекта (по умолчанию 10 USD), счёт подтверждается сразу при обнаружении платежа, без ожидания подтверждений блоков, и AML-проверка не выполняется.

Получение адреса депозита

GET /v1/deposit/address?uid={uid}&chain={chain}&crypto={crypto}

Нужна подпись (request_body — пустая строка). Выдаёт конечному пользователю персональный адрес депозита (адрес смарт-контракта).

Параметр Обязательно Описание
uid Да Идентификатор конечного пользователя, 1–128 символов, только буквы, цифры, _, -
chain Да Код сети
crypto Да Символ криптовалюты
{ "deposit_address": "0xAbCd...1234" }
  • Для одного проекта, одного uid и одной сети адрес постоянен и не зависит от crypto (все валюты сети используют один адрес).
  • Поддерживаются EVM-сети и Tron (в Tron только USDT, TRX). Нужен адрес сбора для соответствующего типа сети (иначе 4001).
  • Нативные монеты EVM (ETH/BNB/POL и др.):
    • Контракт по этому адресу разворачивается только после вызова интерфейса с crypto=нативная монета; нативные монеты, поступившие до развёртывания контракта, зачисляются после его завершения.
    • Адрес депозита — это контракт, поэтому gas limit перевода должен быть больше 21000 (достаточно автоматической оценки кошелька); переводы с жёстко заданным 21000 завершатся ошибкой.
  • Ошибки: 4000 неверный uid; 2000 сеть не существует / не включена / не соответствует тестовому признаку проекта / не поддерживает депозиты этой валюты; 2001 валюта не существует или не включена; 2002 валюта не включена в этой сети; 4001 не настроен адрес сбора; 4002 достигнут лимит пользователей депозитов по тарифу (только официальное облако).

Метаданные сетей и валют

GET /v1/metadata

Публичный интерфейс, возвращает включённые сейчас сети и валюты (без учёта тестового/основного признака проекта).

{
  "chains": [{ "code": "ethereum", "name": "Ethereum", "icon": "https://...", "is_testnet": false }],
  "cryptos": [{ "symbol": "USDT", "name": "Tether", "icon": "https://...", "is_native": false }]
}

Webhook

Правила доставки

Событие Адрес доставки Способ Успешный ответ
Счёт завершён (нативный протокол) notify_url счёта, если пуст — адрес уведомлений проекта POST JSON + HMAC-заголовки HTTP 200 и тело ответа ok
Депозит зачислен Адрес уведомлений проекта POST JSON + HMAC-заголовки HTTP 200 и тело ответа ok
Заказ EPay завершён notify_url, указанный при создании заказа GET query + MD5-подпись HTTP 200 и тело ответа success
  • Тело ответа сравнивается точно, с учётом регистра, после обрезки пробелов по краям. Таймаут одного запроса — 5 секунд.
  • Повторяются: сетевые ошибки/таймауты, 5xx, 408, 425, 429. Все остальные случаи сразу считаются неудачей без повторов, включая 200 с неверным телом, 2xx кроме 200, 3xx и прочие 4xx.
  • По умолчанию не более 5 попыток доставки (включая первую), экспоненциальная задержка примерно 4s / 8s / 16s / 32s (не более 120s за раз); число попыток и предел настраиваются в админ-панели в «Системных параметрах»; неудачные события можно доставить повторно из списка событий Webhook в админ-панели.
  • Если уведомления проекта выключены или адрес доставки пуст, событие откладывается и повторяется каждые 10 минут, что тоже засчитывается как попытка.
  • По умолчанию доставка идёт только на публичные HTTPS-адреса; http, localhost и внутренние адреса сразу считаются неудачей (при самостоятельном размещении это можно разрешить через WEBHOOK_ALLOW_INTERNAL_TARGETS=true).
  • Окно повторов короткое — для сверки статуса счёта используйте интерфейс запроса счёта как резервный.

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

Заголовки запроса — XC-Appid, XC-Nonce, XC-Timestamp, XC-Signature, алгоритм тот же, что и для API-запросов:

expected = hmac.new(hmac_key.encode(), f"{nonce}{timestamp}{raw_body}".encode(), hashlib.sha256).hexdigest()
ok = hmac.compare_digest(expected, signature)
  • raw_body должен быть исходным полученным телом запроса; не разбирайте и не сериализуйте его заново (порядок полей JSON и пробелы не гарантируются).
  • XC-Nonce одинаков во всех повторах одного события — используйте его для идемпотентной дедупликации. XC-Timestamp — время отправки каждой доставки.

Счёт завершён

Отправляется один раз, когда счёт переходит в completed.

{
  "type": "invoice",
  "data": {
    "sys_no": "INV2606028X7K2P9Q",
    "out_no": "order-20260602-001",
    "crypto": "USDT",
    "chain": "ethereum",
    "pay_address": "0xAbCd...1234",
    "pay_amount": "29.99",
    "hash": "0xabc123...",
    "block": 12345678,
    "confirmed": true,
    "risk_level": null,
    "risk_score": null
  }
}

Депозит зачислен

Отправляется один раз, когда перевод депозита достигает требуемых подтверждений (confirmed всегда true). Поступления валют, отключённых в админ-панели, только зачисляются, Webhook не отправляется.

{
  "type": "deposit",
  "data": {
    "sys_no": "DXC2606026K9P2QWX",
    "uid": "user-10001",
    "chain": "base",
    "block": 12345678,
    "hash": "0xabc123...",
    "crypto": "USDC",
    "amount": "500",
    "confirmed": true,
    "risk_level": null,
    "risk_score": null
  }
}

risk_level / risk_score — снимок результата AML на момент подтверждения, значения описаны в разделе AML-контроль рисков. Webhook означает только подтверждение поступления, а не соответствие средств требованиям — отгружать ли товар и зачислять ли средства, мерчант решает сам с учётом результата проверки.

AML-контроль рисков

Xcash может подключать оценки риска адресов MistTrack и проводить AML-проверку (противодействие отмыванию денег) адреса отправителя каждого платежа; результат передаётся мерчанту в Webhook и доступен в записях счетов и депозитов в админ-панели. По умолчанию функция выключена.

Основной принцип: система только оценивает риск, решение принимает мерчант

  • Xcash — некастодиальный шлюз: попав в сеть, платёж уже находится на собственном адресе/контракте мерчанта, система не может его отклонить или вернуть.
  • Результат проверки не влияет ни на какие процессы приёма: счета как обычно переходят в completed, депозиты зачисляются, средства собираются, Webhook отправляются; высокий риск не блокирует и не задерживает.
  • Результат — лишь оценка адреса отправителя сторонним источником данных: мерчант обязан сам решить по risk_level и risk_score, отгружать ли товар, зачислять ли средства, замораживать баланс, отправлять на ручную проверку или возвращать средства, и несёт ответственность за это решение.

Условия включения

Проверяются только платежи, удовлетворяющие всем условиям ниже; иначе risk_level / risk_score равны null:

  1. В системе настроен источник данных: при самостоятельном размещении в админ-панели в разделе Система → Параметры работы → AML-проверка укажите эндпоинт QuickNode с подключённым дополнением MistTrack Address Risk Scores; в официальном облаке он настроен платформой.
  2. В проекте включена «AML-проверка» (при самостоятельном размещении — вкладка «AML-проверка» на странице проекта в админ-панели, в официальном облаке — страница настроек консоли).
  3. Стоимость платежа в долларах больше «порога AML-запросов» проекта (по умолчанию 100 USD; 0 означает проверку всех платежей).
  4. Счёт не прошёл быстрое подтверждение: если стоимость счёта ниже «порога быстрого подтверждения», приоритет у скорости и проверка не выполняется. Чтобы проверялись все счета выше порога, установите порог быстрого подтверждения ≤ порога AML-запросов. На депозиты быстрое подтверждение не влияет.
  5. Сеть платежа входит в покрытие MistTrack: ethereum, bsc, polygon, arbitrum-one, optimism, base, avalanche, tron. Тестовые сети, linea, scroll не проверяются.

Момент проверки

  1. Как только перевод в сети сопоставлен со счётом или адресом депозита, риск адреса отправителя запрашивается асинхронно, параллельно с подтверждением блоков;
  2. Каждый платёж проверяется заново в реальном времени, прошлые результаты по этому адресу не переиспользуются (риск адреса меняется вместе с источником средств);
  3. При подтверждении платежа уже полученный результат передаётся в Webhook;
  4. Если запрос завершился позже подтверждения (например, при очень быстром подтверждении или медленном источнике данных), результат сохраняется как обычно, но Webhook повторно не отправляется — его можно посмотреть в записях счетов и депозитов в админ-панели (в официальном облаке — в консоли).
  5. При сетевых ошибках, лимитах или 5xx от источника данных выполняется до 3 попыток; если и они неудачны, этот платёж больше не проверяется, а поля риска остаются null.

Значения полей

Поле Описание
risk_level Уровень риска MistTrack, от низкого к высокому: Low → Moderate → High → Severe
risk_score Оценка риска MistTrack, строка с не более чем 2 знаками после запятой (например, "35", "87.5"); чем выше оценка, тем выше риск; правила разбиения на уровни и оценки — согласно документации MistTrack

null означает, что доступного результата нет: не выполнены условия включения выше, запрос не удался или на момент отправки Webhook запрос ещё не завершился. null не означает низкий риск.

Рекомендации по обработке для мерчанта

Ниже — лишь пример; конкретную стратегию определяйте с учётом требований комплаенса и допустимого уровня риска вашего бизнеса:

Результат Пример обработки
Low Обычная отгрузка / зачисление
Moderate Обычная обработка, можно взять на заметку
High Приостановить отгрузку или заморозить соответствующий баланс, передать на ручную проверку
Severe Не отгружать, заморозить соответствующий баланс, после ручной проверки решить вопрос о возврате
null при сумме выше порога AML-запросов По потребностям бизнеса — пропустить сразу или обработать позже, после запроса счёта / проверки результата в админ-панели
def handle_paid(data: dict) -> None:
    level = data.get("risk_level")
    if level in ("High", "Severe"):
        hold_for_review(data["sys_no"], level, data.get("risk_score"))  # на усмотрение мерчанта: приостановить отгрузку/заморозить баланс, ручная проверка
    else:
        fulfill(data["sys_no"])
  • Асинхронные уведомления и синхронный переход EasyPay (EPay) не содержат полей риска — мерчантам, подключённым через EPay, следует смотреть результат через интерфейс запроса счёта или в списке счетов в админ-панели.
  • В официальном облаке каждый успешный запрос оплачивается по цене AML-запроса тарифа, и списание происходит только после подтверждения платежа; неудачные запросы и платежи, отброшенные реорганизацией сети до подтверждения, не оплачиваются. При самостоятельном размещении расходы на запросы вы оплачиваете QuickNode напрямую, Xcash ничего не взимает.

Совместимость с EasyPay V1

Совместим с распространёнными плагинами EasyPay для Typecho, WordPress, Discuz и др. Заголовки HMAC не используются — применяется собственная MD5-подпись EPay.

Учётные данные мерчанта

Поле Описание
pid ID мерчанта EPay
secret_key Ключ MD5-подписи (независим от hmac_key)
active Включена ли точка входа EPay
  • Официальное облако: выдаётся автоматически при создании проекта, смотрите в консоли.
  • Самостоятельное размещение: добавьте на вкладке «Настройка EPay» страницы проекта в админ-панели.

Создание заказа

GET /epay/submit.php или POST /epay/submit.php (POST — в формате формы, не отправляйте JSON)

Поле Тип Обязательно Описание
pid integer Да ID мерчанта EPay
type string Нет Поле для совместимости, до 32 символов; не ограничивает сеть или валюту, только возвращается без изменений в уведомлении
out_trade_no string Да Номер заказа мерчанта, до 64 символов, уникален в пределах проекта (общее пространство имён с out_no из /v1/invoice)
notify_url string Да Адрес асинхронного уведомления
return_url string Нет Адрес синхронного перехода
name string Да Название товара, до 128 символов
money string Да Сумма, от 0.01 до 1000000, не более двух знаков после запятой
currency string Нет Расширение Xcash: фиатная валюта цены, по умолчанию CNY, без учёта регистра
param string Нет Дополнительный параметр, до 512 символов
sign string Да MD5-подпись (в нижнем регистре)
sign_type string Да Всегда MD5
  • Успех: HTTP 302 с переходом на страницу оплаты /pay/{sys_no}; ошибка: HTTP 400, простой текст fail (без указания причины); лимит запросов: HTTP 429.
  • Срок действия счёта фиксирован — 15 минут; способы оплаты — все доступные комбинации проекта.
  • При повторной отправке того же out_trade_no, если type, name, money, currency, notify_url, return_url, param совпадают, возвращается тот же счёт; иначе — ошибка.

Алгоритм подписи

  1. Возьмите все параметры запроса, исключив sign, sign_type и поля с пустыми значениями;
  2. Отсортируйте по имени параметра в порядке возрастания ASCII и соедините в k1=v1&k2=v2;
  3. Сразу в конце допишите secret_key и возьмите MD5 в виде шестнадцатеричной строки в нижнем регистре.
import hashlib

def epay_sign(params: dict, secret_key: str) -> str:
    items = sorted((k, str(v)) for k, v in params.items()
                   if k not in ("sign", "sign_type") and v not in (None, ""))
    raw = "&".join(f"{k}={v}" for k, v in items) + secret_key
    return hashlib.md5(raw.encode("utf-8")).hexdigest()

Асинхронное уведомление

После завершения счёта на notify_url отправляется GET-запрос со следующими query-параметрами (алгоритм подписи тот же, мерчант должен проверить подпись):

Поле Описание
pid ID мерчанта EPay
trade_no Системный номер Xcash (sys_no)
out_trade_no Номер заказа мерчанта
type type из заказа, пусто если не передавался
name Название товара
money Сумма заказа, два знака после запятой
trade_status Всегда TRADE_SUCCESS
param param из заказа, возвращается только если задан
sign_type MD5
sign MD5-подпись

Ответ мерчанта HTTP 200 с телом success считается успешным; правила повторов см. в разделе Webhook.

Синхронный переход

Если при создании заказа был передан return_url, то после завершения счёта return_url, возвращаемый интерфейсом запроса счёта, — это URL перехода с параметрами из таблицы выше и подписью; по нему страница оплаты возвращает покупателя к мерчанту. Синхронный переход означает лишь окончание процесса на странице оплаты — отгружайте товар по асинхронному уведомлению.

Коды ошибок

Код HTTP Описание
1000 400 Ошибка параметров
1001 400 Неверный AppID
1002 403 IP не в белом списке
1003 403 Неверная подпись
1004 400 Проект не готов (detail перечисляет недостающие настройки)
1005 403 Проект отключён
1007 400 out_no уже существует с другими параметрами
1008 400 Метка времени отсутствует или отличается более чем на 300 секунд
1009 400 Повтор Nonce
2000 400 Неверная сеть
2001 400 Неверная валюта
2002 400 Сеть не поддерживает эту валюту
4000 400 Неверный uid
4001 400 В проекте не настроен адрес сбора для этого типа сети
4002 403 Достигнут лимит пользователей депозитов по тарифу (официальное облако)
5000 400 Неподдерживаемая фиатная валюта
5008 400 Нет доступных способов оплаты
5009 400 Слишком много счетов, ожидающих оплаты
6004 403 Аккаунт заморожен (официальное облако)

Процесс интеграции

Счета: мерчант вызывает POST /v1/invoice → направляет покупателя на pay_url → покупатель выбирает валюту и сеть и платит → Xcash отправляет Webhook invoice → мерчант отвечает ok → мерчант отгружает товар (для резервной сверки — GET /v1/invoice/{sys_no}).

Депозиты: мерчант вызывает GET /v1/deposit/address → показывает пользователю deposit_address → пользователь переводит средства → Xcash отправляет Webhook deposit → мерчант отвечает ok → мерчант зачисляет средства (дедупликация по XC-Nonce или sys_no).