The execution lifecycle

The three fields that describe where an execution is, and every value each of them can take
View as Markdown

An execution is asynchronous from the first millisecond: the call that starts it answers 202 and hands you an execution_id, and the work happens behind that. Everything on this page answers the question that follows — where is it now, and what do I do about it?


Three fields, three different questions

This is the part worth reading slowly, because the three are easy to confuse and they do not mean the same thing.

FieldAnswersValues
status_codeWhat kind of situation is this?A closed set of 10 families. This is what you branch on.
status_reasonWhy, exactly?One of many precise codes. Each belongs to exactly one family. This is what you log, show to support, and use for the fine-grained cases.
authentication_statusDid we get into the source at all?A separate axis, reported independently of the two above.

Plus one convenience field that sits above all of them:

is_closed is the only signal that means finished. true — the run is over and nothing about it will change. false — it is alive, whatever the other fields say. It is in every state response, and it is what Execution Status turns into a 200.

the four together, in a state response
{
"is_closed": true,
"status_code": "PARTIAL",
"status_reason": "PARTIAL",
"authentication_status": "AUTH_OK"
}

A reason always implies its code, never the other way round. INCORRECT_CREDENTIALS is always AUTH_ERROR; AUTH_ERROR might be any of nine reasons. Branch on the code, and reach for the reason when the code is not specific enough to decide — which, for the failures, it usually is not.


The ten families

ACCEPTED ─▶ WAITING ─▶ RUNNING ─┬─▶ COMPLETED · PARTIAL · FAILED
├─▶ ACTION_REQUIRED ─▶ (you answer) ─▶ RUNNING
│ └─▶ ABORTED (nobody answered in time)
└─▶ AUTH_ERROR · UNHANDLED_AUTH_ERROR
CONFIGURATION_ERROR · TEMPORARY_ERROR · ABORTED
status_codeClosed?MeaningWhat it asks of you
ONGOINGnoWorking.Nothing. Wait.
ACTION_REQUIREDnoWaiting for an answer from your customer.Answer it, within the deadline.
COMPLETEDyesEvery requested feature answered.Read the results.
PARTIALyesSome features answered, others did not.Read the results, and decide whether what arrived is enough.
FAILEDyesNothing could be retrieved.Look at the reason before retrying.
ABORTEDyesCancelled — by you, by a timeout, or because a person was needed and none was available.Depends on who cancelled; see below.
AUTH_ERRORyesThe login was rejected, in a way the source explained.Talk to your customer. Do not retry the same values.
UNHANDLED_AUTH_ERRORyesThe login failed in a way we could not classify.Retry later; if it persists, contact support with the execution_id.
CONFIGURATION_ERRORyesThe request itself was not valid.Fix your integration. Retrying identically will fail identically.
TEMPORARY_ERRORyesSomething on the way was unavailable.Retry later. Nothing is wrong with your request.

PARTIAL is a finished execution, not a failing one. It is what you get when a bank answers for accounts and times out for investments. What arrived is real and final; what did not will not appear later. Read features to see which is which, and treat the gap as a business decision — is this enough to act on? — rather than as an error to retry blindly.


Every reason, by family

Each heading below is a status_code — one of the ten families in the table above — and the rows under it are the status_reason values that belong to it. That is the relationship in one sentence: the family is the situation, the reason is the granular cause.

So a state reading status_code: AUTH_ERROR will always carry one of the reasons in the AUTH_ERROR section, and never a reason from another one. If your integration only handles the ten families it will work; it will just be less specific than it could be, and the failures are exactly where that specificity is worth having.

status_code: ONGOING — it is working

status_reasonWhat is happening
ACCEPTEDQueued. Nothing has started yet.
WAITINGPicked up; the engine is warming up.
RUNNINGLogged in and extracting.
ASYNC_WAITWaiting on the source to produce something on its own schedule. Slow by design, not stuck — the credit registry is the usual case.

status_code: ACTION_REQUIRED — it is waiting for you

status_reasonWhat is happening
MFA_REQUIREDA strong-authentication challenge: a code, a push, a confirmation.
INPUT_REQUIREDAny other field the engine turned out to need — typically one of its lazy_fields, which you can send up front when you know the rule, and then it never asks.

