Verifying signatures
Every webhook request Moneybird sends includes a Moneybird-Signature header. Use it to verify that the request was sent by Moneybird and that the payload was not modified in transit. Verification is optional but strongly recommended for any production integration.
The Moneybird-Signature header
The header contains a timestamp and one or more signatures, separated by commas:
Code
t=— the delivery timestamp as a Unix epoch (seconds).v1=— an HMAC-SHA256 digest of the signed payload, hex-encoded.
During a secret rotation the header carries one v1= digest per currently active secret:
Code
Future signing schemes may introduce new prefixes. Ignore any scheme you do not recognise to prevent downgrade attacks.
How to verify
-
Split the header on
,and parse eachkey=valuepair. -
Extract
tand collect everyv1value. -
Build the signed payload by concatenating the timestamp, a literal
., and the raw request body as received on the wire:CodeThe body must be the exact bytes received. Re-serialising the JSON (for example after parsing and re-encoding) will change byte-for-byte content and break verification.
-
Compute
HMAC-SHA256(signing_secret, signed_payload)and hex-encode the result. -
Compare your computed digest to each
v1value using a constant-time comparison. Accept the request if any value matches. -
Reject the request if
tis more than 5 minutes away from the current time. The timestamp is part of the signed payload, so an attacker cannot modify it without also invalidating the digest, but a freshness check protects against replay.
Managing your signing secret
Retrieving the secret. When you create a webhook via POST /{administration_id}/webhooks.json, the response body includes a secret field. This is the only time the secret is exposed through the API — store it in your secret manager immediately. GET, activate, and deactivate responses do not include the secret field.
Recovery and rotation. If you lose the secret, or want to rotate it after a suspected leak, open the webhook on its detail page inside Moneybird. The secret can be revealed there after an MFA confirmation, and the same page supports rotation. When you rotate, you choose a grace period during which the previous secret remains valid alongside the new one.
Behaviour during a rotation grace period. While both secrets are active, every delivery's Moneybird-Signature header carries one v1= digest per active secret. Recipients that accept any matching digest (step 5 above) continue to verify successfully throughout the rollover — first against the old secret, and against the new secret once they have updated their stored value.
Existing webhooks. Webhooks created before signing was introduced have been backfilled with a secret, so signed requests are sent for every webhook regardless of when it was registered. To obtain the secret for a pre-existing webhook, reveal it through the webhook detail page in Moneybird.