Пакет — это не одна транзакция, а множество независимых ордеров, которые просто стартуют вместе. У каждого получателя своя котировка, свой депозитный адрес и свой статус, поэтому список выплат свободно пересекает сети и активы, а одна плохая строка не задерживает остальные.
- Получателям в одном запуске можно платить разными активами и в разных сетях.
- Отказ — по получателю: сумма ниже минимума отклоняется при создании ордера, до движения денег.
- Idempotency-ключи делают повторный прогон после сбоя безопасным.
- Никакого ончейн-контракта multisend и никакого общего баланса.
От CSV до закрытого запуска
-
Проверьте список до того, как считать котировки
Каждая строка —
адрес, актив, сеть, сумма. Прогоните их черезGET /v1/validate-address(вызов без ключа) и отклоняйте файл, а не выплату.known:falseозначает, что для сети нет шаблона проверки: это «не проверено», а не «верно». -
Котировка каждой строки
По одной котировке на получателя, по сумме к получению (
amount_to). Сумма возвращённыхFromAmount— это стоимость запуска; согласуйте её до того, как что-то создано. -
Создавайте ордера небольшими партиями
Пять–десять параллельных созданий — правильный темп: провайдеры троттлят всплески, а каждый ордер нужно успеть создать и оплатить за пять минут жизни предложения. В каждом создании —
Idempotency-Keyиз идентификатора запуска и строки. -
Оплатите каждый ордер
У каждого свой
DepositAddressи точная суммаAmountFrom. Здесь и живут комиссии сети: сто получателей — сто исходящих переводов с вашего кошелька. -
Соберите результаты
Опросите ордера до финального статуса и напишите отчёт по запуску:
DONEсTxID— или причина и строка на повтор.
Веерная отправка
import pLimit from "p-limit";
const limit = pLimit(8); // провайдеры не любят всплески
const results = await Promise.all(rows.map((row, i) => limit(async () => {
try {
const order = await createPayout(runID, row, i); // котировка → POST /orders
return { row: i, ok: true, id: order.ID, send: order.AmountFrom,
to: order.DepositAddress };
} catch (e) {
return { row: i, ok: false, error: String(e) }; // одна строка, а не весь запуск
}
})));
const payable = results.filter((r) => r.ok);
const rejected = results.filter((r) => !r.ok); // покажите их до оплаты
Перезапускаемым запуск делает именно idempotency-ключ. Стройте его из запуска и строки, но не из часов:
const key = `${runID}:${row.address}:${row.amount}`; // не меняется при повторах
// POST /v1/partner/orders с заголовком "Idempotency-Key: "
// Повтор вернёт тот же ордер — упавший запуск продолжится, а не задвоится.
Когда строка не проходит
| Что вы видите | Почему | Что делать |
|---|---|---|
400, сумма ниже минимума | Строка меньше MinFromAmount провайдера для этой пары. | Сверяйте MinFromAmount на котировке; объединяйте мелкие суммы в более крупные выплаты или меняйте актив. |
400 offer expired | Между котировкой и созданием прошло больше пяти минут. | Пересчитайте строку. Держите цепочку котировка → ордер → оплата плотной. |
400 provider is disabled | Обменник отключили уже после котировки. | Пересчитайте: следующее предложение придёт от другого провайдера. |
| Предложений нет вовсе | Эту пару сейчас никто не обслуживает. | Заплатите этому получателю активом, который есть в /v1/assets. |
| TIME_EXPIRED после пропущенной оплаты | Депозит не пришёл в окно провайдера. | Пересчитайте и создайте заново: ничего не отправлено — ничего не потеряно. |
| REFUNDED | Обмен не удался уже после оплаты. | Провайдер вернёт монеты на refund_address — всегда указывайте там свой кошелёк. |
Чем это отличается от ончейн-multisend
| Контракт multisend | Пакет SwapZilla | |
|---|---|---|
| Сети | Одна, в которой живёт контракт | Любая пара, которую покрывают провайдеры, вперемешку в одном запуске |
| Активы | Тот, что у вас уже есть | Свой у каждого получателя — конвертация по пути |
| Транзакции | Одна, дёшево в пересчёте на получателя | Один депозит на получателя — цена отказа от общего котла |
| Кастодиальность | Нет | Нет |
| Отказ | Обычно всё или ничего | По получателю, с причиной |
Чего нет и что стоит учесть заранее: единого batch-эндпоинта, одной оплачивающей транзакции, вебхуков и фиатного плеча. Запуск — это цикл на вашей стороне; API делает безопасной каждую его итерацию.
Что рассылают веером
- Партнёрские и реферальные выплаты — сотни небольших сумм, каждая в том активе, который попросил партнёр.
- Программы для авторов и баунти, где список меняется каждый цикл, а адреса приходят от пользователей.
- Аирдропы и вознаграждения, которые должны прийти в предпочитаемой получателем сети, а не в вашей.
- Возвраты и компенсации, которые сверяются построчно по
TxID.
Вопросы
Есть ли один эндпоинт, принимающий список получателей?
Нет. Пакет создаётся как один ордер на получателя — массового эндпоинта в API не существует. На практике именно это и делает возможными запуски со смешанными активами и сетями, а каждый получатель получает собственный статус и собственную причину отказа.
Можно отправить на сто адресов в разных сетях за один запуск?
Да. В каждом ордере свои актив и сеть получения, поэтому один запуск может закрыть USDT TRC20, BTC и ETH одновременно из одного исходного актива. Общим остаётся только идентификатор запуска, который вы кладёте в client_order_id каждого ордера.
Что мешает упавшему запуску заплатить дважды при перезапуске?
Стабильный Idempotency-Key на строку — собранный из идентификатора запуска и получателя, а не из времени. Повторное создание с тем же ключом вернёт уже существующий ордер, а не откроет второй.
Сколько ордеров можно создавать одновременно?
Со стороны SwapZilla лимитов нет, но провайдеры троттлят всплески котировок, поэтому восемь–десять параллельных строк — комфортный темп. Настоящее ограничение — пятиминутный срок жизни предложения: строку нужно успеть котировать, создать и оплатить внутри него.
Кто платит комиссии сети?
Вы платите комиссию за каждый отправленный депозит, а выплатная комиссия провайдера уже учтена в ToAmount предложения — поэтому котировка через amount_to и есть надёжный способ сделать сумму получателя точной.
Можно ли посмотреть весь запуск потом?
GET /v1/partner/orders?page=1&limit=100 отдаёт ваши ордера свежими вперёд и постранично, и в каждом есть заданный вами client_order_id — запуск собирается обратно по вашему же префиксу. Отдельный ордер можно синхронно обновить через POST /v1/partner/orders/{id}/refresh.
Что ещё собирают на этом же ключе
- Ссылки на оплату и инвойсы в криптовалютеОплата по ссылке и инвойсы для фрилансеров и подрядчиков: котировка по сумме счёта, зачисление напрямую на кошелёк получателя.
- Крипто-процессинг и эквайринг для бизнесаЧекаут для магазинов и SaaS: приём 100+ активов, зачисление в одном, сверка по вашему order id.
- API обмена криптовалют, SDK и виджетОбмен внутри кошелька, бота, агрегатора или сайта: стриминг котировок, один вызов на ордер, ваш интерфейс.
- Крипто-payroll для подрядчиков и распределённых командРегулярные выплаты реестру подрядчиков: свой актив и сеть у каждого, точная сумма на руки, сверка по периодам.
- Свой MCP-сервер для ИИ-агентовГотовый swapzilla-mcp одной строкой — или свой, на вашем партнёрском ключе, с белыми списками и лимитами.
- Стриминг котировок, живые курсы и price alertsSSE-стрим котировок, всегда свежий фид курсов и отслеживание ордеров — основа для алертов.
Как получить ключ
Зарегистрируйтесь в партнёрском кабинете — партнёрский id и api_key для заголовка X-API-Key выпускаются сразу. Ключ становится рабочим после активации: напишите в @swapzilla_support_bot и коротко опишите интеграцию. Все эндпоинты, поля и статусы — в документации partner API.