> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tess.im/llms.txt
> Use this file to discover all available pages before exploring further.

# Stream Run

> Opens a Server-Sent Events (SSE) stream to follow a run in real time.

The stream endpoint uses Server-Sent Events (SSE) to deliver incremental run output. Connect to this endpoint while a run is `running` to receive output as it is generated.

### **Code Examples**

<CodeGroup>
  ```http cURL theme={null}
  curl --request GET \
    --url 'https://api.tess.im/digital-employees/{employeeId}/runs/{runId}/stream' \
    --header 'Authorization: Bearer YOUR_API_KEY' \
    --header 'x-workspace-id: YOUR_WORKSPACE_ID' \
    --header 'Accept: text/event-stream' \
    --no-buffer
  ```

  ```json Node.js theme={null}
  const https = require('https');

  const options = {
    hostname: 'api.tess.im',
    path: '/digital-employees/{employeeId}/runs/{runId}/stream',
    method: 'GET',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'x-workspace-id': 'YOUR_WORKSPACE_ID',
      'Accept': 'text/event-stream'
    }
  };

  const req = https.request(options, (res) => {
    res.on('data', (chunk) => {
      const lines = chunk.toString().split('\n');
      lines.forEach((line) => {
        if (line.startsWith('data: ')) {
          const data = JSON.parse(line.slice(6));
          if (data.delta) process.stdout.write(data.delta);
          if (data.status === 'completed') console.log('\nRun completed.');
        }
      });
    });
  });

  req.on('error', console.error);
  req.end();
  ```

  ```python Python theme={null}
  import requests
  import json

  url = "https://api.tess.im/digital-employees/{employeeId}/runs/{runId}/stream"
  headers = {
      "Authorization": "Bearer YOUR_API_KEY",
      "x-workspace-id": "YOUR_WORKSPACE_ID",
      "Accept": "text/event-stream"
  }

  with requests.get(url, headers=headers, stream=True) as response:
      for line in response.iter_lines():
          if line:
              decoded = line.decode('utf-8')
              if decoded.startswith('data: '):
                  data = json.loads(decoded[6:])
                  if 'delta' in data:
                      print(data['delta'], end='', flush=True)
                  if data.get('status') == 'completed':
                      print('\nRun completed.')
  ```

  ```php PHP theme={null}
  <?php
  $curl = curl_init();

  curl_setopt_array($curl, [
    CURLOPT_URL => "https://api.tess.im/digital-employees/{employeeId}/runs/{runId}/stream",
    CURLOPT_RETURNTRANSFER => false,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => "GET",
    CURLOPT_HTTPHEADER => [
      "Authorization: Bearer YOUR_API_KEY",
      "x-workspace-id: YOUR_WORKSPACE_ID",
      "Accept: text/event-stream"
    ],
    CURLOPT_WRITEFUNCTION => function($curl, $data) {
      $lines = explode("\n", $data);
      foreach ($lines as $line) {
        if (str_starts_with($line, 'data: ')) {
          $payload = json_decode(substr($line, 6), true);
          if (isset($payload['delta'])) echo $payload['delta'];
          if (($payload['status'] ?? '') === 'completed') echo "\nRun completed.";
        }
      }
      return strlen($data);
    }
  ]);

  curl_exec($curl);
  curl_close($curl);
  ```

  ```java Java theme={null}
  import java.net.URI;
  import java.net.http.HttpClient;
  import java.net.http.HttpRequest;
  import java.net.http.HttpResponse;
  import java.io.BufferedReader;
  import java.io.InputStreamReader;

  HttpClient client = HttpClient.newHttpClient();
  HttpRequest request = HttpRequest.newBuilder()
      .uri(URI.create("https://api.tess.im/digital-employees/{employeeId}/runs/{runId}/stream"))
      .header("Authorization", "Bearer YOUR_API_KEY")
      .header("x-workspace-id", "YOUR_WORKSPACE_ID")
      .header("Accept", "text/event-stream")
      .GET()
      .build();

  HttpResponse<java.io.InputStream> response = client.send(request,
      HttpResponse.BodyHandlers.ofInputStream());

  try (BufferedReader reader = new BufferedReader(new InputStreamReader(response.body()))) {
      String line;
      while ((line = reader.readLine()) != null) {
          if (line.startsWith("data: ")) {
              System.out.println(line.substring(6));
          }
      }
  }
  ```

  ```go Go theme={null}
  package main

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

  func main() {
      client := &http.Client{}
      req, _ := http.NewRequest("GET",
          "https://api.tess.im/digital-employees/{employeeId}/runs/{runId}/stream", nil)
      req.Header.Add("Authorization", "Bearer YOUR_API_KEY")
      req.Header.Add("x-workspace-id", "YOUR_WORKSPACE_ID")
      req.Header.Add("Accept", "text/event-stream")

      resp, _ := client.Do(req)
      defer resp.Body.Close()

      scanner := bufio.NewScanner(resp.Body)
      for scanner.Scan() {
          line := scanner.Text()
          if strings.HasPrefix(line, "data: ") {
              fmt.Println(line[6:])
          }
      }
  }
  ```

  ```jsonnet .NET theme={null}
  using System.Net.Http;
  using System.IO;

  using var client = new HttpClient();
  client.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_API_KEY");
  client.DefaultRequestHeaders.Add("x-workspace-id", "YOUR_WORKSPACE_ID");
  client.DefaultRequestHeaders.Add("Accept", "text/event-stream");

  using var response = await client.GetAsync(
      "https://api.tess.im/digital-employees/{employeeId}/runs/{runId}/stream",
      HttpCompletionOption.ResponseHeadersRead);

  using var stream = await response.Content.ReadAsStreamAsync();
  using var reader = new StreamReader(stream);

  while (!reader.EndOfStream)
  {
      var line = await reader.ReadLineAsync();
      if (line != null && line.StartsWith("data: "))
          Console.WriteLine(line.Substring(6));
  }
  ```

  ```ruby Ruby theme={null}
  require 'uri'
  require 'net/http'

  uri = URI('https://api.tess.im/digital-employees/{employeeId}/runs/{runId}/stream')
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true

  request = Net::HTTP::Get.new(uri)
  request['Authorization'] = 'Bearer YOUR_API_KEY'
  request['x-workspace-id'] = 'YOUR_WORKSPACE_ID'
  request['Accept'] = 'text/event-stream'

  http.request(request) do |response|
    response.read_body do |chunk|
      chunk.split("\n").each do |line|
        if line.start_with?('data: ')
          puts line[6..]
        end
      end
    end
  end
  ```
