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. The deliveries of the subscription route — new_lead, pre_approve,
reevaluation and installment_paid — 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. A UUID |
eventType | string | The event's name — new_lead, pre_approve, reevaluation or installment_paid. Not present on loan_approved |
data | object | Event-specific payload. Its shape depends on the event |
Why loan_approved has no eventType​
The real-estate and mortgage-lender events share a registration route, so one destination can legitimately be
subscribed to several of them. eventType tells you which one just arrived without inspecting data.
loan_approved deliveries never carry eventType, whichever destination receives them. It is
the BNPL event, and a BNPL partner's destinations are subscribed to loan_approved alone — the
BNPL route and the partners portal both enforce it for BNPL partners, and they verify by hmac
(see Verify HMAC Signatures). There is nothing to
disambiguate, and widening what a frozen, externally-verified signature covers is not a risk
worth taking for a field that integration 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.
It is assigned per destination: when one event goes to two of your destinations, each delivery
carries a different eventId. If several destinations feed the same system, deduplicate per
destination.
For installment_paid, eventId is stable: there is one per installment and destination, and
every send of that pair carries it — the first attempt, the retry and every nightly resend.
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, and checked again before every delivery |
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 |
reevaluation | 5 seconds | one retry |
new_lead | 3 seconds | none — a single attempt |
installment_paid | 5 seconds | one retry, then a resend every night until a 2xx |
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. installment_paid is the one exception: banca.me sends it again every night until your
endpoint answers 2xx, or until it rejects it with a 4xx other than 408 and 429 — see
its delivery rules. 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, 12 fields |
pre_approve | Real estate | The risk evaluation, flat, in up to 52 fields |
reevaluation | Real estate | A lead re-evaluation: its result, what worsened and the refreshed risk data |
installment_paid | Mortgage lender | A collected installment of one of your loans: amounts, dates and payment provider |
All five 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