POST to the endpoint you registered.
Each partner has a single webhook endpoint per environment (Test and Live). You configure it in the developers portal, under Developers → Webhooks. Webhook endpoints are not managed through the API.
Setting up your endpoint
In the developers portal, open Developers → Webhooks and select the environment you’re configuring (Test or Live).- Enter your Endpoint URL. It must be an
httpsURL. - Choose the events you want to receive (see Event types). You must select at least one.
- Select Save endpoint.
- Edit the URL or the subscribed events. Saving replaces the whole event list.
- Pause deliveries without deleting the endpoint, and resume them later. See Retries and failure handling for what happens to events while paused.
- Rotate the signing secret.
- Delete the endpoint. Melio stops sending deliveries. Registering a new endpoint later creates a new signing secret.
Event types
Delivery payload
Each delivery is a lightweight notification. It identifies the affected resource, not its full state. Treat the payload as a signal to fetch the current resource (for exampleGET /payments/{id}) rather than as the source of truth, so you never act on a stale snapshot.
Every delivery includes these fields:
Some events carry a small
data object; most do not, and you should fetch the resource for its current state. Account created/deleted events include:
Verifying deliveries
Every delivery is signed so you can confirm it genuinely came from Melio and was not tampered with. Deliveries follow the Standard Webhooks specification and are signed with HMAC-SHA256 using your webhook signing secret. The signing secret looks likewhsec_<base64>. It is shown in the developers portal when you create your endpoint or rotate the secret. It is not an API key and can’t be used to call the API, so your webhook receiver never needs to hold an API credential.
Request headers
The signed content is the string
{webhook-id}.{webhook-timestamp}.{raw request body}.
Verifying with the Standard Webhooks library
The simplest option is the officialstandardwebhooks library. Pass it the signing secret exactly as shown in the portal, along with the raw request body and the request headers. It throws if the signature is invalid or the timestamp is more than 5 minutes old.
Verifying without a library
If you’d rather not add a dependency, compute the HMAC yourself. The HMAC key is the base64-decoded part of the secret afterwhsec_.
Rotating the signing secret
You can rotate the signing secret from Developers → Webhooks at any time, for example on a schedule or if you suspect it has leaked. The new secret is shown once, when you rotate. When you rotate, you choose how the old secret is retired:- Keep the old secret valid for 24h (default). For the next 24 hours every delivery is signed with both the old and the new secret, and
webhook-signaturecarries both signatures. Your verifier keeps accepting deliveries with either secret, so you can deploy the new secret at any point in that window without dropping events. After 24 hours only the new secret signs. - Rotate now. The old secret stops signing immediately. Use this if the secret may have leaked. Deliveries are signed only with the new secret, so update your verifier first or expect failed verifications until you do.
Handling deliveries reliably
- Verify every delivery. Check the signature and the timestamp before you trust the payload.
- Be idempotent. The same event may be delivered more than once. Deduplicate on
messageId(also sent as thewebhook-idheader) so you process each event only once. - Respond quickly with a
2xx. Acknowledge receipt fast and do heavy work asynchronously. Failed deliveries are retried. - Fetch current state. Because deliveries are notifications, always read the resource (
GET) to get its latest state before acting, rather than trusting a possibly out-of-order payload. - Pause safely. Pause the endpoint in the portal to stop deliveries during maintenance instead of deleting and recreating it. Note that events that occur while paused are dropped (see below).
Retries and failure handling
A delivery succeeds when your endpoint returns a2xx status. Any other outcome is a failure and Melio retries the delivery: a 4xx, a 5xx, a connection error, or no response at all. Redirects are not followed, and a 3xx response counts as a failed delivery. Point the endpoint URL directly at your handler.
Retry schedule
Melio makes up to 3 attempts per event, spaced roughly 45 minutes apart:- Within seconds of the event occurring.
- About 45 minutes after attempt 1.
- About 45 minutes after attempt 2.
Retries are per event, not per batch. One failing delivery does not delay or duplicate the deliveries for other events.
What gets retried
Because every failing status is retried, returning a
5xx is a legitimate way to ask for a retry, for example when your own datastore is briefly unavailable. Return a 2xx only once you have durably stored or queued the delivery.
Paused endpoints
Staying correct across retries
- Deduplicate on
messageId. The samemessageIdis used for every attempt of the same event, so it is a stable idempotency key. It is also sent as thewebhook-idheader. Treat a delivery whosemessageIdyou have already processed as a no-op and return2xx. - Don’t assume ordering. A retried delivery can arrive after newer events for the same resource. A retried
api.payment.updatedmay land after the payment has moved on again. AlwaysGETthe resource and act on its current state rather than on the payload, and never rely onoccurredAtordering to drive a state machine. - Respond quickly. Acknowledge with a
2xxas soon as the delivery is persisted, and do heavy work asynchronously. A slow handler burns the attempt and forces an unnecessary retry. - Expect a fresh timestamp on a retry. Each attempt is signed at the time it is sent, so the 5-minute timestamp check in your verifier applies to retries as well.
Related
- Timestamps - the
occurredAtformat. - External IDs - correlating events to your own records.
- Metadata - extra context carried on deliveries.