> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://infonite.dev/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://infonite.dev/_mcp/server.

# Changelog

Stay up to date with new features, API updates, portal connector improvements, and security enhancements across all INFONITE products and widgets.

You can subscribe to these updates via [RSS](./changelog.rss).

## Vehicles — the registration in force, and registration_date deprecated

### Vehicles: each registration in a field of its own

* **`last_registration_date`, new**: the registration in force, the day the vehicle was registered in `country`.
* **`first_registration_date`**: the vehicle's first registration, in any country — the original one abroad for an imported vehicle. The same day as `last_registration_date` for a vehicle first registered in `country`.
* **An absent one means only that the connection does not give it**: the date present may well be both.
* **`registration_date` is deprecated**: depending on the connection it is one registration or the other. It is still there and filled as before — move to the two fields above. How to read them: [Registration dates](/guides/data-models/vehicles#registration-dates).
* **Fixed**: one connection returned the dates of vehicles, insurance, driving licences and identity documents one day early.

## Vehicles — every incident flag explained, and an expired inspection among them

### Vehicles: the incident report, flag by flag

The [Vehicles](/guides/data-models/vehicles#what-each-flag-means) data model now explains every incident flag in `simple_vehicle_report.flags`, with the DGT's own name for it — *Embargo*, *Precinto*, *Carga de entidad financiera*, the deregistrations — and what it means for a vehicle you buy, finance or insure.

* **`inspection_expired`, a new flag**: the vehicle's inspection (ITV) had expired on the day of the report, so the vehicle may not circulate. It is raised whichever source returned the vehicle; when no source issued a report, the report holds this flag alone.
* **A flag always means incidents**: `has_incidents` is `true` whenever `flags` names one. Having no flags never makes it `false`: a vehicle can carry incidents no flag names.
* **Each flag once**: `flags` holds each code once, in no particular order.
* **The report comes when you ask for it**: `{"code": "vehicles_data", "configurations": {"simple_vehicle_report": true}}`. Without it, no report is returned.

## You choose the administrations, and the order — the Banco de España and the DGT among them

### Spain Public Administration Flow: the administrations are yours to choose, in order

`settings.allowed_sources` is now an ordered list: the administrations your customer may be asked to sign in to, in your order of preference. The session goes to the first one that returns something still missing, and never back to one it passed over. Leaving an administration out spares your customer that sign-in, never data that another administration you allow returns. Without the list, your application's default applies, else `["tgss", "aeat", "citizen_folder"]`; a list that leaves a feature you ask for with no administration to return it is refused when you [create the session](https://infonite.dev/flows/spain-public-administration/api-reference/spain-public-administration-api/sessions-management/flows-es-public-administration-v-1-session-create). Every choice, and what it gives you, is in [Choosing the administrations](/flows/spain-public-administration/sources).

* **The Banco de España is an administration you can allow** (`bde`): the CIRBE report from its own service, without signing in at the Social Security. With `bde` in the list, the report is read there and at no other administration.
* **The DGT is an administration like the others** (`dgt`): the driving licence and the vehicles from the DGT itself, wherever you place it in the list.
* **The driving licence and the vehicles are combined across administrations**: what one returns completes what another left out — licence categories, points history, vehicles —, so a later sign-in adds to them instead of repeating them.
* **`fixed_parameters.birth_date`**, optional: give your customer's date of birth and the Banco de España's screen does not ask for it.

> **Warning**
>
> **`fixed_parameters.user_email` is required whenever you ask for `credit_registry_data`**, whichever administration reads the report: the CIRBE report is requested with it. A session without it is refused at creation with a `422` on `fixed_parameters.user_email`.

### Spain Public Administration Flow: what Cl\@ve allowed, said in the results

When your customer's Cl\@ve keeps an administration out, `messages` says so once, as an `info` under a stable `message_id` — [What the session tells you](/flows/spain-public-administration/overview#what-the-session-tells-you-beside-the-data):

* `clave_not_registered` — they are not registered in Cl\@ve. No administration that signs in with Cl\@ve is offered again; the Social Security is still reached through its SMS access.
* `clave_level_insufficient` — their Cl\@ve registration is below the level an administration requires; at `["data", "credit", "registry"]` when it is the Banco de España's level for the CIRBE report. It replaces the `credit_registry_insufficient_clave_level` warning.
* `clave_access_unavailable` — signing in with Cl\@ve failed repeatedly, or the access was blocked. It may work again later, in a new session.

### Spain Public Administration Flow: how a session ends, and why your customer left

* **`status_code` says who ended the session**, status by status in [How a session ends](/flows/spain-public-administration/overview#how-a-session-ends).
* **Abandoning one connection is not leaving the session.** A sign-in your customer abandons can be started again; one abandoned after signing in keeps what had arrived, and the session moves on to the next administration. A session that connects no administration because your customer abandoned one closes as `CUSTOMER_CANCELLED`, no longer `SYSTEM_CANCELLED`.
* **Why they left**: when your customer leaves from the widget, [`es-public-administration:ended`](/flows/spain-public-administration/api-reference/spain-public-administration-api/webhooks/webhook-es-public-administration-ended) carries `user_feedback.reason` — `took_too_long`, `missing_information`, `distrust`, `unclear_steps` or `other` — and, when they wrote something, `user_feedback.feedback` in their own words.
* **Leaving while a connection is in progress asks your customer to stay**: going on is the obvious choice, and abandoning that one connection stays within reach.

### Spain Public Administration Flow: records from a second administration reach the results

Pensions, income tax, academic degrees, properties and the CIRBE report are read from the connection that holds them, not from the first one that could have: a record that a second administration returned, when the first could not, now reaches the results.

## Taxes, academic records and properties in the Spain Public Administration Flow

### Spain Public Administration Flow: three more features

A session can now ask for three more features in `settings.executions_features`, alongside the ones it already reads:

* **`yearly_individual_tax`** — the person's fiscal data from the Agencia Tributaria, year by year: the last three closed fiscal years by default, up to five with `last_n_years`. What employers, banks and lenders reported, payer by payer — every home loan with its lender and the person's share — and the filed income-tax return attached, with its verification code. See [Taxes](/guides/data-models/taxes).
* **`academic_data`** — the official degrees the person holds, university and non-university, from the Ministry's registries through the Carpeta Ciudadana. See [Academic Records](/guides/data-models/academic).
* **`properties_data`** — the real estate the person holds in the Cadastre, through the Carpeta Ciudadana, with its cadastral value and every co-owner with their share. See [Properties](/guides/data-models/properties).

All three are optional. Each of these administrations is one more Cl\@ve identification for the person, after the Social Security's, so ask only for what you will use.

The [Spain Public Administration overview](/flows/spain-public-administration/overview#use-cases) now lists the use cases these records open — mortgage underwriting, asset verification, CV checks, professional drivers and more —, each with the sources it reads.

## A fairer income floor for recent hires

### Labor check: a partly worked month no longer sets the income floor

The **[labor check](/guides/data-models/labor-check)**'s [income floor](/guides/data-models/labor-check#income-floor) is the lowest of the last twelve months, after deductions. A month in which a job started or ended part-way through holds only the days worked, so for a recent hire it set the floor far below their salary. Such a month is now left out once at least two full months are on record; with less evidence it still counts, so the floor stays a floor. The method is now `floor-v3`.

* **`observed_months`** on the income floor says how many months it was measured over: fewer than three means it rests on little evidence, typically a recent hire.

## Financial Rider gets its reference, and every run stays in its own environment

### Financial Rider: Open Banking in a widget we host, now documented end to end

**[Financial Rider](/flows/financial-rider/overview)** has its public reference. Create a session from your backend — naming the markets and kinds of bank your customer may choose from, or the one bank to connect —, send your customer to the widget, and read one financial position merged from every bank they connected, up to three per session: accounts, cards, deposits, loans, investments and direct debits, in the same shape direct executions return.

* **Three webhooks** tell your backend what happened: `financial-rider:started`, `financial-rider:consent` and `financial-rider:ended`. Their data travels **only encrypted**, with the key the session was created with; without one, each event is a notification and the results are read over the API. [Webhooks](/flows/financial-rider/webhooks).
* **A bank that turns the credentials down is never taken away.** Your customer is warned before trying it again, so they do not lock their own access, and decides.
* **One-shot or recurring access.** A session reads your customer's banks once — or, with recurring access, your customer connects once in the widget and your backend refreshes those banks afterwards, without them, through the direct executions API. Built for bank reconciliation, money management and monitoring: [Recurring Access](/flows/financial-rider/recurring-access).
* Where your customer lands when they are done is yours to choose, exactly as in Spain Public Administration: [Redirects & Completion](/flows/financial-rider/redirects).

The endpoints, the schemas and the events are in the [Financial Rider API reference](/flows/financial-rider/api-reference/overview).

### Spain Public Administration: a production session needs the product enabled

A production session of [Spain Public Administration](/flows/spain-public-administration/overview) now requires the application to be enabled for the product, exactly as Financial Rider's does: without it, [Create Session](https://infonite.dev/flows/spain-public-administration/api-reference/spain-public-administration-api/sessions-management/flows-es-public-administration-v-1-session-create) answers `403 insufficient_capabilities@product:es_public_administration`. Every application already running the flow in production has been enabled before this went live; a sandbox session needs nothing.

### Sandbox and production never mix

* **A widget session runs engines of its own environment only.** A sandbox session never opens a real institution (`503 engine_not_available_for_sandbox_sessions`), and a production session never opens a demo engine (`503 engine_not_available_for_production_sessions`), so nothing a production session returns comes from a demo.
* **The engine catalogue of direct executions lists one environment**, the one you ask for: [List your engines](https://infonite.dev/direct-executions/api-reference/direct-executions-api/engines/direct-executions-v-1-engines-list) takes `environment` — `production` or `sandbox`, by default your application's. A production application may list the sandbox engines to rehearse with; a sandbox application lists sandbox engines only, and asking it for `production` answers `403 production_not_enabled_for_this_app`.
* **A sandbox application is refused a real institution with `engine_not_available_for_sandbox_apps`.** `engine_not_available_for_current_company` no longer exists: nothing restricts an engine by company.
* An engine that is still being built is neither listed nor launched, for any application.

> **Warning**
>
> **An engine alternative is named, never numbered.** An `engine_reference` ends in the alternative's name — `website`, `mobile`, `api` or `other` —, and a number in its place (`0` to `3`, or a reference ending in `-1`) is refused as invalid. Take the references from [List your engines](https://infonite.dev/direct-executions/api-reference/direct-executions-api/engines/direct-executions-v-1-engines-list), which returns them named.

### Downloading attachments: the answers it really gives

The attachment download of the widget flows documents exactly what it answers — `401` and `403` for the application secret, `404` for a session or a document that is not yours, `422` for an id that is not one, and `429` past one download every 5 seconds per document. It never answered `202` nor `412`, which its page used to list: a handler written for them can go. It is published in the [Financial Rider reference](https://infonite.dev/flows/financial-rider/api-reference/financial-rider-api/sessions-results/flows-attachment-download) too, for the receipts a bank keeps with a direct debit.

## The credit registry reads the official report, and the labor check names its holder

### Credit registry: the whole report, read from the Bank of Spain's document

The **[credit registry](/guides/data-models/credit-registry)** is now filled from the official CIRBE report itself: every operation the holder has with each institution, the minor risks, and the totals, exactly as the Bank of Spain printed them. The report still travels as an [attachment](/guides/data-models/attachments), and its metadata now carries the verdict on its **digital signature** — who signed it and whether the signature is valid.

> **Warning**
>
> **If you integrated against the sandbox, the operation keys changed shape.** Each key the report prints — product type, intervention, joint liability, residual maturity, guarantees, situation — now arrives as its **meaning** (`financial_credit`, `direct_holder`…), and the code exactly as printed travels beside it in a field of its own, named after the key with `_code` (`product_type_code: "V32"`). Read the meaning; keep the code for display or audit.

Two more things to know:

* **Every amount is always present.** One the report does not give reads as unknown — currency `***`, amount `NaN` — as on every other money field of the platform, never as zero.
* **The holder is reported only when the report could be read.** A report that could not be interpreted still arrives attached, with the product saying what is missing.

### Labor check: who the reports are about, and a longer history

The **[labor check](/guides/data-models/labor-check)** carries two new fields, `holder_name` and `identifier` (the DNI or NIE), exactly as the official Social Security reports print them. They record what the documents say; comparing them with your customer's identity is your decision. When the two reports name the same person differently, `holder_name` is not reported and the product is worth a careful review — the data model page explains what to look at.

The contribution history now covers **five years by default and up to eighty**, through the feature's `from_date` — see [Features](/guides/features). A date outside that range is adapted, never refused: further back than eighty years reads eighty, and less than a year back reads one year. When the official reports cannot be used and the history is read from the Social Security's pages instead, it covers the last twelve months.

### Direct Executions: tokenizing without the capability answers `403`

Asking for `base_configurations.tokenized_access` from an application that is not allowed to tokenize now answers **`403`** with `detail: insufficient_capabilities@login:tokenized_access`, on both launch endpoints, instead of the `400` that carried `status_reason: T10N_FORBIDDEN`. Branch on the part before the `@`, which never changes; what follows names the capability you are missing. A **sandbox** run is never refused for a capability. [Credential Tokenization](/guides/credential-tokenization) explains how to have it enabled for an application.

## Sessions now tell you what they found, not only what they read

The results of a **[Spain Public Administration](/flows/spain-public-administration/overview)** session carry a new field: **`messages`** — situations the session detected while it ran, beside the records themselves. It travels in [Get Session Results](/flows/spain-public-administration/api-reference/spain-public-administration-api/sessions-results/flows-es-public-administration-v-1-session-results) and in the payload of the `ended` and `partial` [webhooks](/flows/spain-public-administration/webhooks).

Nothing changes for an integration that ignores it. Most sessions detect nothing and the list is empty.

### The one to route is `flag`

There are four types, and three of them describe how the *reading* went — an `error`, a `warning`, an `info` note. The fourth describes what the reading **found**.

A **flag** never means something failed on our side. It means the session found something about the person or the data that deserves a decision on yours: a signal a clean, successful verification would not normally carry. Treat it as an input to the rules that already decide when a case needs a human — a verification can be technically perfect and still be worth a second look.

> **Note**
>
> **Automate on `message_id`, never on the wording.** `message_id` is the stable name of the *situation* — `profile_identity_mismatch`, `crossed_identity` — and a situation is reported **once** however many times it occurred, so `messages` is a set of facts about the verification rather than a trace of it. The text in `message` is written for a person and may be rewritten without the situation becoming a different one.

### It points at the data it is about

`location` is a `loc` list — the same shape as the `loc` of a validation error: `["data", "customer", "profile"]`, with strings for fields and **integers for array positions**. An empty list means the message is about the session as a whole.

That is why it is a list and not a path written out: a results document contains arrays, and `data.driver.vehicles.0.license_plate` cannot be resolved without guessing whether `0` is a key or an index. With a `loc` you can put the message on the exact field in your own interface, with no parsing.

### Where to read about it

* [**What the session tells you, beside the data**](/flows/spain-public-administration/overview#what-the-session-tells-you-beside-the-data) — the types, the `loc`, and a worked example: what happens when two administrations describe different people, and why that particular flag is a guarantee on this flow rather than something you should expect to see.
* [**Get Session Results**](/flows/spain-public-administration/api-reference/spain-public-administration-api/sessions-results/flows-es-public-administration-v-1-session-results) — every field, and what to do with each type.

## Direct Executions — the API without the widget, documented

The second way to use INFONITE now has a section of its own: **[Direct Executions](/direct-executions/overview)** — the same engines, called straight from your backend, for the cases where nobody is in front of a screen.

It is not a new API. It is the one that has been running client integrations for a long time, written down properly for the first time: what to send, what comes back, what each state means, and the decisions that are easy to get wrong.

### The guides

* [**What is a direct execution**](/direct-executions/overview) — when this is the right integration, when a [flow](/guides/what-is-a-flow) is, and what becomes your responsibility when there is no widget in the middle.
* [**Your first execution**](/direct-executions/quickstart) — six calls, as real commands, against a sandbox engine: find the engine, ask what it needs, run it, follow it, read the results, delete them.
* [**Authentication & keys**](/direct-executions/authentication) — the `X-APP-SECRET` header, sandbox versus production, and how to encrypt the credentials you send with your application's public key so that not even an intercepted request body reveals them.
* [**The execution lifecycle**](/direct-executions/lifecycle) — every state, the three clocks, the limits that end a run on their own, and why `PARTIAL` is a finished execution rather than a failed one.
* [**Challenges & MFA**](/direct-executions/challenges) — what to do when the institution asks for a one-time code: reading the form it publishes, answering it, and the deadline you have to beat.
* [**Stored credentials**](/direct-executions/tokenization) — turning one execution into a token so that next month's run needs no password on your side, what a token is scoped to, and what each of its states means.
* [**Webhooks**](/direct-executions/webhooks) — the four execution events, the delivery envelope, and the authentication header your endpoint can require.
* [**Reading the results**](/direct-executions/results) — global positions versus per-product endpoints, the difference between "nothing to report" and "you never asked for it", and the original documents behind the data.

### The reference

The **[Direct Executions API](/direct-executions/api-reference/direct-executions-api/engines/direct-executions-v-1-engines-list)** is in the API Reference tab, beside the flow API, with a request explorer on every operation: the engine catalogue, the execution lifecycle, tokenization, every results endpoint, attachments, and the four webhooks.

> **Note**
>
> **Execution webhooks carry the state, never the data.** An execution event tells you *that* something happened; the records are read back over an authenticated call. That is deliberate — it keeps somebody's financial data off a public endpoint — and it is different from a flow session, which can deliver its results encrypted with a key you supplied.

### Credential tokenization, explained once

**[Credential Tokenization](/guides/credential-tokenization)** is a guide of its own now, in the Security section, because it is not a Direct Executions feature — it is a platform one, and it is coming to the widget flows too, Bank Reader first.

It documents what tokenization actually gives you: the credentials are stored encrypted under a key **derived** from the token key you hold together with a secret that never leaves our runtime, so neither side can open them alone. We keep the ciphertext and a non-reversible verifier of your key, never the key itself.

> **Warning**
>
> **If you lose your token key, the stored credentials can never be opened again — by anyone, including us.** That is the design working, not a failure of it. Store your half as you store any secret you cannot recreate, and mint a new token from a fresh run when you have to.

### Banking data models

The [data models](/guides/data-models/overview) section gains the **[Banking](/guides/data-models/banking/overview)** family — the models any financial engine returns, field by field: [accounts](/guides/data-models/banking/accounts) with their categorised transactions, [cards](/guides/data-models/banking/cards), [loans and mortgages](/guides/data-models/banking/credit), [deposits and savings](/guides/data-models/banking/savings), [investments](/guides/data-models/banking/investments) and [direct debits](/guides/data-models/banking/direct-debits).

Until now that section documented only what comes back from a public administration. Both family maps are on the overview page now, side by side.

### Also on the site

* The **API Reference** now opens by naming the two APIs and what each one is for, with the base URLs of both.
* The [encryption guide](/guides/payload-encryption) finally points somewhere for the RSA envelope used to send values *to* us: the walkthrough now lives with the credentials it protects.
* `clients.infonite.io` is announced as the address the Direct Executions API is moving to; `clients.infonite.tech` keeps serving until it arrives.

## A guide to webhooks, and a documentation you can navigate

Two things: webhooks now have a page of their own, and the site has been reorganised around what you are actually trying to do.

### Webhooks, explained end to end

The [**Webhooks**](/flows/spain-public-administration/webhooks) page covers what the four events mean and when each one fires, the delivery envelope field by field, the authentication header your endpoint can require, the rules a destination URL has to satisfy, and the template variables and `hooks_extra_data` you can use to carry your own context into the call.

> **Warning**
>
> **We never send personal data over a webhook unless you gave us a key to encrypt it with.** Without an `aes_key`, the event carries no `data` at all: it tells you *that* something happened, and you fetch the records over the authenticated API. This was always the behaviour — it is now written down, because designing around the opposite assumption fails silently.

While the self-service screens are being built, webhook destinations are configured by our team: send [support](mailto:support@infonite.tech) the URL for each event you want, and the header you would like us to send. The per-event `hooks` endpoints in the API reference are **deprecated** and no longer decide any delivery.

### A clearer shape

The navigation now separates **learning** from **looking things up**:

* [**Guides**](/guides/welcome) — the platform itself: getting started, payload encryption, and the data models reference.
* [**Flows**](/guides/what-is-a-flow) — one section per product, with a new page explaining [what a flow is](/guides/what-is-a-flow) and how it differs from calling the API directly.
* [**API Reference**](/guides/using-the-api) — endpoints and schemas only, nothing else mixed in. **Every API URL is unchanged.**
* **Changelog** — this page, now one click from anywhere.

The API Reference now opens with [**Using the API**](/guides/using-the-api), which gathers what holds true for every endpoint and had never been written down anywhere: the `X-APP-SECRET` header and where it must never go, the base URLs, the `{"detail": "<code>"}` error shape and why you should branch on the code rather than the message, and the headers every response carries — `x-request-id` (quote it to support and we find your exact call), `x-process-time`, and the `x-ratelimit-*` trio you should read your budget from instead of hardcoding limits.

Guide pages moved to `/guides/…` and `/flows/…`; every previous link redirects, so nothing you have bookmarked or linked to is broken.

### Payload encryption, scoped honestly

The [encryption guide](/guides/payload-encryption) said "Payload Encryption & Decryption" while documenting a single scheme. It now opens by naming the scheme it details — AES-256-GCM, for everything we send you — and closes with the RSA envelope used for values sent *to* us, whose full walkthrough ships with the Direct Executions reference.

## Income floor, lifetime employment history, and the new Data models reference

Two families of news: the Spanish labor check got substantially deeper, and the documentation gained a whole section dedicated to the data itself.

### Spain Public Administration (v1)

* **Guaranteed income floor**: every labor check now carries an automatically computed income insight — a conservative **minimum net income** — deductions estimated conservatively, so it stays a floor — derived from the person's certified contribution bases, with each current employer's share broken out. It ships as part of the labor check model ([`income_floor`](/guides/data-models/labor-check#TGSSSpainLaborCheckSchema.income_floor) — [how to read it](/guides/data-models/labor-check#income-floor)). Nothing to configure: it is computed automatically whenever you request the `labor_check` feature.

> **Warning**
>
> The floor is a **guaranteed minimum**, never a salary estimate: real income can only be equal or higher, and for self-employed workers it deliberately understates. Use it as the lower bound in your risk models.

* **Lifetime contribution history**: the connection now reads the official TGSS certificates directly and returns the **full per-employer contribution history** — previously limited to the last \~5 years ([contribution bases](/guides/data-models/labor-check#contribution-bases)). The certificates travel as [attachments](/guides/data-models/attachments) carrying their official verification codes, re-checkable against the Seguridad Social at any time.
* **Current work statuses**: the labor check now answers *"what is this person's situation today"* at a glance — one entry per ongoing relation (employee, self-employed, public employee, unemployment benefit…); simultaneous employments show as repeats, and benefit income never inflates the income floor.
* **Sandbox parity**: the sandbox connection returns the same new shapes, so you can integrate and test end to end before going near production.

### New in the docs: Data models

The API reference shows you the endpoints; the new [**Data models**](/guides/data-models/overview) section shows you the **data** — every object the platform returns, laid out flat and explained field by field: where it arrives in your results, how the pieces join together, and the caveats that matter when you consume it. Start with the [customer profile](/guides/data-models/customer-profile), the [labor check](/guides/data-models/labor-check) and [public pensions](/guides/data-models/public-pensions), and continue through [driver](/guides/data-models/driver) & [vehicles](/guides/data-models/vehicles), [academic records](/guides/data-models/academic), [taxes](/guides/data-models/taxes), [properties](/guides/data-models/properties), [credit registry](/guides/data-models/credit-registry) and [attachments](/guides/data-models/attachments).

## Partial results when a source answers late

Some administrations do not answer in real time. The *CIRBE* credit risk report from the Banco de España is the usual case: it can take minutes to be produced, and until now your customer sat in front of a spinner waiting for it.

### Spain Public Administration (v1)

* **New callback event `es-public-administration:partial`**: the widget now lets the customer go as soon as they are done, and this event delivers **everything gathered up to that moment** — the same `FlowResultsSchema` you already parse, with the pending sources simply absent from it. Use it to show your customer something immediately, or to start the work that does not depend on the slow source.

> **Warning**
>
> **That payload is partial, and the session is still open.** `es-public-administration:ended` still fires afterwards, with the complete and final data. That is the event that closes the verification — do not act on the partial one as if it were the outcome.

* **Delivered at most once per session**, even while the flow moves in and out of the waiting state as the remaining sources finish. As with every webhook, keep your endpoint idempotent.
* **Subscribing is optional**: if you configure no hook for this event, nothing changes for you. You keep receiving `ended` exactly as before.

## Launch of the New Developer Portal

Welcome to the official launch of the new **INFONITE Developer Portal and Documentation**. This release consolidates our existing services, API references, and security integrations into a single unified developer platform:

### Spain Public Administration (v1)

* **Integration Reference**: Ported the OpenAPI references and callback events (`started`, `consent`, `ended`) to the portal for real-time verification sessions with official registries (AEAT, TGSS, MEC, DGT, CIRBE).

### Bank Reader Flow (In Development)

* **Initial Overview**: Added an initial page to describe the Bank Reader integration flow. This documentation section is currently under active development to define bank statement parsing and financial aggregation steps.

### Portal Security & Tooling

* **AES-256-GCM Payload Encryption**: Centralized documentation for secure webhook transport layers utilizing unique session keys.
* **Interactive Decryption Playground**: Test and validate encryption configurations directly in the browser.