Payment links и инвойсы

Ссылки на оплату и инвойсы в криптовалюте

Счёт — это один вызов для котировки и один для создания ордера. Плательщик отправляет ту монету, которая у него есть, исполнитель получает ту, которую запросил, а деньги не проходят ни через ваш сервис, ни через наш.

  • Вызовов на счёт2 — котировка и ордер
  • Кастодиальностьнет — плательщик → провайдер → получатель
  • Сумма счётакотировка через amount_to
  • Фиксация курсаrate_type=fixed

Собрано на/v1/partner/quotes/v1/partner/orders/v1/validate-address

SwapZilla не хостит инвойсы — он даёт те два вызова, из которых инвойс состоит. Котировка по сумме счёта, создание ордера — и плательщик получает адрес для оплаты, а средства уходят прямо на кошелёк получателя. Ни мы, ни вы их не держите.

  • Плательщик отправляет любой доступный актив, получатель получает тот, в котором выставил счёт.
  • Курс фиксируется на время жизни предложения через rate_type=fixed.
  • Ваш номер счёта едет вместе с ордером в client_order_id.
  • Расчёт некастодиальный: плательщик → обменник → получатель.

Как устроена ссылка на оплату

  1. Получатель указывает, что ему должны

    Актив, сеть и адрес — 500 USDT в сети TRC20 на собственный кошелёк. Это ваша запись о счёте; SwapZilla узнаёт о ней только в момент, когда появляется плательщик.

  2. Плательщик открывает ссылку и выбирает монету

    GET /v1/assets — честный список того, чем можно заплатить прямо сейчас: активы и сети, за которыми стоит хотя бы один провайдер. Из него и рисуется выбор.

  3. Котировка по сумме счёта, а не по сумме отправки

    Именно этот вызов превращает обмен в инвойс: запрашиваете amount_to=500 — и предложение отвечает точной суммой FromAmount, которую нужно отправить. Добавьте rate_type=fixed, и это число не изменится, пока идёт оплата.

  4. Создание ордера

    POST /v1/partner/orders: предложение, адрес получателя в to_address, адрес плательщика в refund_address, ваш номер счёта в client_order_id. Передайте expected_to_amount — и ордер будет отклонён, а не создан, если выплата успела «уехать».

  5. Показать адрес и следить за ордером

    DepositAddress и AmountFrom — это и есть вся страница оплаты: текстом, QR-кодом и с явно названной сетью. Опрашивайте GET /v1/partner/orders/{id} раз в 5–10 секунд до DONE; квитанция — это AmountToReceived и TxID.

Оба вызова целиком

Котировка счёта на 500 USDT, оплачиваемого в BTC:

curl -sG "https://api.swapzilla.io/v1/partner/quotes" \
  -H "X-API-Key: $API_KEY" \
  --data-urlencode "from_asset=BTC" \
  --data-urlencode "from_network=BITCOIN" \
  --data-urlencode "to_asset=USDT" \
  --data-urlencode "to_network=TRC20" \
  --data-urlencode "amount_to=500" \
  --data-urlencode "rate_type=fixed"

Первое предложение — лучшее. Превращаем его в адрес для оплаты:

curl -s -X POST "https://api.swapzilla.io/v1/partner/orders" \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "offer_id": "0b0c8f0e-2c1a-4f3f-8f57-2a1d1c4e77aa",
    "to_address": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE",
    "refund_address": "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq",
    "client_order_id": "INV-2026-0413",
    "expected_to_amount": 500
  }'

И цикл, который переводит статусы ордера в состояния счёта:

const terminal = ["DONE", "TIME_EXPIRED", "FAILED", "REFUNDED"];

async function watch(orderID) {
  for (;;) {
    const r = await fetch(`https://api.swapzilla.io/v1/partner/orders/${orderID}`, {
      headers: { "X-API-Key": process.env.API_KEY },
    });
    const order = await r.json();
    await onInvoiceState(order);                       // ваш собственный учёт
    if (terminal.includes(order.Status)) return order;
    await new Promise((s) => setTimeout(s, 7000));     // 5–10 с — правильный ритм
  }
}

Котировать нужно в момент открытия ссылки, а не в момент выставления счёта. Предложение живёт пять минут. Счёт, отправленный в понедельник и оплаченный в пятницу, котируется в пятницу: ссылка — это ваша страница, а предложение создаётся, когда на неё зашли.

