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

# Answer and resume

PUT https://clients.infonite.tech/api/executions/handler/v1/{execution_id}
Content-Type: application/json

Send the values a paused execution asked for, and let it carry on.

Some logins cannot be completed in one step: the source sends a code to your customer's phone, asks them to confirm a push notification, or requests a field nobody could know in advance. The execution parks in `ACTION_REQUIRED`, publishes the exact form it needs, and waits for you.

[Read the state](api:GET/executions/handler/v1/\{execution_id}) answers `423` with `form_schema` — an OpenAPI 3.0.3 Schema Object describing the fields to collect, their types and their labels — and `action_required_expires`, your deadline as an instant.

Ask your customer for exactly what the form declares, nothing more. `producer` says who is asking: the login, or one feature that needs something of its own.

A flat JSON object, keyed by the form's property names. Values may travel encrypted like any other secret — individually as `rsa::…` or `hybrid::…`, or the whole body as one encrypted string.

**Answer within the window.** `action_required_expires` is a hard deadline: past it the execution is aborted with `ACTION_TIMEOUT` and the answer is refused with `410`. A code issued by a bank expires on the institution's timetable — usually a couple of minutes — so collect and forward without a detour.

**A wrong value is not an HTTP error.** The source is what judges it, not us: a mistyped code still answers `202`. The execution resumes, the source refuses it, and the state comes back either asking again — with `payload_errors` naming what was wrong — or ending with an authentication reason.

## What the answers mean

| Status | Meaning                                                                                           |
| :----- | :------------------------------------------------------------------------------------------------ |
| `202`  | Accepted and queued again, back to `ONGOING`.                                                     |
| `400`  | Nothing is waiting: `not_waiting_for_action`, or `execution_already_closed` when the run is over. |
| `410`  | The window closed. The execution was aborted with `ACTION_TIMEOUT`; start a new one.              |
| `503`  | The engine became unavailable while the execution was parked, so the answer cannot be delivered.  |

**Server to server only.** This call is authorised with your application secret: it belongs in your backend, never in a browser, a mobile app or anything your customer can read.

Reference: https://infonite.dev/api-reference/direct-executions/direct-executions-api/handling-the-state/direct-executions-v-1-handler-resume

## Authentication

- `X-APP-SECRET` header (required) — Application Secret

## Servers

- `https://clients.infonite.tech/api` (Legacy Server, default)
- `https://clients.infonite.io/api` (Production Server)

## Request

### Path parameters

- `execution_id` (string, required) — The execution, as the acceptance response returned it.

### Body (application/json)

This endpoint expects a map from string to any.

- `map from string to any`

## Response

### 202

**202 Accepted**Accepted: the answer is on its way to the engine and the execution is queued again, back to `ONGOING`. The body is the same acceptance shape the run started with — nothing about it changed except that it is moving. **A wrong value is not an error here.** The source is the one that judges it, so a mistyped code still answers `202`: the execution resumes, the source refuses it, and the state comes back either asking again or ending with an authentication reason.