Both publish a form_schema describing exactly what to collect. See Challenges & MFA.

status_code: AUTH_ERROR — we could not get in

The most actionable family, because almost every value here means a person has to do something, and none of them is fixed by retrying.

status_reasonWhat the source saidWhat to do
INCORRECT_CREDENTIALSThe credentials were rejected.Ask your customer for them again. Do not retry: institutions count failed attempts and enough of them locks the account.
INCORRECT_MFAThe challenge was answered wrongly.Start again and collect the code carefully.
BLOCKED_USERThe institution has blocked the access.Only your customer can unblock it, with their institution.
FRIEZED_CREDENTIALSThe access is temporarily frozen.Wait, or have the customer resolve it with the institution.
CHANGE_PASSWORDThe institution requires a password change before anyone can log in.The customer changes it, then you run again with the new one.
MANUAL_INTERVENTIONThe source is asking the person to do something in its own channel first — accept a notice, complete a step.The customer does it; then run again.
INCOMPATIBLE_ACCESSThis access is not usable through the channel this engine speaks to.A different engine for the same institution may fit; check the catalogue.
DUPLICATED_SESSIONThe source refused because another session is already open for that user.Retry after a few minutes.

A tokenized execution that ends in this family also locks the token. The stored credentials are the ones that were rejected, so check Token Status and mint a new token from a fresh parametrized execution rather than retrying the locked one.

UNHANDLED_AUTH_ERROR is its own family, not a member of this one, and it has a single reason of the same name: the login failed in a way the engine could not classify. Treat it as transient, and if the same access keeps producing it, send us the execution_id.

status_code: CONFIGURATION_ERROR — the request was not valid

status_reasonWhat went wrong
BAD_CONFIGURATIONSA feature configuration the engine does not accept — often a date range outside its limits.
INCORRECT_PARAMETERS_FORMATThe parameters did not match what the engine’s form declares.
INCORRECT_RESUME_FORMATThe body you sent to resume did not match the form_schema that was published.
ENCRYPTION_ERRORAn encrypted value could not be opened — wrong key, wrong scheme for its size, mangled Base64.
T10N_FORBIDDENYour application is not allowed to tokenize, and you asked for a ticket.
T10N_REJECTEDThe token is revoked or broken.
T10N_NOT_AVAILABLEThis engine does not support tokenization.
T10N_EXCEPTIONThe stored credentials could not be read. Mint a new token.
BAD_PROXY_CONFIGURATIONThe routing this application uses for this engine is not usable. Contact support — this one is ours, not yours.

The state carries configurations_errors and parameters_errors naming the offending fields, which is where to look before changing anything.

status_code: ABORTED — it was cancelled

status_reasonWho cancelled, and why
CLIENT_CANCELLEDYou did, with Abort. Not a failure.
USER_CANCELLEDYour customer did, from an interactive surface. Not a failure.
ACTION_TIMEOUTA challenge was published and nobody answered in time. Not a failure — a missed window.
TIMEOUTThe execution exceeded its execution_timeout.
CUSTOMER_INTERVENTION_REQUIREDThe source asked for something and the execution was started declaring that nobody could answer.
SYSTEM_CANCELLEDThe platform stopped it.

status_code: TEMPORARY_ERROR — try again later

status_reasonWhat it means
OUT_OF_SERVICEThe source itself is unavailable — maintenance, an outage, a nightly window.
ENGINE_UNAVAILABLEThe engine is not serving right now.
ALREADY_EXECUTINGAnother execution is already running for that access.
ENGINE_BANNED · AUTO_CAPTCHA_ERROR · PROXY_ERROR · NETWORK_ERROR · INTERNAL_ERRORThe run could not be set up. These are ours, and they are transient.

Nothing in this family means your request was wrong. A sensible retry — minutes for the setup ones, longer for OUT_OF_SERVICE — is the right response, with a cap so a source that is down all day does not become an infinite loop.

status_code: COMPLETED · PARTIAL · FAILED

One reason each, carrying the same name as its family — COMPLETED, PARTIAL, FAILED. When the run ends well there is nothing more to say at this level; the detail lives one level down, in the features.


The fourth axis: authentication_status

Reported separately from everything above, and it answers a question the execution status cannot: did we get into the source?

