> 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.

# On Authentication Ended

POST 

Fired when the login attempt against the source is resolved, one way or the other.

**You do not have to subscribe to this one**, and it is worth saying first: everything it tells you is in the execution state as well, under `authentication_status`, and it arrives again with `ended`. What this event buys you is **time** — the login is resolved seconds into a run that may take minutes.

Nobody typed those credentials today, so `AUTH_OK` is the proof that the stored access still works. It is also the moment a `ticket` becomes exchangeable: the credentials behind it are only stored **when the login succeeds**.

A rejected password is known at once. If your product says *"your bank did not accept these credentials"*, this is when it can say it — instead of after a run that was never going to produce anything.

It also separates *we could not get in* from *we got in and the extraction failed* — very different things for your integration, and for what you say to your customer. The first is usually about the credentials; the second about the source.

**`AUTH_OK` is the one that continues.** The credentials were accepted and the extraction begins; the execution carries on and you do nothing. Every other reason **ends the execution**: an `ended` event follows immediately with the same reason.

| `status_reason`                        | What happened, and what resolves it                                                                          |
| :------------------------------------- | :----------------------------------------------------------------------------------------------------------- |
| `INCORRECT_CREDENTIALS`                | The source rejected them. Ask your customer for their access again — the same values will fail the same way. |
| `INCORRECT_MFA`                        | The challenge was answered wrongly. A new execution, and a new code.                                         |
| `BLOCKED_USER` · `FRIEZED_CREDENTIALS` | The institution has locked or frozen the access. Only your customer can resolve it, with their institution.  |
| `CHANGE_PASSWORD`                      | The institution requires a password change before it will let anyone in.                                     |
| `MANUAL_INTERVENTION`                  | The source wants your customer to do something in its own channel first.                                     |
| `INCOMPATIBLE_ACCESS`                  | This access is not usable through the channel this engine speaks to.                                         |

**Do not retry a rejected login.** Institutions count failed attempts, and enough of them locks the account for your customer — not just for you. A failure here is a conversation with them, not a loop.

A **tokenized** execution that fails at this step also locks the token: read [Token Status](api:GET/executions/t10n/\{token_id}) before you use it again, and mint a new one rather than insisting.

Reference: https://infonite.dev/api-reference/direct-executions/direct-executions-api/webhooks/webhook-direct-executions-auth-ended

## Request

### Payload

- `app_id` (string, required) — The application this execution was launched with — the one your secret belongs to. Worth keeping when your product uses more than one, a sandbox and a production app being the usual case: every record and every event we send carries it.
- `customer_id` (string, required) — The `customer_id` you supplied when the execution was initialised, returned as you sent it — so an answer can be routed to the right case with no lookup on your side.
- `execution_id` (string, required) — The execution this belongs to — the value you poll for the state and address every results endpoint with. Always present here: an event exists because an execution does.
- `event` ("auth_ended", required) — The event type: `auth_ended`.
- `date` (string, required) — When the event was raised, in UTC. Deliveries can arrive out of order — a retry is delivered after whatever came next — so order your own records by this, not by arrival.
- `customer_available` (boolean, required) — Whether the execution was started as one a person can answer (`customer_interaction_available`). When `false`, a challenge from the source cannot be solved and the execution ends instead of waiting.
- `status_reason` (enum or enum or enum or enum or enum or enum or enum or enum or enum or enum or enum, required) — The precise reason for the state at the moment of the event — one of the execution reasons, or a feature's own when `producer` names a feature. Branch on this and not on the message: it is a stable code. [Every reason by family](/direct-executions/lifecycle#every-reason-by-family).
- `session_id` (string, optional, nullable)
- `external_execution_id` (string, optional, nullable)
- `locking_hash` (string, optional, nullable)
- `event_class` ("ExecutionEvent", optional, default: ExecutionEvent) — Payload class discriminator — always this value for an execution event. If the same endpoint also receives flow events, branch on it first.
- `producer` ("engine" or enum, optional, default: engine) — Who raised it: `engine` for the execution itself — the login, typically — or the feature's own code when a single feature is what needs something. An `action_required` from the accounts reader says `accounts_read`, so you know what is being asked for before reading the form.
- `status_message` (string, optional, nullable)
- `data` (map from string to any, optional, nullable)