Webhooks

Webhooks are the asynchronous source of truth. Yusker POSTs an event to your endpoint whenever a transfer settles, a payout is paid, a dispute opens, or a merchant's status changes.

Register an endpoint

Configure an HTTPS URL in the dashboard (or via API). Yusker signs each delivery so you can verify it came from Yusker.

curl -u "$YUSKER_KEY" "$YUSKER_BASE/webhooks" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://api.yourapp.com/webhooks/yusker", "enabled_events": ["transfer.*", "dispute.*"] }'

Event types

transfer.succeeded
eventoptional
A sale captured and is settling. Close the check here.
transfer.failed
eventoptional
A sale was declined or reversed. No funds moved.
payout.paid
eventoptional
Settlement funds were paid out to a merchant's bank.
dispute.opened
eventoptional
A cardholder disputed a transfer (chargeback). Respond with evidence.
merchant.updated
eventoptional
A merchant's onboarding or processing state changed.

Event payload

{
  "id": "EVxxxx",
  "type": "transfer.succeeded",
  "created_at": "2026-07-01T14:38:25Z",
  "transfer": {
    "id": "TRxxxx",
    "state": "SUCCEEDED",
    "merchant": "MUxxxx",
    "amount": 5000,
    "fee": 175,
    "currency": "CAD",
    "tags": { "check_id": "4823" }
  }
}

Verify the signature

Each delivery carries a signature derived from your webhook secret. Verify it before acting, and reject anything that doesn't match — an unverified webhook must never move money.

import crypto from "crypto";

function verifyYuskerSignature(req) {
  const sig = req.headers["yusker-signature"];
  const expected = crypto
    .createHmac("sha256", process.env.YUSKER_WEBHOOK_SECRET)
    .update(req.rawBody)
    .digest("hex");
  return crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
}
Be idempotent
Yusker retries deliveries until it receives a 2xx, so the same event can arrive more than once. Key your handler on event.id(or the transfer id) and make the side-effect a no-op if you've already processed it.

Retries

Non-2xx responses are retried with exponential backoff for up to 24 hours. Return 200 as soon as you've durably enqueued the event.