Skip to Content
QuasarВебхуки

Вебхуки (Webhooks)

Коли транзакція, синхронізована з Quasar, досягає термінального статусу, Quasar надсилає захищений HTTP POST-запит на всі зареєстровані ендпоінти вашого додатку. Кожен запит підписується унікальним секретом ендпоінта за алгоритмом HMAC-SHA256, що дозволяє вашому бекенду безпечно оновлювати замовлення, баланси та надсилати сповіщення без постійного опитування блокчейну (polling).


🛠️ Реєстрація ендпоінта

У панелі керування перейдіть у розділ Webhooks та додайте ендпоінт для відповідного додатку:

ПолеПризначення та правила
URLКуди Quasar надсилатиме сповіщення. Обов'язково за протоколом https://, за винятком адреси localhost для локальної розробки.
EventsМаска * (всі події), або окремі події: transaction:success, transaction:failed, transaction:replaced.
Transaction type filter* для всіх типів операцій або точний тип транзакції з вашого Pulsar store (наприклад, SWAP, BRIDGE, STAKE).
ActiveНеактивні ендпоінти не отримують нових доставок і спроб повтору.

Quasar генерує секрет підпису (signing secret): рядок із префіксом whsec_ та 64 шістнадцятковими символами (32 криптографічні випадкові байти). Він зберігається в зашифрованому вигляді. Один додаток може мати до 500 ендпоінтів.


📨 Формат запиту та корисне навантаження

POST /api/webhooks/quasar HTTP/1.1Content-Type: application/jsonUser-Agent: Quasar-Webhook-Worker/1.0 (TuwaIO)x-quasar-signature: 5f3c… (hex HMAC-SHA256 of the body)x-quasar-event: Success
{ "txKey": "0x3a5f…", "hash": "0x3a5f…", "status": "Success", "action": "Success", "txType": "SWAP", "chainId": "1", "timestamp": 1790000000, "metadata": { "tokenIn": "USDC", "tokenOut": "ETH", "amount": 100 }}
Поле тілаОпис даних
txKey, hashУнікальний ключ транзакції в Pulsar та її ончейн-хеш у мережі (якщо він уже відомий). Для пакета EIP-5792 txKey — це ідентифікатор пакета, а hash — транзакція, що його виконала.
status, actionФінальний статус: Success, Failed або Replaced; також дублюється у заголовку x-quasar-event.
txTypeТип операції згідно з вашою бізнес-логікою в Pulsar.
chainIdМережа виконання у форматі CAIP-2: наприклад, "1" для Ethereum, або "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp" для Solana mainnet.
timestampЧас Unix (в секундах), коли було сформовано вебхук.
replacedTxHashДля Replaced: транзакція, яка зайняла nonce цієї, якщо її знайдено.
replacedReasonДля Replaced: repriced (та сама транзакція з вищою комісією, Speed up у гаманці), cancelled, replaced (інша транзакція) або unknown (її nonce зайняла транзакція, яку не вдалося знайти, тож кошти могли піти).
metadataПовний вихідний об'єкт payload, переданий клієнтом у Pulsar.

🔐 Верифікація підпису HMAC

Заголовок x-quasar-signature містить шістнадцятковий HMAC-SHA256 від сирого тіла HTTP-запиту, підписаний вашим whsec_.... Розраховуйте підпис строго над сирим текстом до парсингу в JSON та порівнюйте у сталий час:

src/app/api/webhooks/quasar/route.ts
import { createHmac, timingSafeEqual } from 'node:crypto'; export async function POST(request: Request) { const secret = process.env.QUASAR_WEBHOOK_SECRET; const signature = request.headers.get('x-quasar-signature'); if (!secret || !signature) { return Response.json({ error: 'Missing signature' }, { status: 401 }); } const body = await request.text(); const expected = Buffer.from(createHmac('sha256', secret).update(body).digest('hex'), 'hex'); const received = Buffer.from(signature, 'hex'); if (received.length !== expected.length || !timingSafeEqual(received, expected)) { return Response.json({ error: 'Invalid signature' }, { status: 401 }); } const event = JSON.parse(body) as { txKey: string; status: string; txType: string; metadata: unknown }; if (event.status === 'Success') { // Fulfill the order, credit the balance, notify the user... } return Response.json({ received: true });}

Коли транзакція завершується невдачею:

  • Solana: транзакція з помилкою в мережі отримує Failed одразу після підтвердження, без очікування фіналізації. Підпис, який так і не потрапив у мережу, отримує Failed, щойно мережа минає його lastValidBlockHeight (Pulsar зберігає його для транзакцій, надісланих через signAndSendSolanaTx; помилка каже, що blockhash застарів), інакше — через годину після синхронізації.
  • Пакети EIP-5792 отримують Failed через годину після синхронізації, якщо ваш застосунок так і не надіслав хеш їхньої транзакції (посібник із синхронізації).
Відповідайте успішним статусом 2xx якомога швидше: Quasar очікує відповіді максимум 10 секунд. Тривалі операції (відправку листів, генерацію звітів) виносьте у фонові черги. Обробник повинен бути ідемпотентним за парою (txKey, status).

🔁 Повтори доставок та аудит

  • Якщо доставка не вдалася (таймаут, помилка мережі чи статус, відмінний від 2xx), система автоматично повторює запит до 5 разів з експоненційним інтервалом (від 1 хвилини).
  • Усі спроби фіксуються в журналі Webhook Deliveries у панелі керування. Будь-які секретні ключі автоматично маскуються в тілі відповідей.
  • Ви можете вручну повторити невдалу доставку прямо зі списку записів у панелі, не частіше разу на хвилину.
  • Трекер може втратити транзакцію з поля зору, а вузол забуває замінений хеш. Коли Quasar згодом знаходить, що її включено в блок або замінено, запис виправляється, і ендпоінт отримує ще один вебхук із новим status: вважайте результатом останній.
  • Журнали доставок зберігаються до 3 місяців. Для довшого аудиту зберігайте події, які отримує ваш ендпоінт.
  • Кожна доставка списує лише 1 одиницю квоти (лише за першу спробу, повтори безкоштовні; дивіться Квоти та ліміти).

💻 Локальна розробка без ngrok

Хмарний Quasar не має прямого доступу до вашого localhost. Для локального тестування додайте ендпоінт із адресою http://localhost:3000/api/webhooks/quasar. Quasar Cloud автоматично зберігатиме події для локального тунелю local relay утиліти CLI quasar-sdk, яка отримує їх через захищений потік Server-Sent Events і пересилає на ваш локальний сервер з оригінальними заголовками підпису:

# .env.local: QUASAR_WEBHOOK_SECRET=whsec_... (the secret of the localhost endpoint)npx @tuwaio/quasar-sdk listen --forward-to http://localhost:3000/api/webhooks/quasar
Востаннє оновлено