Webhooks
A session does not finish when your customer closes the widget. It finishes when the last public administration answers — which can be seconds later, or minutes later when the CIRBE report from the Banco de España is involved. Polling for that moment means asking a question whose answer is “not yet” almost every time.
A webhook inverts it: you register an HTTPS URL, and INFONITE sends your backend an HTTP POST the moment something happens. You do nothing until there is something to do.
Webhooks are the recommended integration. Everything they deliver is also available by polling Get Session State and Get Session Results — keep that path as your fallback, not as your design.
The four events
Each event is delivered independently, and you subscribe to as many or as few as you need. Every one carries the same envelope, so a single handler can serve all four.
The customer opened the widget. Useful to mark a case as in progress and to start your own timeout.
The customer signed the consent. From this moment the sources may be queried on their behalf — this is the event your audit trail wants.
The customer left while a source was still answering. Everything gathered so far, in the final schema. Not the end of the session.
The session is over — with the complete results, or with the reason it did not complete. This is the one that closes the verification.
partial is an early view, never a conclusion. It exists so you can move before the slow sources answer, and the records in it may still change, be corrected, or appear for the first time. Branch on is_closed, exactly as described in knowing when a session is finished.
What a delivery looks like
A single POST, with a JSON body, to the URL you registered.
The envelope is identical across the four events — only event, status_code and data differ:
Fired when the session finishes — successfully with the complete results, or on cancellation/failure with the reason.
Payload class discriminator — always this value for Spain Public Administration events.
The event type: ended.
Verification results payload.
- On success (COMPLETED):
- If an
aes_keywas provided during session creation, the results are delivered encrypted. Please refer to the Payload Decryption section of the API introduction to decrypt them intoFlowResultsSchema. - If no
aes_keywas specified, this field is not informed (null), and you must retrieve the results manually using the session API.
- If an
- On cancellation or failure, it contains error/feedback details conforming to
WebhookEndedErrorPayload.
customer_id is yours. It is the identifier you supplied at Create Session, so a handler can route the event to the right case in your system without a lookup table.
Answer quickly, and answer 2xx
Authenticating the call
Your endpoint is on the public internet, so it needs to know that a delivery really came from us. Each destination can carry one static authentication header, sent on every delivery to it:
Pick the header
Either Authorization or a custom x-… header of your own — x-webhook-token, x-infonite-signature, whatever your gateway already understands. Headers the delivery itself owns (Host, Content-Type) cannot be overridden.
The secret is write-only. You can set it and you can replace it; nothing in the platform — no screen, no endpoint, no support agent — will read it back to you. Store your own copy when you mint it.
Never put credentials in the URL. A destination like https://user:pass@api.yourcompany.com/hook is refused: it would be stored in clear and shown on every read, which is the opposite of what the encrypted header next to it is for. The same goes for a token in a query parameter — see below.
Where the calls come from
Deliveries leave through our API gateway, from a fixed set of addresses. If your endpoint sits behind a firewall that only accepts known sources, you can allow-list them.
The current list — production and pre-production — is shown in the Console, beside your application’s webhook settings, and support will provide it on request. It is not published here on purpose: an address list printed in a document goes stale the day we scale or fail over, and a stale copy in your firewall is an outage you would discover as missing deliveries.
An allow-list is a filter, not an authentication. It proves a request came from INFONITE’s infrastructure — not that it came from your application, and not that the body was not tampered with. Keep the authentication header; the allow-list narrows who can reach your endpoint, the header proves who is calling.
The destination URL
HTTPS, to a public host
Plain http, private addresses (10.x, 192.168.x, 172.16-31.x), loopback and link-local ranges, and internal-only names are all refused. A stored destination is fired from inside our platform on a schedule, so it has to prove it points at the open internet.
Sending your own context along
hooks_extra_data is a dictionary you set per session, in settings at Create Session. Every key and value in it is appended to the delivery as query parameters, and the same template variables work inside them:
Your endpoint then receives ?case=A-1029&stage=underwriting&session=644599da47847b79c03cc950. It is the natural place for the correlation id of whatever process opened the session.
hooks_extra_data is not a place for secrets. Query strings end up in access logs, proxies and browser-adjacent tooling. Authentication belongs in the header.
Encrypted payloads — and what travels without a key
We never send personal data over a webhook unless you gave us a key to encrypt it with.
The aes_key you supply at Create Session is not an option that improves the payload — it is the condition for there being a payload at all.
That gives you two delivery modes, and choosing between them is an architectural decision, not a preference:
The rest of the envelope — session_id, customer_id, event, status_code, date — is always in clear, in both modes. It carries no personal information, so you can route, log and deduplicate an event without decrypting or fetching anything.
The keyless mode is a perfectly good design, and for some architectures it is the better one: the sensitive records never touch your webhook endpoint at all, they are pulled over an authenticated call from the service that is going to process them. What is not a design is expecting data to be there without a key — it will not be.
Configuring your webhooks
Webhook configuration is made of two pieces, which is what lets several events share one destination and lets you rotate a domain in one place:
Self-service is coming to the console — very soon. 🚀 The screens to create endpoints, bind events to them and rotate the authentication header are being built right now.
In the meantime, contact support with the destination URL for each event you want to receive and, if you want one, the header name and value to send. We will configure it for your application and confirm when it is live. If you have no rules configured yet, no events are delivered — polling still works, and the widget still runs normally.
The hooks/list, hooks/update and hooks/delete endpoints are deprecated and no longer configure anything. They remain in the API so existing tooling does not break, but a change made through them has no effect on delivery. Use the process above until the console screens ship.