Overview

Webhooks push real-time notifications to your server when events occur on EU Rails, so you do not have to poll the API. You create a subscription with an HTTPS endpoint URL and a list of event types; Balansas then POSTs a signed JSON payload to that URL whenever a matching event fires.
1

Create a subscription

POST /webhooks with your HTTPS url and the eventTypes you want. The response returns a signing_secret — store it now (see Signing below).
2

Verify the signature

On every delivery, recompute the HMAC and compare it to the X-Webhook-Signature header before trusting the payload.
3

Acknowledge with 2xx

Return any 2xx status to mark the event delivered. Anything else (or a timeout) triggers a retry.
The endpoint URL must be HTTPS and must not resolve to a private or reserved address. Subscriptions are validated at creation and again before every delivery.

Event types

EU Rails (Fiat Republic) subscriptions can listen for these event types:
payment.created, payment.status_updated, payment.completed, payment.failed
fiat_account.created, fiat_account.status_updated, fiat_account.balance_updated
virtual_account.created, virtual_account.status_updated, virtual_account.balance_updated
end_user.created, end_user.status_updated, end_user.review_required
payee.created, payee.status_updated
A subscription must list at least one event type and at most 50.

HMAC signing & verification

Every delivery carries three headers:
HeaderDescription
X-Webhook-IdThe subscription ID the event was delivered for.
X-Webhook-TimestampUnix timestamp (seconds) when the delivery was signed.
X-Webhook-Signaturesha256=<hex> — the HMAC of the signed message.
The signature is computed as HMAC-SHA256 over the string {timestamp}.{body} (the timestamp, a literal dot, then the raw request body), keyed by your subscription’s signing secret, and hex-encoded with a sha256= prefix. To verify, recompute the HMAC using the exact raw request body (do not re-serialize the parsed JSON), the X-Webhook-Timestamp value, and your signing secret, then compare in constant time:
import crypto from "node:crypto";

function verify(rawBody, headers, signingSecret) {
  const timestamp = headers["x-webhook-timestamp"];
  const received = headers["x-webhook-signature"]; // "sha256=<hex>"
  const expected =
    "sha256=" +
    crypto
      .createHmac("sha256", signingSecret)
      .update(`${timestamp}.${rawBody}`)
      .digest("hex");
  const a = Buffer.from(received);
  const b = Buffer.from(expected);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}
The signing secret (whsec_…) is returned only when you create a subscription or rotate its secret. Store it securely at that moment — it cannot be retrieved later. Listing a subscription returns only a non-sensitive prefix (signing_secret_prefix).

Delivery & retries

Your endpoint should respond with a 2xx status to acknowledge receipt. Any 4xx, 5xx, or timeout marks the delivery as failed and schedules a retry with exponential backoff:
AttemptDelay
1Immediate
2After 1 minute
3After 5 minutes
4After 30 minutes
5After 2 hours
FinalAfter 24 hours
After repeated consecutive failures a subscription may be auto-disabled (is_active: false, with disabled_at and disabled_reason set). Re-enable it by updating the subscription once your endpoint is healthy again.
Deliveries can be repeated due to retries or network conditions. Process events idempotently: dedupe on the event id and always return 2xx for an event you have already handled.
You can inspect past attempts via the delivery log and re-send a specific failed attempt with Retry a failed webhook delivery. A delivery that already succeeded cannot be retried.

Rotating the signing secret

Rotate the secret if it may have been exposed. Rotate a webhook signing secret generates a new whsec_… value and returns it once in the response. Update your verification code to the new secret immediately — deliveries signed after rotation use the new secret.

Sending a test event

Use Send a test event to a webhook to confirm your endpoint is reachable and your signature verification works. It delivers a signed payload with event webhook.test to your configured URL and returns the HTTP status, response time, and any error from the attempt.

List webhook subscriptions

See your configured subscriptions.

Create a webhook subscription

Register an endpoint and event types.

Rotate a signing secret

Issue a fresh signing secret.

Send a test event

Verify reachability and signing.