Hbridge Docs
API reference

Webhooks & events

Hbridge delivers signed, at-least-once webhooks to your endpoint as things happen. Set your endpoint URL and get your signing secret in the dashboard under Webhooks. Then verify every request and dedupe on the event id.

Event types#

Your endpoint receives these event types:

FieldTypeRequiredDescription
address.provisionedeventnoA deposit address was created for a user on a chain.
deposit.pendingeventnoA deposit was detected but has not yet reached finality.
deposit.confirmedeventnoA deposit reached finality and counts toward your balance.
deposit.reorgedeventnoA previously reported deposit was dropped by a chain reorg.
payout.completedeventnoA payout settled on-chain (net sent to your address).
payout.failedeventnoA payout could not be completed.

Payload#

Every event is a JSON envelope with a stable type, a unique id (dedupe on this), a created_at timestamp, and event-specific fields.

Example: deposit.confirmed
{
  "type": "deposit.confirmed",
  "id": "evt_9f2c...",
  "user": { "id": "6a44...", "external_ref": "user_42" },
  "chain": "ETH",
  "token": "USDC",
  "amount": "2",
  "txid": "0x3646...98f9a",
  "created_at": "2026-07-02T10:07:00.000Z"
}

Verify signatures#

Each request carries an X-Hbridge-Signature header of the form t=<timestamp>,v1=<hmac>. Compute the HMAC-SHA256 of "<t>.<rawBody>" using your signing secret and compare it to v1 with a constant-time comparison. Use the raw request body (not re-serialized JSON).

Header
X-Hbridge-Signature: t=1719914820,v1=9c8f...e3a1
Node.js verification
import crypto from "node:crypto";

function verify(rawBody, header, secret) {
  const parts = Object.fromEntries(
    header.split(",").map((kv) => kv.split("=")),
  );
  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${parts.t}.${rawBody}`)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(parts.v1),
  );
}

Event API#

Every outbound event is also stored, so you can audit what was sent and replay anything your endpoint missed (e.g. during downtime).

GET/v1/events

List outbound events, newest first. Paginated.

Query
FieldTypeRequiredDescription
typestringnoFilter by event type, e.g. deposit.confirmed.
statusstringnoOne of pending, delivered, failed.
limitnumbernoPage size, 1–200, default 50.
cursorstringnoPrevious next_cursor.
200 Response
{
  "events": [
    {
      "id": "6e01...",
      "event_id": "evt_9f2c...",
      "type": "deposit.confirmed",
      "delivery_status": "delivered",
      "attempts": 1,
      "last_attempt_at": "2026-07-02T10:07:03.000Z",
      "delivered_at": "2026-07-02T10:07:03.000Z",
      "created_at": "2026-07-02T10:07:00.000Z"
    }
  ],
  "next_cursor": "6e01...",
  "has_more": true
}
GET/v1/events/:id

Fetch a single event, including the full payload Hbridge sent.

Path
FieldTypeRequiredDescription
idstringyesThe event id (not event_id).
POST/v1/events/:id/redeliver

Re-send an event to your endpoint (even one already delivered). Returns 202; 422 no_webhook_configured if you have no endpoint set.

202 Response
{ "id": "6e01...", "event_id": "evt_9f2c...", "status": "pending" }