- `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.
- `auth_origin` (enum, required) — How the call that created the execution was authorised: an application secret for a server-to-server call, or a user session when it was launched from a console. An audit field — it says who started the run, not how it went.
  - Allowed values: `app-secret`, `user-token`, `session-token`
- `engine_reference` (string, required) — The engine this execution runs, exactly as the catalogue publishes it. It is echoed on every event and every record, so a stored result says which source it came from with no lookup on your side.
- `status_reason` (enum or enum or enum or enum or enum or enum or enum or enum or enum or enum, required) — The precise cause of the state. Every reason belongs to exactly one `status_code` family and its wording never changes, so it is safe to branch on — read `status_code` when the family is all you need, and see [the lifecycle](/direct-executions/lifecycle#every-reason-by-family) for what each one asks of you. * Reasons for `ONGOING`: * `ACCEPTED`: queued, nothing has started yet. * `WAITING`: picked up, the engine is warming up. * `RUNNING`: logged in and extracting. * `ASYNC_WAIT`: waiting on the source to produce something on its own schedule. * Reasons for `ACTION_REQUIRED`: * `MFA_REQUIRED`: the source asked for a strong-authentication factor. * `INPUT_REQUIRED`: the engine needs another field it could not know in advance. * Reasons for `COMPLETED`: * `COMPLETED`: every requested feature answered. * Reasons for `PARTIAL`: * `PARTIAL`: finished, with some features answered and others not. * Reasons for `FAILED`: * `FAILED`: finished, and nothing could be retrieved. * Reasons for `ABORTED`: * `CLIENT_CANCELLED`: you aborted it. * `USER_CANCELLED`: your customer abandoned it. * `ACTION_TIMEOUT`: nobody answered the challenge in time. * `TIMEOUT`: the run exceeded its `execution_timeout`. * `CUSTOMER_INTERVENTION_REQUIRED`: a person was needed and none was available. * `SYSTEM_CANCELLED`: the platform stopped it. * Reasons for `AUTH_ERROR` — the source refused the login, and retrying the same values will not help: * `INCORRECT_CREDENTIALS`: rejected. Ask your customer for them again. * `INCORRECT_MFA`: the challenge was answered wrongly. * `BLOCKED_USER`: the institution has blocked the access. * `FRIEZED_CREDENTIALS`: the access is temporarily frozen. * `CHANGE_PASSWORD`: the institution requires a password change first. * `MANUAL_INTERVENTION`: the person must do something in the source's own channel. * `INCOMPATIBLE_ACCESS`: this access does not work through this engine's channel. * `DUPLICATED_SESSION`: another session is already open for that user. * Reasons for `UNHANDLED_AUTH_ERROR`: * `UNHANDLED_AUTH_ERROR`: the login failed in a way we could not classify. * Reasons for `CONFIGURATION_ERROR` — the request itself, so retrying it unchanged fails the same way: * `BAD_CONFIGURATIONS`: a feature configuration the engine does not accept. * `INCORRECT_PARAMETERS_FORMAT`: the parameters did not match the engine's form. * `INCORRECT_RESUME_FORMAT`: the resume body did not match the published form. * `ENCRYPTION_ERROR`: an encrypted value could not be opened. * `T10N_FORBIDDEN`: your application may not tokenize. * `T10N_NOT_AVAILABLE`: this engine does not support tokenization. * `T10N_REJECTED`: the token is revoked or broken. * `T10N_EXCEPTION`: the stored credentials could not be read. * `BAD_PROXY_CONFIGURATION`: ours, not yours — contact support. * Reasons for `TEMPORARY_ERROR` — nothing is wrong with your request, retry later: * `OUT_OF_SERVICE`: the source itself is unavailable. * `ENGINE_UNAVAILABLE`: the engine is not serving right now. * `ALREADY_EXECUTING`: another execution is already running for that access. * `ENGINE_BANNED`, `AUTO_CAPTCHA_ERROR`, `PROXY_ERROR`, `NETWORK_ERROR`, `INTERNAL_ERROR`: the run could not be set up. Ours, and transient. `AUTH_OK` belongs to this vocabulary too, but it only ever appears in `authentication_status`: a login that succeeds leaves the execution `ONGOING`.
- `status_code` (enum, required) — The family a state belongs to, and the value to branch on: it is always present, and every `status_reason` belongs to exactly one of these. The precise cause lives in the reason — read it when the family is not specific enough to decide. Allowed values are: - `ONGOING`: The execution is ongoing - `ACTION_REQUIRED`: The execution is waiting for an input - `COMPLETED`: The execution has been completed - `ABORTED`: The execution has been aborted - `CONFIGURATION_ERROR`: The execution has been rejected due to a configuration error - `PARTIAL`: The execution has been completed with errors - `TEMPORARY_ERROR`: The execution cannot be processed due to a temporary error - `AUTH_ERROR`: The execution failed due to an authentication error - `UNHANDLED_AUTH_ERROR`: The execution failed during the login because of an unhandled error - `FAILED`: The execution has failed
  - Allowed values: `ONGOING`, `ACTION_REQUIRED`, `COMPLETED`, `ABORTED`, `CONFIGURATION_ERROR`, `PARTIAL`, `TEMPORARY_ERROR`, `AUTH_ERROR`, `UNHANDLED_AUTH_ERROR`, `FAILED`
- `execution_id` (string, optional) — The handle to this execution, and the one value worth storing from this response: you poll it for the state, you match it against the webhooks we deliver, and every results endpoint is addressed by it. **Present only when the execution was created.** A request refused before that — a collision, an invalid configuration — answers without it.
- `session_id` (string, optional) — The session this execution belongs to. An execution launched on its own is its own session, so today the two values usually match — **treat them as two independent identifiers anyway**: an execution can be one step of a wider journey, and a run you are pointed at is not always the one you asked for. Address results and state by `execution_id`. Like it, this is only present when an execution was created.
- `external_execution_id` (string, optional) — The reference you attached when the execution was started, if you sent one — echoed so your own identifier travels beside ours, on this response and on every event.
- `status_message` (string, optional) — A human-readable note, when there is one to add. It is diagnostic and never a contract: do not parse it and do not show it to your end user as it comes — branch on `status_reason` and write your own copy.

## Errors

### 400 Bad Request Error

**400 Bad Request**This execution is not waiting for anything. `detail` says which: `execution_already_closed` — it is over, and an answer cannot reopen it — or `not_waiting_for_action`, which is the answer to a second `PUT` for a challenge that was already resolved.

- `detail` (string, required) — Error message

### 404 Not Found Error

**404 Not Found**No execution with that id for your application, or it has been deleted. A deleted execution answers exactly like one that never existed.

- `detail` (string, required) — Error message

### 410 Gone Error

**410 Gone****The window closed.** `action_required_expires` had passed, so the execution was aborted with `ACTION_TIMEOUT` and this answer arrives too late — a bank's code expires on the institution's timetable, not ours. Start a new execution; there is nothing to resume.

- `detail` (string, required) — Error message

### 422 Unprocessable Entity Error

Validation Error

- `detail` (list of object, optional)
  - `loc` (list of string or integer, required)
  - `msg` (string, required)
  - `type` (string, required)
  - `input` (any, optional)
  - `ctx` (object, optional)

### 503 Service Unavailable Error

**503 Service Unavailable**The engine became unavailable while the execution was parked, so the answer cannot be delivered. The execution is aborted with the same reason `detail` carries — the cases are the ones [Initiate with parameters](api:POST/executions/init/v1/parametrized) lists.

- `detail` (string, required) — Error message

## Examples

**Request**

```json
{
  "code": "1234"
}
```

**Response**

```json
{
  "app_id": "4aa3dcbab3287e2385bb5cec",
  "customer_id": "my-customer-1",
  "auth_origin": "app-secret",
  "engine_reference": "DEMOBANKXXXXFIN100ES9999-mobile",
  "status_reason": "WAITING",
  "status_code": "ONGOING",
  "execution_id": "6aa3d8b418d1c5dc9a8e3d36",
  "session_id": "5aa3dca503e37e6809539a58",
  "external_execution_id": "case-A-1029"
}
```

**SDK Code**

```python The answer is on its way
import requests

