- Все пути не содержат
/на конце, запрашивайте их как есть. - Тела запросов и ответов — 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 перечислено недостающее):
- Есть хотя бы один включённый прямой адрес кошелька, либо настроен адрес сбора EVM / Tron;
- Если для типа сети режим приёма оплаты счетов — «смарт-контракт», для этого типа сети обязателен адрес сбора;
- Белый список IP не пуст (по умолчанию
*разрешает всё); - Адрес для уведомлений проекта (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"
}{
"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полностью совпадают с исходным счётом, возвращается исходный счёт (HTTP200); иначе —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 }]
}| Событие | Адрес доставки | Способ | Успешный ответ |
|---|---|---|---|
| Счёт завершён (нативный протокол) | 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 означает только подтверждение поступления, а не соответствие средств требованиям — отгружать ли товар и зачислять ли средства, мерчант решает сам с учётом результата проверки.
Xcash может подключать оценки риска адресов MistTrack и проводить AML-проверку (противодействие отмыванию денег) адреса отправителя каждого платежа; результат передаётся мерчанту в Webhook и доступен в записях счетов и депозитов в админ-панели. По умолчанию функция выключена.
- Xcash — некастодиальный шлюз: попав в сеть, платёж уже находится на собственном адресе/контракте мерчанта, система не может его отклонить или вернуть.
- Результат проверки не влияет ни на какие процессы приёма: счета как обычно переходят в
completed, депозиты зачисляются, средства собираются, Webhook отправляются; высокий риск не блокирует и не задерживает. - Результат — лишь оценка адреса отправителя сторонним источником данных: мерчант обязан сам решить по
risk_levelиrisk_score, отгружать ли товар, зачислять ли средства, замораживать баланс, отправлять на ручную проверку или возвращать средства, и несёт ответственность за это решение.
Проверяются только платежи, удовлетворяющие всем условиям ниже; иначе risk_level / risk_score равны null:
- В системе настроен источник данных: при самостоятельном размещении в админ-панели в разделе Система → Параметры работы → AML-проверка укажите эндпоинт QuickNode с подключённым дополнением MistTrack Address Risk Scores; в официальном облаке он настроен платформой.
- В проекте включена «AML-проверка» (при самостоятельном размещении — вкладка «AML-проверка» на странице проекта в админ-панели, в официальном облаке — страница настроек консоли).
- Стоимость платежа в долларах больше «порога AML-запросов» проекта (по умолчанию
100USD;0означает проверку всех платежей). - Счёт не прошёл быстрое подтверждение: если стоимость счёта ниже «порога быстрого подтверждения», приоритет у скорости и проверка не выполняется. Чтобы проверялись все счета выше порога, установите порог быстрого подтверждения ≤ порога AML-запросов. На депозиты быстрое подтверждение не влияет.
- Сеть платежа входит в покрытие MistTrack:
ethereum,bsc,polygon,arbitrum-one,optimism,base,avalanche,tron. Тестовые сети,linea,scrollне проверяются.
- Как только перевод в сети сопоставлен со счётом или адресом депозита, риск адреса отправителя запрашивается асинхронно, параллельно с подтверждением блоков;
- Каждый платёж проверяется заново в реальном времени, прошлые результаты по этому адресу не переиспользуются (риск адреса меняется вместе с источником средств);
- При подтверждении платежа уже полученный результат передаётся в Webhook;
- Если запрос завершился позже подтверждения (например, при очень быстром подтверждении или медленном источнике данных), результат сохраняется как обычно, но Webhook повторно не отправляется — его можно посмотреть в записях счетов и депозитов в админ-панели (в официальном облаке — в консоли).
- При сетевых ошибках, лимитах или 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 для 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}; ошибка: HTTP400, простой текстfail(без указания причины); лимит запросов: HTTP429. - Срок действия счёта фиксирован — 15 минут; способы оплаты — все доступные комбинации проекта.
- При повторной отправке того же
out_trade_no, еслиtype,name,money,currency,notify_url,return_url,paramсовпадают, возвращается тот же счёт; иначе — ошибка.
- Возьмите все параметры запроса, исключив
sign,sign_typeи поля с пустыми значениями; - Отсортируйте по имени параметра в порядке возрастания ASCII и соедините в
k1=v1&k2=v2; - Сразу в конце допишите
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).