Fired when the source asks for something only your customer can provide.
A one-time code sent to their phone, a push notification to confirm, a security question, an extra field the engine could not know in advance. The execution is paused, not broken, and it is waiting for you.
This is the one event you cannot replace with patience. The others tell you about a run that is progressing on its own; this one is a run that will expire unless you answer, and the window is the institution’s, not ours. The alternative is polling the state every few seconds for every execution in flight.
Execution State answers 423 and carries form_schema — the exact fields to collect, with x-meta.timeout saying how long you have — and action_required_expires, the deadline as a date.
Ask for exactly what the form declares, nothing more. The values travel like any other secret: you may send them encrypted.
Resume an Execution hands the answer over and the engine carries on from where it stopped.
A strong-authentication challenge: a code, a push confirmation, a signature.
Anything else the engine needs and could not know in advance — a security question, a contract to choose.
producer says who is asking: engine while the login is being resolved, or the feature’s own code — accounts_read, say — when one feature raised the challenge on its own.
Move fast. A code issued by a bank expires on the institution’s timetable, usually a couple of minutes. Past the deadline the execution is aborted with ACTION_TIMEOUT and has to be started again.
This event only happens when you asked for it to be possible. An execution started with customer_interaction_available: false never pauses: if the source raises a challenge, the execution ends instead.
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.
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.
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.
The event type: action_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.
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.
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.
Payload class discriminator — always this value for an execution event. If the same endpoint also receives flow events, branch on it first.
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.