url = "https://clients.infonite.tech/api/executions/handler/v1/6aa3d8b418d1c5dc9a8e3d36"

payload = { "code": "1234" }
headers = {
    "X-APP-SECRET": "<apiKey>",
    "Content-Type": "application/json"
}

response = requests.put(url, json=payload, headers=headers)

print(response.json())
```

```javascript The answer is on its way
const url = 'https://clients.infonite.tech/api/executions/handler/v1/6aa3d8b418d1c5dc9a8e3d36';
const options = {
  method: 'PUT',
  headers: {'X-APP-SECRET': '<apiKey>', 'Content-Type': 'application/json'},
  body: '{"code":"1234"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go The answer is on its way
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://clients.infonite.tech/api/executions/handler/v1/6aa3d8b418d1c5dc9a8e3d36"

	payload := strings.NewReader("{\n  \"code\": \"1234\"\n}")

	req, _ := http.NewRequest("PUT", url, payload)

	req.Header.Add("X-APP-SECRET", "<apiKey>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby The answer is on its way
require 'uri'
require 'net/http'

url = URI("https://clients.infonite.tech/api/executions/handler/v1/6aa3d8b418d1c5dc9a8e3d36")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Put.new(url)
request["X-APP-SECRET"] = '<apiKey>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"code\": \"1234\"\n}"

response = http.request(request)
puts response.read_body
```

```java The answer is on its way
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.put("https://clients.infonite.tech/api/executions/handler/v1/6aa3d8b418d1c5dc9a8e3d36")
  .header("X-APP-SECRET", "<apiKey>")
  .header("Content-Type", "application/json")
  .body("{\n  \"code\": \"1234\"\n}")
  .asString();
```

```php The answer is on its way
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('PUT', 'https://clients.infonite.tech/api/executions/handler/v1/6aa3d8b418d1c5dc9a8e3d36', [
  'body' => '{
  "code": "1234"
}',
  'headers' => [
    'Content-Type' => 'application/json',
    'X-APP-SECRET' => '<apiKey>',
  ],
]);

echo $response->getBody();
```

```csharp The answer is on its way
using RestSharp;

var client = new RestClient("https://clients.infonite.tech/api/executions/handler/v1/6aa3d8b418d1c5dc9a8e3d36");
var request = new RestRequest(Method.PUT);
request.AddHeader("X-APP-SECRET", "<apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"code\": \"1234\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift The answer is on its way
import Foundation

let headers = [
  "X-APP-SECRET": "<apiKey>",
  "Content-Type": "application/json"
]
let parameters = ["code": "1234"] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://clients.infonite.tech/api/executions/handler/v1/6aa3d8b418d1c5dc9a8e3d36")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "PUT"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```