> This page is for Direct Executions.

> 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 Execution Ended

POST 

Fired when the execution is over. Nothing about it will change afterwards.

This is the event that closes your case, and **the one to subscribe to if you subscribe to only one**: it is the only event that says the results are there, the only one delivered for an execution that never got to run, and the only one the platform re-delivers if your endpoint was down.

Nothing is pushed here — read it over the authenticated API. The [financial](https://infonite.dev/direct-executions/api-reference/direct-executions-api/fetching-the-results/financial-data/direct-executions-v-1-results-financial-position) or [public](https://infonite.dev/direct-executions/api-reference/direct-executions-api/fetching-the-results/public-administration/direct-executions-v-1-results-public-position) global position gives you everything at once; the per-product endpoints give you one thing at a time.

On your side, in your own model. The results stay readable while the execution exists, which is not forever.

[Delete an Execution](https://infonite.dev/direct-executions/api-reference/direct-executions-api/handling-the-state/direct-executions-v-1-handler-delete) purges its records and documents. The less of somebody's financial data sits anywhere, the better — including here.

`status_reason` says how it ended:

| Outcome                               | What it means                                                                                                                                             |
| :------------------------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `COMPLETED`                           | Every requested feature answered.                                                                                                                         |
| `PARTIAL`                             | **Also finished.** Some features answered and others did not — the state says which, feature by feature. Read what arrived; the rest will not come later. |
| `FAILED`                              | Nothing could be retrieved.                                                                                                                               |
| `ABORTED`                             | Cancelled — by you, by the platform, or by a timeout.                                                                                                     |
| `AUTH_ERROR` · `UNHANDLED_AUTH_ERROR` | The session with the source could never be opened. The preceding `auth_ended` event carries the detail.                                                   |
| `CONFIGURATION_ERROR`                 | The request itself was not valid: parameters or configurations. The state lists the offending fields.                                                     |
| `TEMPORARY_ERROR`                     | Something on the way was unavailable. The execution is over, but the cause is transient: the same request may well succeed later.                         |

**This is the only event the platform re-delivers on its own.** If your endpoint was unreachable when it fired, a background job tries again — so a deploy window does not cost you a case. The other three are delivered once.

**The payload carries no records**, and that is deliberate: an execution event is a notification, which is what keeps somebody's financial data off a public endpoint. Anything that arrives in `data` today is empty.

**Answer `2xx` as soon as the payload reaches you**, whatever your processing does with it afterwards: any other status is recorded as a failed delivery even though the event arrived. [Answering a delivery](/guides/webhooks#answering-a-delivery) has the handler to copy.

Reference: https://infonite.dev/direct-executions/api-reference/direct-executions-api/webhooks/webhook-direct-executions-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` ("ended", required) — The event type: `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` (WebhookEndedPayloadStatusReason, 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` (WebhookEndedPayloadProducer, 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)

## Types

### WebhookEndedPayloadStatusReason

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

- OngoingReason: enum
  - Allowed values: `ACCEPTED`, `WAITING`, `RUNNING`, `ASYNC_WAIT`
- ActionRequiredReason: enum
  - Allowed values: `MFA_REQUIRED`, `INPUT_REQUIRED`
- AbortedReason: enum
  - Allowed values: `USER_CANCELLED`, `CLIENT_CANCELLED`, `SYSTEM_CANCELLED`, `TIMEOUT`, `ACTION_TIMEOUT`, `CUSTOMER_INTERVENTION_REQUIRED`
- ConfigurationReason: enum
  - Allowed values: `BAD_CONFIGURATIONS`, `BAD_PROXY_CONFIGURATION`, `ENCRYPTION_ERROR`, `INCORRECT_PARAMETERS_FORMAT`, `INCORRECT_RESUME_FORMAT`, `T10N_REJECTED`, `T10N_NOT_AVAILABLE`, `T10N_EXCEPTION`
- CompletedReason: enum
  - Allowed values: `COMPLETED`
- PartialReason: enum
  - Allowed values: `PARTIAL`
- FailedReason: enum
  - Allowed values: `FAILED`
- AuthenticationReason: enum
  - Allowed values: `AUTH_OK`, `INCORRECT_CREDENTIALS`, `INCORRECT_MFA`, `DUPLICATED_SESSION`, `FRIEZED_CREDENTIALS`, `BLOCKED_USER`, `MANUAL_INTERVENTION`, `CHANGE_PASSWORD`, `INCOMPATIBLE_ACCESS`
- UnhandledAuthReason: enum
  - Allowed values: `UNHANDLED_AUTH_ERROR`
- TemporaryReason: enum
  - Allowed values: `ENGINE_UNAVAILABLE`, `ENGINE_BANNED`, `OUT_OF_SERVICE`, `ALREADY_EXECUTING`, `AUTO_CAPTCHA_ERROR`, `PROXY_ERROR`, `NETWORK_ERROR`, `INTERNAL_ERROR`
- FeatureReason: enum
  - Allowed values: `FEATURE_ACCEPTED`, `FEATURE_WAITING`, `FEATURE_RUNNING`, `FEATURE_ASYNC_WAIT`, `FEATURE_ACTION_REQUIRED`, `FEATURE_ACTION_REJECTED`, `FEATURE_INCORRECT_PARAMETERS_FORMAT`, `FEATURE_ABORTED`, `FEATURE_TIMEOUT`, `FEATURE_ACTION_TIMEOUT`, `FEATURE_CUSTOMER_INTERVENTION_REQUIRED`, `FEATURE_CONFIGURATION_ERROR`, `FEATURE_COMPLETED`, `FEATURE_PARTIAL`, `FEATURE_FAILED`, `FEATURE_DISABLED`, `FEATURE_NOT_IMPLEMENTED`, `FEATURE_TEMPORARY_ERROR`, `FEATURE_INTERNAL_ERROR`

### WebhookEndedPayloadProducer

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.

- "engine"
- FeatureType: enum
  - Allowed values: `accounts_read`, `cards_read`, `deposits_read`, `loans_read`, `credits_read`, `investment_accounts_read`, `funds_read`, `stocks_read`, `pensions_read`, `accounts_certificates`, `direct_debits_read`, `customer_information_read`, `source_contracts_read`, `cloud_resource_read`, `supplier_invoices_read`, `client_invoices_read`, `labor_check`, `public_pensions`, `public_document_verification`, `yearly_individual_tax`, `vehicles_data`, `driver_data`, `academic_data`, `properties_data`, `credit_registry_data`