ValueMeaning
not-performedThe engine has not tried yet.
AUTH_OKThe credentials were accepted. The extraction is under way — the execution status stays ONGOING.
anything elseThe login was rejected, with one of the AUTH_ERROR reasons above. The execution ends with that same reason.

The distinction is the one that decides what you do next:

  • We could not get in → a conversation with your customer. Their credentials, their bank, their action.
  • We got in and the extraction fell short (PARTIAL, FAILED, TEMPORARY_ERROR after AUTH_OK) → nothing to ask anyone. Retry later, or take what arrived.

The auth_ended webhook delivers this the moment it is known, which is usually well before the execution ends — that is what lets you start the “ask for the credentials again” conversation early.


One level down: the features

features carries one entry per feature you requested, each with its own status_reason from a parallel vocabulary. This is where a PARTIAL explains itself.

Feature status_reasonMeaning
FEATURE_ACCEPTED · FEATURE_WAITING · FEATURE_RUNNING · FEATURE_ASYNC_WAITNot finished yet.
FEATURE_ACTION_REQUIREDThis feature is the one asking for something.
FEATURE_COMPLETEDRetrieved.
FEATURE_PARTIALRetrieved incompletely — some of it is there.
FEATURE_FAILED · FEATURE_INTERNAL_ERROR · FEATURE_TEMPORARY_ERRORNot retrieved. The first is definitive for this run; the others are worth another run.
FEATURE_ABORTED · FEATURE_TIMEOUT · FEATURE_ACTION_TIMEOUTStopped when the execution was.
FEATURE_DISABLED · FEATURE_NOT_IMPLEMENTEDThis engine does not offer it. Asking for it is ignored — no data, no error, and nothing in the results to say so — which is why the catalogue is where you build the list from.
FEATURE_CONFIGURATION_ERROR · FEATURE_INCORRECT_PARAMETERS_FORMATIts configuration was rejected.
FEATURE_ACTION_REJECTEDThe answer to its challenge was refused.

A results endpoint for a feature that never finished answers 202; one for a feature you never requested answers 204. Both are described in Reading the results.


How to follow one

Webhooks — the design

Four events: started, action required, authentication ended, ended. You do nothing until there is something to do.

Polling — the fallback

HEAD on the execution answers 202, 423 or 200 with no body. Cheap enough for a loop; ask every few seconds, not every few milliseconds.

An engine talks to a real institution over a real network: seconds to minutes is normal, and a source that produces its report on its own schedule can take considerably longer. Size your own timeouts on the slowest feature you requested, not on the average.


The clocks

Three timings come back on the state, and they answer three different questions:

FieldMeasuresUse it to
execution_timeActive processing only.Judge the engine.
running_timeSince work began, including time parked waiting for a person.Judge the whole run.
total_elapsed_timeSince you asked, including the queue.Judge what your customer experienced.

And three limits end an execution on their own:

  • execution_timeout — active processing, 60 to 1200 seconds, chosen per execution (default 1200). Waiting for you does not count against it.
  • action_required_expires — the deadline to answer a challenge. Past it, ABORTED / ACTION_TIMEOUT.
  • The unattended window — an execution started with customer_interaction_available: false has up to three hours to find a moment when the source cooperates, then gives up.

Running the same engine twice

An application cannot have two live executions for the same customer and engine — nor two carrying the same external_execution_id for the same customer, nor two on the same token. The second is refused with 409, and the body names the one already running so you can follow it instead of guessing. It is a guard against a double-submitted form running two logins against a bank at the same time, which some institutions treat as an attack.

If the parallel run is deliberate, give each one a different external_execution_id: your own identifier makes them distinguishable and both are accepted. It travels through every event and every state, which also makes it the natural place for your case number.


Ending it yourself

Abort

Stops a live execution and closes it as CLIENT_CANCELLED — a cancellation, not a failure. Whatever was extracted stays readable, and the slot is freed immediately.

Delete

Purges a closed execution and everything under it — records and documents — permanently. This is the one to build into your flow.

Delete as soon as you have stored what you need. Everything an execution retrieved is somebody’s financial life; the strongest protection available is not to be holding it. Executions nobody deletes are purged after the retention period, but that is a safety net, not a data-minimisation policy.