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

# Stream Run Logs (WebSocket)

> Stream a run's live `app.log` over a **WebSocket** as the job progresses — the same log the dashboard's run view shows.

This is not a normal HTTP request: connect with a WebSocket client, not `curl`. It is documented here as `GET` because OpenAPI has no way to declare a `wss://` operation. Replace the `https://` in the server URL with `wss://`.

**Building the URL.** Do not assemble the path by hand — a run reports it as `logs_url`, on the launch response (`POST /rt/redteam`, `/rt/eval`, `/rt/playground`) and on `GET /rt/runs/{run_id}`. That value is relative; join it onto `wss://api.enkryptai.com/wss/redteam/v1/logs/tasks/` and append `?apikey=<your key>`. The `v1` in that prefix is the gateway route's own name, not a version of the Red Team API; `v2` is an identical alias.

**Authentication.** The key goes in the query string, not the `apikey` header, because a browser cannot set headers on a WebSocket handshake. The resulting URL therefore contains your API key — do not log it or share it.

**What you receive.** One text frame per log line, already formatted (`<timestamp> - <LEVEL> - <message>`). Lines already produced are replayed first, so connecting part-way through still gives you the run from the beginning; the server then tails, and closes the socket once the run reaches a terminal state. Retention is limited, so a long-finished run may replay from its stored `app.log` instead.

**Ownership.** The first path segment is the run's owner and must match the account your API key belongs to; another account's run is a `403`. A run started with an organization key is owned by the organization.

<Info>
  **There is no Try-it control on this page, on purpose.** This address is a WebSocket
  upgrade, not a request/response `GET`, so it cannot be exercised over HTTP — the playground
  is suppressed rather than offered and left to fail. Dial it with `wss://` from a WebSocket
  client, or use `stream_logs()` in the Python SDK, which resolves the URL from a run id and
  hands you the lines.

  It is documented as a `GET` only because OpenAPI has no way to declare a `wss://`
  operation.
</Info>

<Warning>
  Do not assemble this path by hand. A run reports it as `logs_url` — on the launch response
  and on [Get Run Status](/api-reference/redteam-v2-api-reference/endpoint/get-run-status) —
  and that value is what you join onto
  `wss://api.enkryptai.com/wss/redteam/v1/logs/tasks/`. Building it yourself is how you end
  up with a socket that opens and then never emits a line, because the run id has to be the
  prefixed one (`rt-…`) and the model folder follows a naming rule.

  The API key rides in the **query string** here, not the `apikey` header, so the finished URL
  is itself a secret.
</Warning>

For the walkthrough — starting a run, following its logs, and reading the results — see
step 5 of [Red Teaming Through the Relay Bridge](/get-started/redteam/relay-bridge).


## OpenAPI

````yaml GET /wss/redteam/v1/logs/tasks/{owner_id}/{job_id}/{model_folder}/app.log
openapi: 3.0.0
info:
  title: Enkrypt AI APIs
  version: 2.0.0
servers:
  - url: https://api.enkryptai.com
security:
  - apiKeyAuth: []
tags:
  - name: Guardrails
  - name: Code of Conduct
  - name: Endpoints
  - name: Redteam
    description: >-
      Red Team API: submit red-team / threat-modeling / playground / eval runs,
      then poll run status, records, results and compliance. Also two-phase
      threat modeling (categories + data), dataset retrieval, model health,
      findings and risk mitigation. The previous task-based Red Team API is
      under **Archived**.
  - name: Deployments
  - name: AI Proxy
  - name: Leaderboard
  - name: Archived
  - name: MCP Hub
    description: >-
      MCP Hub vulnerability scanning APIs. Submitting scans (the POST endpoints)
      is open to all authenticated callers. The scan **retrieval** APIs — Get
      Scan Job Status, Get Complete Scan Results, List Scans, and Get MCP Hub
      Scan Statistics (the GET endpoints) — are an **enterprise data-license
      feature**: they require your organization to have MCP Hub API access
      enabled by Enkrypt, otherwise they return `403`. Contact us at
      support@enkryptai.com to enable access.
  - name: MCP Registry Servers
  - name: MCP Gateways
  - name: MCP Playground
paths:
  /wss/redteam/v1/logs/tasks/{owner_id}/{job_id}/{model_folder}/app.log:
    get:
      tags:
        - Redteam
      summary: Stream Run Logs (WebSocket)
      description: >-
        Stream a run's live `app.log` over a **WebSocket** as the job progresses
        — the same log the dashboard's run view shows.


        This is not a normal HTTP request: connect with a WebSocket client, not
        `curl`. It is documented here as `GET` because OpenAPI has no way to
        declare a `wss://` operation. Replace the `https://` in the server URL
        with `wss://`.


        **Building the URL.** Do not assemble the path by hand — a run reports
        it as `logs_url`, on the launch response (`POST /rt/redteam`,
        `/rt/eval`, `/rt/playground`) and on `GET /rt/runs/{run_id}`. That value
        is relative; join it onto
        `wss://api.enkryptai.com/wss/redteam/v1/logs/tasks/` and append
        `?apikey=<your key>`. The `v1` in that prefix is the gateway route's own
        name, not a version of the Red Team API; `v2` is an identical alias.


        **Authentication.** The key goes in the query string, not the `apikey`
        header, because a browser cannot set headers on a WebSocket handshake.
        The resulting URL therefore contains your API key — do not log it or
        share it.


        **What you receive.** One text frame per log line, already formatted
        (`<timestamp> - <LEVEL> - <message>`). Lines already produced are
        replayed first, so connecting part-way through still gives you the run
        from the beginning; the server then tails, and closes the socket once
        the run reaches a terminal state. Retention is limited, so a
        long-finished run may replay from its stored `app.log` instead.


        **Ownership.** The first path segment is the run's owner and must match
        the account your API key belongs to; another account's run is a `403`. A
        run started with an organization key is owned by the organization.
      operationId: stream_run_logs_websocket
      parameters:
        - name: owner_id
          in: path
          required: true
          description: >-
            The run's owner id, as reported in `user_metadata.user_id`. Must
            match the account the API key belongs to.
          schema:
            type: string
            title: Owner Id
        - name: job_id
          in: path
          required: true
          description: >-
            The prefixed run id, e.g. `rt-<uuid>` or `eval-<uuid>`. A bare uuid
            opens a socket that never emits anything.
          schema:
            title: Job Id
            type: string
        - name: model_folder
          in: path
          required: true
          description: >-
            The target model's folder segment: the part of `model_name` after
            the last `/`, with `_<model_version>` appended when a version is
            set. `unknown` for runs with no target, such as eval.
          schema:
            type: string
            title: Model Folder
        - name: apikey
          in: query
          required: true
          description: >-
            Your API key. In the query string because a WebSocket handshake
            cannot carry headers.
          schema:
            type: string
            title: Api Key
      responses:
        '101':
          description: >-
            Switching Protocols - the socket is open and log lines follow as
            text frames.
        '403':
          description: The owner id in the path is not the account this API key belongs to.
        '429':
          description: >-
            Too many handshakes from this IP. The connection limit is per IP,
            not per key.
      security:
        - apiKeyQueryAuth: []
components:
  securitySchemes:
    apiKeyAuth:
      type: apiKey
      in: header
      name: apikey
    apiKeyQueryAuth:
      type: apiKey
      in: query
      name: apikey
      description: >-
        API key passed as a query parameter instead of a header. Used only by
        the log-streaming WebSocket, because the browser WebSocket API cannot
        set request headers on the handshake. Treat the resulting URL as a
        secret.

````