Состояния счёта в терминах статусов ордера

Статус ордераЧто показывает счётЧто делаете вы
NEW WAIT_DEPOSITОжидает оплатыПоказываете адрес и таймер.
CONFIRMINGПлатёж виден в сетиОстанавливаете таймер: со стороны плательщика всё сделано.
EXCHANGING SENDINGИдёт расчётНичего — провайдер выполняет выплату.
DONEОплаченЗакрываете счёт по AmountToReceived, сохраняете TxID как квитанцию.
TIME_EXPIREDСсылка истекла неоплаченнойПересчитываете котировку и выдаёте новый адрес.
FAILED REFUNDEDНе оплаченПровайдер возвращает монеты на refund_address — ради этого его и спрашивали у плательщика.

Чего здесь нет

Не входитЧто это значит для вас
Хостинг страницы счёта и PDFСсылка, вёрстка и письма — ваши. API даёт сумму, адрес и статус.
ВебхукиИх пока нет — опрашивайте ордер раз в 5–10 секунд до финального статуса.
ФиатКрипта на входе, крипта на выходе. Счёт в евро — это ваш собственный источник курса, переводящий сумму в стейблкоин перед котировкой.
Частичная и повторная оплатаОдин ордер принимает один платёж на одну сумму. Разбитый на части счёт — это несколько ордеров.
Инициация возвратаВозврат делает провайдер на refund_address, если обмен не удался; вызова, отменяющего проведённый платёж, нет.

Кто так выставляет счета

  • Фрилансеры, работающие с зарубежными заказчиками. Клиент платит тем, что у него есть; счёт закрывается в USDT в той сети, которой действительно пользуется кошелёк исполнителя.
  • Студии и агентства со счетами по этапам: каждый этап — свой ордер и свой client_order_id.
  • Платформы, выставляющие счета от имени своих пользователей: адрес получателя — пользовательский, поэтому платформа не держит клиентские деньги и не становится должником по ним.
  • Все, кому платят из другой сети: BTC плательщика и USDT TRC20 получателя не обязаны встречаться в одном блокчейне.

Вопросы

Можно ли сделать бессрочную ссылку на оплату?

Ссылка может жить сколько угодно, предложение — нет. Предложения истекают через пять минут после котировки, поэтому долгоживущая ссылка ведёт на вашу страницу, которая считает котировку и создаёт ордер в момент прихода плательщика. Адрес для оплаты появляется тогда же, а не при выставлении счёта.

Держит ли SwapZilla деньги в процессе?

Нет. Обмен некастодиальный: плательщик отправляет средства на депозитный адрес провайдера, провайдер выплачивает на адрес получателя. Ни SwapZilla, ни ваша платформа не владеют средствами — поэтому и вызова на выплату не существует.

Как добиться, чтобы получатель получил ровно сумму счёта?

Котируйте через amount_to, а не amount_from, запрашивайте rate_type=fixed и передавайте expected_to_amount при создании ордера: если пересчитанная выплата больше не совпадает с обещанной в счёте, ордер будет отклонён, а не создан.

Что будет, если плательщик отправит не ту сумму?

Провайдер обрабатывает это по своим правилам: недоплата обычно возвращается на refund_address, переплата либо обменивается по текущему курсу, либо возвращается. Поэтому адрес для возврата у плательщика стоит спрашивать до создания ордера.

В каких монетах можно оплатить счёт?

В тех, что перечисляет GET /v1/assets на текущий момент: топ-100 активов по капитализации с сетями и провайдерами, которые их сейчас обслуживают. Актив зачисления получателю берётся из того же списка.

Нужен ли ключ, чтобы попробовать?

Для котировок и ордеров — да; /v1/assets, /v1/providers и /v1/validate-address отвечают и без него. Ключ выдаёт администратор SwapZilla, и используется он в заголовке X-API-Key с вашего сервера, а не из браузера.

Что ещё собирают на этом же ключе

Как получить ключ

Зарегистрируйтесь в партнёрском кабинете — партнёрский id и api_key для заголовка X-API-Key выпускаются сразу. Ключ становится рабочим после активации: напишите в @swapzilla_support_bot и коротко опишите интеграцию. Все эндпоинты, поля и статусы — в документации partner API.