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

# Issue a session token

PUT https://clients.infonite.tech/api/executions/handler/v1/{execution_id}/session-token

Give a running execution a new session token, and the widget link that carries it.

Every direct execution is born with one: its acceptance carries the `session_token` and, when you declared a person available, the `widget_url` built with it. Call this while it runs, when that link has to change hands — it leaked into a log, it was sent to the wrong person, your customer moved to another device — or when you want a link for an execution that has none: one whose token you [revoked](https://infonite.dev/direct-executions/api-reference/direct-executions-api/handling-the-state/direct-executions-v-1-handler-revoke-session-token), or one started without `customer_interaction_available`. **A closed execution gets no new token**: there is nothing left for your customer to do.

**The token the execution had opens nothing from this moment**, and neither does any link built with it. There is one token per execution: issuing is replacing.

| Status | Meaning                                                                                                                    |
| :----- | :------------------------------------------------------------------------------------------------------------------------- |
| `200`  | The new `session_token`, its `widget_url` and its `expiration_date`.                                                       |
| `400`  | `execution_already_closed`: it has ended. Its current token keeps showing how — until it expires or you revoke it.         |
| `404`  | No such execution for your application, or it has been deleted.                                                            |
| `409`  | It is not one of your direct executions: a flow launched it, and its person carries it on through that flow's own session. |

**It expires with the execution**, a day after the execution started — issuing a new token does not move that. The widget link carries no way back: append `completion_url` (and `completion_mode`) to it yourself, exactly as to the one the acceptance carried.

**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/direct-executions/api-reference/direct-executions-api/handling-the-state/direct-executions-v-1-handler-issue-session-token

## Authentication

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

## Servers

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

## Request

### Path parameters

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

## Response

### 200

**200 OK**The new token and its widget link. Whatever link you handed out before opens nothing any more.

- `session_token` (string, required) — A short-lived token that authorises **acting on this execution and nothing else**: it cannot read a single extracted record, and once the execution ends it only shows how it ended. It expires with the execution, and opens nothing once you delete the execution, [revoke it](https://infonite.dev/direct-executions/api-reference/direct-executions-api/handling-the-state/direct-executions-v-1-handler-revoke-session-token) or [issue another](https://infonite.dev/direct-executions/api-reference/direct-executions-api/handling-the-state/direct-executions-v-1-handler-issue-session-token). **Resolving a pause through this API needs none of it** — collect the value and send it to the resume endpoint. The token is for the other option: handing that moment to your customer in our widget, which `widget_url` already carries it to. Keep it as you keep that URL. The prefix says which kind of run issued it: `st_test_` when the run is a rehearsal — a sandbox application, or a sandbox engine under a production one — and `st_live_` otherwise.
- `widget_url` (string, required) — Where your customer carries this execution on, opened by this token — the link the execution had opens nothing any more. Treat it as a credential, and append your way back (`completion_url`, `completion_mode`) to it yourself.
- `expiration_date` (string, required) — When the token stops opening anything, in UTC: the execution's own expiration, a day after it started. Issuing another token does not move it.

## Errors

### 400 Bad Request Error

**400 Bad Request**It has closed: a closed execution gets no new token. Its current one keeps showing how it ended until it expires, and you can still revoke it.

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

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

### 409 Conflict Error

**409 Conflict**It is not one of your direct executions: a flow launched it, and that flow's own session is what its person carries it on with.

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

### 422 Unprocessable Entity Error

Validation Error

- `detail` (list of ValidationError, optional)

## Types

### ValidationError

- `loc` (list of ValidationErrorLocItems, required)
- `msg` (string, required)
- `type` (string, required)
- `input` (any, optional)
- `ctx` (ValidationErrorCtx, optional)

### ValidationErrorLocItems

- string
- integer

### ValidationErrorCtx

## Examples

**Response**

```json
{
  "session_token": "st_test_Q2wPzN8rTkLm4XyB.Hn7vC3dF9sJ1kR5tW0zQ",
  "widget_url": "https://infonite.app/direct-execution?execution_id=6aa3d8b418d1c5dc9a8e3d36&session_token=st_test_Q2wPzN8rTkLm4XyB.Hn7vC3dF9sJ1kR5tW0zQ",
  "expiration_date": "2026-09-13T10:15:42+00:00"
}
```

**SDK Code**

```python A new token, and its widget link
import requests

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

headers = {"X-APP-SECRET": "<apiKey>"}

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

print(response.json())
```

```javascript A new token, and its widget link
const url = 'https://clients.infonite.tech/api/executions/handler/v1/6aa3d8b418d1c5dc9a8e3d36/session-token';
const options = {method: 'PUT', headers: {'X-APP-SECRET': '<apiKey>'}};

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

```go A new token, and its widget link
package main

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

func main() {

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

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

	req.Header.Add("X-APP-SECRET", "<apiKey>")

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

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

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

}
```

```ruby A new token, and its widget link
require 'uri'
require 'net/http'

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

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

request = Net::HTTP::Put.new(url)
request["X-APP-SECRET"] = '<apiKey>'

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

```java A new token, and its widget link
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/session-token")
  .header("X-APP-SECRET", "<apiKey>")
  .asString();
```

```php A new token, and its widget link
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('PUT', 'https://clients.infonite.tech/api/executions/handler/v1/6aa3d8b418d1c5dc9a8e3d36/session-token', [
  'headers' => [
    'X-APP-SECRET' => '<apiKey>',
  ],
]);

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

```csharp A new token, and its widget link
using RestSharp;

var client = new RestClient("https://clients.infonite.tech/api/executions/handler/v1/6aa3d8b418d1c5dc9a8e3d36/session-token");
var request = new RestRequest(Method.PUT);
request.AddHeader("X-APP-SECRET", "<apiKey>");
IRestResponse response = client.Execute(request);
```

```swift A new token, and its widget link
import Foundation

let headers = ["X-APP-SECRET": "<apiKey>"]

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

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()
```