Every webhook delivery is signed using HMAC-SHA256. The signature allows recipients to verify that the webhook originated from the Formance webhooks service and has not been tampered with.
- Secrets are 24 random bytes, base64-encoded
- A secret is auto-generated when creating a config if none is provided
- Secrets can be rotated via
PUT /configs/{id}/secret/change - Custom secrets must be exactly 24 bytes (before base64 encoding)
The formance-webhook-signature header contains: v1,<base64-hmac-sha256>
The signed content is: {webhook_id}.{unix_timestamp}.{json_body}
The v1 prefix enables future signature scheme upgrades without breaking existing integrations.
The service follows strict rules about what appears in logs:
- Environment variables —
os.Environ()is never dumped to logs, as it typically contains database credentials, API keys, and other secrets - Webhook secrets — Config objects are never logged with
%+vor any format that would expose thesecretfield. Onlyconfig.IDandconfig.Endpointappear in log messages - Event payloads in traces — Raw event payloads are not stored as OpenTelemetry span attributes, as they may contain sensitive business data
- Event types being processed
- Config IDs and endpoints matched for delivery
- Webhook IDs and delivery status
- Retry claim counts and webhook IDs
The REST API supports OAuth2 client credentials authentication via the --auth-* flags. When enabled, all config management endpoints require a valid bearer token. The /_healthcheck and /_info endpoints are unauthenticated.
- Endpoint URLs are validated (must be parseable, non-empty)
- Event types must be non-empty strings
- Secrets must be valid base64 encoding exactly 24 bytes when decoded
- Request bodies reject unknown JSON fields (
DisallowUnknownFields) - Query filters reject unknown filter keys with an error (no silent pass-through)
- All queries use parameterized statements (via bun ORM) — no SQL injection risk
- The atomic claim pattern for retries uses
WHERE status = 'to retry'scoping to prevent double-processing - Config deletion verifies existence before deleting (SELECT then DELETE)