Concepts
Webhooks
Signed, at-least-once, replayable. The backbone of reconciliation.
We deliver events to your HTTPS endpoint as JSON POSTs. Delivery is at-least-once: your receiver must deduplicate byevent.id, which stays stable across retries and manual replays.
Verifying signatures
Each delivery carries a signature header computed with your endpoint’s signing secret. Verify before trusting the payload; reject anything older than 5 minutes to block replays by third parties.
GlobbaPay-Signature header
GlobbaPay-Signature: t=1721825632,v1=5257a869e7… signed_payload = t + "." + raw_body expected = HMAC_SHA256(signing_secret, signed_payload) valid = timing_safe_equal(expected, v1) && now - t < 300
Node.js verifier
import { createHmac, timingSafeEqual } from "node:crypto";
export function verify(header, rawBody, secret) {
const { t, v1 } = Object.fromEntries(
header.split(",").map((p) => p.split("=")),
);
const expected = createHmac("sha256", secret)
.update(`${t}.${rawBody}`)
.digest("hex");
const fresh = Date.now() / 1000 - Number(t) < 300;
return fresh && timingSafeEqual(
Buffer.from(expected), Buffer.from(v1),
);
}Retries and replay
Non-2xx responses are retried with exponential backoff for 24 hours. Every attempt is visible in the dashboard delivery log with the response code and next retry time, and any event can be replayed manually — same event ID, new delivery.
Event types
| Field | Type | Description |
|---|---|---|
| inflow.received | event | Money landed in a virtual account. Carries amount, currency, account, payer attributes, ledger_ref. |
| payout.status.changed | event | A payout moved to processing, completed, failed, or cancelled. Failures carry a failure_code. |
| account.status.changed | event | An account became active, suspended, or closed. |
| customer.status.changed | event | Screening resolved: approved, needs_info, or rejected. |