Webhook Event Format
This page describes what every webhook delivery looks like, regardless of which integration you are on: the envelope, how events are identified, and how delivery behaves.
The contents of data depend on the event, and each event is documented in the
Event Catalog.
Event Structure​
When an event occurs that matches one of your destinations, banca.me sends an HTTP POST to that
destination's URL with a JSON body. new_lead and pre_approve deliveries carry an eventType
field; loan_approved deliveries do not — see below for why:
{
"eventId": "9f2a1c4e-3b8d-4f71-a205-6c9e8d0b1a37",
"eventType": "pre_approve",
"data": {}
}
| Field | Type | Description |
|---|---|---|
eventId | string | Identifies the event, not the delivery attempt |
eventType | string | The event's name — new_lead or pre_approve. Not present on loan_approved |
data | object | Event-specific payload. Its shape depends on the event |
Why loan_approved has no eventType​
new_lead and pre_approve share a registration route, so one destination can legitimately be
subscribed to both. eventType tells you which one just arrived without inspecting data.
loan_approved deliveries do not carry eventType, and structurally cannot need it: a
loan_approved destination is BNPL's frozen, hmac-verified route (see
Verify HMAC Signatures), and it can never be combined with
another event type on the same URL — there is nothing to disambiguate, and widening what a
frozen, externally-verified signature covers is not a risk worth taking for a field that route
never needed.
If you built a discriminator against data's shape before eventType existed, it still works —
see Telling the events apart for that
approach, kept for loan_approved and for anyone who prefers it regardless.
eventId and idempotency​
eventId identifies the event itself. A retry carries the same eventId as the original
attempt, so it is what you use to recognise a duplicate.
Store processed ids and skip anything you have already handled:
async function handleWebhook(event) {
const { eventId, data } = event;
if (await alreadyProcessed(eventId)) {
return; // duplicate delivery — nothing to do
}
await process(data);
await markProcessed(eventId);
}
Delivery behaviour​
These hold for every event:
| Destination scheme | HTTPS only |
| Redirects | Not followed |
| Private addresses | Rejected at registration |
Timeouts and retries are not universal — they depend on the event:
| Event | Timeout | Retries |
|---|---|---|
loan_approved | 5 seconds | one retry |
pre_approve | 5 seconds | one retry |
new_lead | 3 seconds | none — a single attempt |
Respond 2xx quickly and do the real work afterwards. A handler that finishes its processing
inline before responding will time out on anything slow, even though the data arrived intact.
That matters most for new_lead, which has both the tightest timeout and no second chance.
Once an event exhausts its attempts it is not delivered again, and there is no self-service
replay. For new_lead that means a single failure loses the event — see
Best Practices for the recovery path.
To recover a range of missed events, contact us.
What arrives in data​
| Event | Integration | Payload |
|---|---|---|
loan_approved | BNPL | Loan terms and instalment schedule |
new_lead | Real estate | Identity and contact, 11 fields |
pre_approve | Real estate | The risk evaluation, flat, in 51 fields |
All three are documented field by field in the Event Catalog. If you are not sure which apply to you, see Which Webhook Integration Is Yours.
Next steps​
- Verify that deliveries really came from banca.me — which page depends on your integration: Verify HMAC Signatures if you are BNPL, Verify the Webhook Token if you are real estate
- Build a handler that holds up in production: Best Practices