</CodeGroup>

### **Headers**

<Note>
  **Authorization:** Pass your API key as a Bearer token in the `Authorization` header: `Authorization: Bearer YOUR_API_KEY`.
</Note>

<ParamField header="x-workspace-id" type="integer" required>
  ID of the workspace. Required for all Digital Employees API requests.
</ParamField>

### **Path Parameters**

<ParamField path="employeeId" type="integer" required>
  The ID of the digital employee.
</ParamField>

<ParamField path="runId" type="integer" required>
  The ID of the run to stream.
</ParamField>

### **SSE Events**

| Event       | Description                                                                                                 |
| :---------- | :---------------------------------------------------------------------------------------------------------- |
| `delta`     | Incremental output chunk. Contains partial text output as the run progresses.                               |
| `complete`  | Final snapshot with `status`, `output`, `rendered_output`, and run metadata. Signals the end of the stream. |
| `heartbeat` | Keep-alive comment (`: heartbeat`) sent periodically to maintain the connection.                            |

### **delta Event Shape**

```
data: {"delta": "The financial report..."}
```

### **complete Event Shape**

```
data: {"status": "completed", "output": "The financial report for Q2 is complete.", "rendered_output": "...", "execution_id": 9001}
```

<Note>Connect to this endpoint only while the run status is `running`. If the run has already finished, use [Get Run Output](/en/de-run-output) instead.</Note>
