# Egress

> Manage OpenWAF Egress, the gateway between your AI agents and their providers, with targets, credentials, agents and events.

OpenWAF Egress sits between your AI agents and their providers. Agents call the gateway with a substitute token, and the gateway adds the real provider credential, inspects the request and blocks injections, data leaks and disallowed destinations. Reads need the `readonly` role and writes `admin`, both organization-wide; creating and changing agents, targets and credentials and reading events require the egress feature to be enabled for the organization (otherwise 403 `feature_disabled`). See [OpenWAF Egress](https://developers.openwaf.dev/egress/).

| Operation | Endpoint |
|---|---|
| [Get egress status](https://developers.openwaf.dev/api/egress/#get-egress) | `GET /v1/orgs/{org}/egress` |
| [List targets](https://developers.openwaf.dev/api/egress/#list-egress-targets) | `GET /v1/orgs/{org}/egress/targets` |
| [Create target](https://developers.openwaf.dev/api/egress/#create-egress-target) | `POST /v1/orgs/{org}/egress/targets` |
| [Delete target](https://developers.openwaf.dev/api/egress/#delete-egress-target) | `DELETE /v1/orgs/{org}/egress/targets/{target}` |
| [Set target credential](https://developers.openwaf.dev/api/egress/#put-egress-credential) | `PUT /v1/orgs/{org}/egress/targets/{target}/credential` |
| [Delete target credential](https://developers.openwaf.dev/api/egress/#delete-egress-credential) | `DELETE /v1/orgs/{org}/egress/targets/{target}/credential` |
| [List agents](https://developers.openwaf.dev/api/egress/#list-egress-agents) | `GET /v1/orgs/{org}/egress/agents` |
| [Create agent](https://developers.openwaf.dev/api/egress/#create-egress-agent) | `POST /v1/orgs/{org}/egress/agents` |
| [Get agent](https://developers.openwaf.dev/api/egress/#get-egress-agent) | `GET /v1/orgs/{org}/egress/agents/{agent}` |
| [Update agent](https://developers.openwaf.dev/api/egress/#update-egress-agent) | `PATCH /v1/orgs/{org}/egress/agents/{agent}` |
| [Delete agent](https://developers.openwaf.dev/api/egress/#delete-egress-agent) | `DELETE /v1/orgs/{org}/egress/agents/{agent}` |
| [Rotate agent token](https://developers.openwaf.dev/api/egress/#rotate-egress-agent-token) | `POST /v1/orgs/{org}/egress/agents/{agent}/rotate-token` |
| [List egress events](https://developers.openwaf.dev/api/egress/#list-egress-events) | `GET /v1/orgs/{org}/egress/events` |
| [Stream egress events](https://developers.openwaf.dev/api/egress/#stream-egress-events) | `GET /v1/orgs/{org}/egress/events/stream` |

## Get egress status

```http
GET /v1/orgs/{org}/egress
```

Returns the egress status of the organization. It can be read without the egress feature (`enabled` false). Without the feature, reading and deleting agents, targets and credentials keeps working so the organization can remove its keys.

**Required role:** `readonly` or higher. Organization-wide.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |

#### Response

- `200`: Returns [EgressOverview](https://developers.openwaf.dev/api/schemas/#egress-overview).

| Field | Type | Description |
|---|---|---|
| `enabled` | boolean | The organization has the egress feature. |
| `gateway_url` | string |  |
| `credentials_available` | boolean | Credentials can be stored right now. |

#### Errors

| Status | Description |
|---|---|
| `403` | The token's role or limits do not allow it (`forbidden`). |

#### Example

**curl**


```sh
curl "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/egress" \
  -H "Authorization: Bearer $OPENWAF_TOKEN"
```

**TypeScript**


```ts
import { OpenWAF } from "./openwaf";

const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token from OPENWAF_TOKEN
const result = await owf.getEgress();
```

**Python**


```py
from openwaf import OpenWAF

owf = OpenWAF(base_url="https://dash.openwaf.dev")  # token from OPENWAF_TOKEN
result = owf.get_egress()
```



```json
{
  "enabled": false,
  "gateway_url": "https://egress.openwaf.dev",
  "credentials_available": false
}
```

## List targets

```http
GET /v1/orgs/{org}/egress/targets
```

Lists the egress targets, the catalog providers and your own, with the status of their credential.

**Required role:** `readonly` or higher. Organization-wide.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |

#### Response

- `200`: Returns `items`, an array of [EgressTarget](https://developers.openwaf.dev/api/schemas/#egress-target).

| Field | Type | Description |
|---|---|---|
| `items[].id` | string | Id. |
| `items[].name` | string | Name. |
| `items[].base_url` | string |  |
| `items[].host` | string |  |
| `items[].auth_header` | string |  |
| `items[].auth_prefix` | string |  |
| `items[].custom` | boolean | Own target of the organization (false = catalog). |
| `items[].docs_url` | string |  |
| `items[].credential` | [EgressCredential](https://developers.openwaf.dev/api/schemas/#egress-credential) |  |

#### Errors

| Status | Description |
|---|---|
| `403` | The token's role or limits do not allow it (`forbidden`). |

#### Example

**curl**


```sh
curl "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/egress/targets" \
  -H "Authorization: Bearer $OPENWAF_TOKEN"
```

**TypeScript**


```ts
import { OpenWAF } from "./openwaf";

const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token from OPENWAF_TOKEN
const result = await owf.listEgressTargets();
```

**Python**


```py
from openwaf import OpenWAF

owf = OpenWAF(base_url="https://dash.openwaf.dev")  # token from OPENWAF_TOKEN
result = owf.list_egress_targets()
```



```json
{
  "items": [
    {
      "id": "openrouter",
      "name": "example.com",
      "base_url": "https://llm.example.com/v1",
      "host": "www.example.com",
      "auth_header": "Authorization",
      "auth_prefix": "Bearer ",
      "custom": false,
      "docs_url": "https://platform.openai.com/docs/api-reference",
      "credential": {
        "fingerprint": "sha256:3f9a1c2b7d4e",
        "updated_at": "2026-10-27T09:30:00Z",
        "updated_by": "token:11111111-2222-4333-8444-555555555555"
      }
    }
  ]
}
```

## Create target

```http
POST /v1/orgs/{org}/egress/targets
```

Creates an own HTTPS target. `base_url` must be `https://` on port 443 with a public DNS name (no IP address, user, query or fragment). On every request the gateway also checks that the name only resolves to public addresses (`ssrf_blocked`).

**Required role:** `admin` or higher. Organization-wide.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |

#### Request body

Content type `application/json`.

| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string | Yes | Cannot be a catalog id. Pattern `^[a-z][a-z0-9-]{1,31}$`. |
| `name` | string | Yes | Name. 1 to 100 characters. |
| `base_url` | string | Yes | At most 2048 characters. |
| `auth_header` | string | No | Default `Authorization`. Pattern `^[A-Za-z0-9-]{1,64}$`. |
| `auth_prefix` | string | No | `Bearer ` by default with Authorization, empty with other headers. At most 32 characters. |

#### Response

- `201`: Created. Returns [EgressTarget](https://developers.openwaf.dev/api/schemas/#egress-target).

| Field | Type | Description |
|---|---|---|
| `id` | string | Id. |
| `name` | string | Name. |
| `base_url` | string |  |
| `host` | string |  |
| `auth_header` | string |  |
| `auth_prefix` | string |  |
| `custom` | boolean | Own target of the organization (false = catalog). |
| `docs_url` | string |  |
| `credential` | [EgressCredential](https://developers.openwaf.dev/api/schemas/#egress-credential) |  |

#### Errors

| Status | Description |
|---|---|
| `403` | The token's role or limits do not allow it (`forbidden`). |
| `409` | The current state does not allow it (`conflict`). |
| `422` | Validation error (`invalid`). |

#### Example

**curl**


```sh
curl -X POST "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/egress/targets" \
  -H "Authorization: Bearer $OPENWAF_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "id": "internal-llm",
    "name": "Internal LLM",
    "base_url": "https://llm.example.com/v1"
  }'
```

**TypeScript**


```ts
import { OpenWAF } from "./openwaf";

const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token from OPENWAF_TOKEN
const result = await owf.createEgressTarget({
  body: {
    id: "internal-llm",
    name: "Internal LLM",
    base_url: "https://llm.example.com/v1"
  }
});
```

**Python**


```py
from openwaf import OpenWAF

owf = OpenWAF(base_url="https://dash.openwaf.dev")  # token from OPENWAF_TOKEN
result = owf.create_egress_target(
    body={
        "id": "internal-llm",
        "name": "Internal LLM",
        "base_url": "https://llm.example.com/v1"
    },
)
```



```json
{
  "id": "openrouter",
  "name": "example.com",
  "base_url": "https://llm.example.com/v1",
  "host": "www.example.com",
  "auth_header": "Authorization",
  "auth_prefix": "Bearer ",
  "custom": false,
  "docs_url": "https://platform.openai.com/docs/api-reference",
  "credential": {
    "fingerprint": "sha256:3f9a1c2b7d4e",
    "updated_at": "2026-10-27T09:30:00Z",
    "updated_by": "token:11111111-2222-4333-8444-555555555555"
  }
}
```

## Delete target

```http
DELETE /v1/orgs/{org}/egress/targets/{target}
```

Deletes an own target and its credential. Catalog targets cannot be deleted.

**Required role:** `admin` or higher. Organization-wide.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |
| `target` | path | string | Yes | Egress target id: a catalog id such as `openai` or the id of an own target. Pattern `^[a-z][a-z0-9-]{1,31}$`. |

#### Response

- `204`: Deleted. No body.

#### Errors

| Status | Description |
|---|---|
| `403` | The token's role or limits do not allow it (`forbidden`). |
| `404` | Not found, or not visible to the token (`not_found`). |
| `409` | `target_in_use`: some agent allows it. |
| `422` | `invalid`: catalog targets cannot be deleted. |

#### Example

**curl**


```sh
curl -X DELETE "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/egress/targets/openai" \
  -H "Authorization: Bearer $OPENWAF_TOKEN"
```

**TypeScript**


```ts
import { OpenWAF } from "./openwaf";

const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token from OPENWAF_TOKEN
const result = await owf.deleteEgressTarget({
  target: "openai"
});
```

**Python**


```py
from openwaf import OpenWAF

owf = OpenWAF(base_url="https://dash.openwaf.dev")  # token from OPENWAF_TOKEN
result = owf.delete_egress_target(target="openai")
```



## Set target credential

```http
PUT /v1/orgs/{org}/egress/targets/{target}/credential
```

Stores or replaces the provider credential of a target. It is write-only, kept in a dedicated secret store, never logged and never returned; the answer only carries its fingerprint (`sha256:` and 12 hexadecimal characters).

**Required role:** `admin` or higher. Organization-wide.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |
| `target` | path | string | Yes | Egress target id: a catalog id such as `openai` or the id of an own target. Pattern `^[a-z][a-z0-9-]{1,31}$`. |

#### Request body

Content type `application/json`.

| Field | Type | Required | Description |
|---|---|---|---|
| `secret` | string | Yes | 1 to 8192 characters. |

#### Response

- `200`: Returns [EgressTarget](https://developers.openwaf.dev/api/schemas/#egress-target).

| Field | Type | Description |
|---|---|---|
| `id` | string | Id. |
| `name` | string | Name. |
| `base_url` | string |  |
| `host` | string |  |
| `auth_header` | string |  |
| `auth_prefix` | string |  |
| `custom` | boolean | Own target of the organization (false = catalog). |
| `docs_url` | string |  |
| `credential` | [EgressCredential](https://developers.openwaf.dev/api/schemas/#egress-credential) |  |

#### Errors

| Status | Description |
|---|---|
| `403` | The token's role or limits do not allow it (`forbidden`). |
| `404` | Not found, or not visible to the token (`not_found`). |
| `422` | Validation error (`invalid`). |
| `502` | A dependency refused or did not answer; retry later. |
| `503` | Not available right now (`unavailable`); retry later. |

#### Example

**curl**


```sh
curl -X PUT "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/egress/targets/openai/credential" \
  -H "Authorization: Bearer $OPENWAF_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "secret": "sk-…"
  }'
```

**TypeScript**


```ts
import { OpenWAF } from "./openwaf";

const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token from OPENWAF_TOKEN
const result = await owf.putEgressCredential({
  target: "openai",
  body: {
    secret: "sk-…"
  }
});
```

**Python**


```py
from openwaf import OpenWAF

owf = OpenWAF(base_url="https://dash.openwaf.dev")  # token from OPENWAF_TOKEN
result = owf.put_egress_credential(
    target="openai",
    body={
        "secret": "sk-…"
    },
)
```



```json
{
  "id": "openrouter",
  "name": "example.com",
  "base_url": "https://llm.example.com/v1",
  "host": "www.example.com",
  "auth_header": "Authorization",
  "auth_prefix": "Bearer ",
  "custom": false,
  "docs_url": "https://platform.openai.com/docs/api-reference",
  "credential": {
    "fingerprint": "sha256:3f9a1c2b7d4e",
    "updated_at": "2026-10-27T09:30:00Z",
    "updated_by": "token:11111111-2222-4333-8444-555555555555"
  }
}
```

## Delete target credential

```http
DELETE /v1/orgs/{org}/egress/targets/{target}/credential
```

Deletes the provider credential of a target, every stored version. Idempotent; it also works without the egress feature.

**Required role:** `admin` or higher. Organization-wide.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |
| `target` | path | string | Yes | Egress target id: a catalog id such as `openai` or the id of an own target. Pattern `^[a-z][a-z0-9-]{1,31}$`. |

#### Response

- `204`: Deleted (or did not exist). No body.

#### Errors

| Status | Description |
|---|---|
| `403` | The token's role or limits do not allow it (`forbidden`). |
| `404` | Not found, or not visible to the token (`not_found`). |
| `502` | A dependency refused or did not answer; retry later. |
| `503` | Not available right now (`unavailable`); retry later. |

#### Example

**curl**


```sh
curl -X DELETE "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/egress/targets/openai/credential" \
  -H "Authorization: Bearer $OPENWAF_TOKEN"
```

**TypeScript**


```ts
import { OpenWAF } from "./openwaf";

const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token from OPENWAF_TOKEN
const result = await owf.deleteEgressCredential({
  target: "openai"
});
```

**Python**


```py
from openwaf import OpenWAF

owf = OpenWAF(base_url="https://dash.openwaf.dev")  # token from OPENWAF_TOKEN
result = owf.delete_egress_credential(target="openai")
```



## List agents

```http
GET /v1/orgs/{org}/egress/agents
```

Lists the egress agents of the organization.

**Required role:** `readonly` or higher. Organization-wide.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |

#### Response

- `200`: Returns `items`, an array of [EgressAgent](https://developers.openwaf.dev/api/schemas/#egress-agent).

| Field | Type | Description |
|---|---|---|
| `items[].id` | string (uuid) | Id. |
| `items[].name` | string | Name. |
| `items[].description` | string |  |
| `items[].allowed_targets` | array of string |  |
| `items[].enforce_injection` | boolean |  |
| `items[].block_dlp` | boolean |  |
| `items[].disabled` | boolean |  |
| `items[].token_prefix` | string | Start of the token (`OWE_TOKEN_` and 6 characters), to recognise it. |
| `items[].token_rotated_at` | string (date-time) |  |
| `items[].created_at` | string (date-time) | Creation time. |
| `items[].created_by` | string | Who created it (actor). |
| `items[].updated_at` | string (date-time) | Last change. |
| `items[].base_urls` | map of string | SDK base URL for each allowed target. |

#### Errors

| Status | Description |
|---|---|
| `403` | The token's role or limits do not allow it (`forbidden`). |

#### Example

**curl**


```sh
curl "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/egress/agents" \
  -H "Authorization: Bearer $OPENWAF_TOKEN"
```

**TypeScript**


```ts
import { OpenWAF } from "./openwaf";

const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token from OPENWAF_TOKEN
const result = await owf.listEgressAgents();
```

**Python**


```py
from openwaf import OpenWAF

owf = OpenWAF(base_url="https://dash.openwaf.dev")  # token from OPENWAF_TOKEN
result = owf.list_egress_agents()
```



```json
{
  "items": [
    {
      "id": "a5614527-0ce6-43be-ad1d-d012b7394867",
      "name": "example.com",
      "description": "Support assistant",
      "allowed_targets": [
        "openai"
      ],
      "enforce_injection": false,
      "block_dlp": false,
      "disabled": false,
      "token_prefix": "OWE_TOKEN_ab12cd",
      "token_rotated_at": "2026-10-27T09:30:00Z",
      "created_at": "2026-10-27T09:30:00Z",
      "created_by": "token:11111111-2222-4333-8444-555555555555",
      "updated_at": "2026-10-27T09:30:00Z",
      "base_urls": {
        "openrouter": "https://egress.openwaf.dev/v1/agent/support-bot/proxy/openrouter"
      }
    }
  ]
}
```

## Create agent

```http
POST /v1/orgs/{org}/egress/agents
```

Creates an agent allowed to call some targets through the gateway. Its substitute `token` is returned only in this answer. `name` is part of the agent's gateway URLs and cannot change.

**Required role:** `admin` or higher. Organization-wide.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |

#### Request body

Content type `application/json`.

| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | Yes | Unique in the organization; part of its gateway URLs and cannot change. Pattern `^[a-z0-9][a-z0-9-]{0,62}$`. |
| `description` | string | No | At most 500 characters. |
| `allowed_targets` | array of string | Yes | 1 to 32 items. |
| `enforce_injection` | boolean | No | Default `true`. |
| `block_dlp` | boolean | No | Default `true`. |
| `disabled` | boolean | No | Default `false`. |

#### Response

- `201`: Created; `token` is shown only once. Returns [IssuedEgressAgent](https://developers.openwaf.dev/api/schemas/#issued-egress-agent).

| Field | Type | Description |
|---|---|---|
| `agent` | [EgressAgent](https://developers.openwaf.dev/api/schemas/#egress-agent) |  |
| `token` | string | Substitute token `OWE_TOKEN_…`; shown only once (only its SHA-256 is stored). |

#### Errors

| Status | Description |
|---|---|
| `403` | The token's role or limits do not allow it (`forbidden`). |
| `409` | The current state does not allow it (`conflict`). |
| `422` | Validation error (`invalid`). |

#### Example

**curl**


```sh
curl -X POST "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/egress/agents" \
  -H "Authorization: Bearer $OPENWAF_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "name": "support-bot",
    "allowed_targets": [
      "openai"
    ]
  }'
```

**TypeScript**


```ts
import { OpenWAF } from "./openwaf";

const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token from OPENWAF_TOKEN
const result = await owf.createEgressAgent({
  body: {
    name: "support-bot",
    allowed_targets: [
      "openai"
    ]
  }
});
```

**Python**


```py
from openwaf import OpenWAF

owf = OpenWAF(base_url="https://dash.openwaf.dev")  # token from OPENWAF_TOKEN
result = owf.create_egress_agent(
    body={
        "name": "support-bot",
        "allowed_targets": [
            "openai"
        ]
    },
)
```



```json
{
  "agent": {
    "id": "a5614527-0ce6-43be-ad1d-d012b7394867",
    "name": "example.com",
    "description": "Support assistant",
    "allowed_targets": [
      "openai"
    ],
    "enforce_injection": false,
    "block_dlp": false,
    "disabled": false,
    "token_prefix": "OWE_TOKEN_ab12cd",
    "token_rotated_at": "2026-10-27T09:30:00Z",
    "created_at": "2026-10-27T09:30:00Z",
    "created_by": "token:11111111-2222-4333-8444-555555555555",
    "updated_at": "2026-10-27T09:30:00Z",
    "base_urls": {
      "openrouter": "https://egress.openwaf.dev/v1/agent/support-bot/proxy/openrouter"
    }
  },
  "token": "owf_…"
}
```

## Get agent

```http
GET /v1/orgs/{org}/egress/agents/{agent}
```

Returns one egress agent.

**Required role:** `readonly` or higher. Organization-wide.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |
| `agent` | path | string (uuid) | Yes | Egress agent id. |

#### Response

- `200`: Returns [EgressAgent](https://developers.openwaf.dev/api/schemas/#egress-agent).

| Field | Type | Description |
|---|---|---|
| `id` | string (uuid) | Id. |
| `name` | string | Name. |
| `description` | string |  |
| `allowed_targets` | array of string |  |
| `enforce_injection` | boolean |  |
| `block_dlp` | boolean |  |
| `disabled` | boolean |  |
| `token_prefix` | string | Start of the token (`OWE_TOKEN_` and 6 characters), to recognise it. |
| `token_rotated_at` | string (date-time) |  |
| `created_at` | string (date-time) | Creation time. |
| `created_by` | string | Who created it (actor). |
| `updated_at` | string (date-time) | Last change. |
| `base_urls` | map of string | SDK base URL for each allowed target. |

#### Errors

| Status | Description |
|---|---|
| `403` | The token's role or limits do not allow it (`forbidden`). |
| `404` | Not found, or not visible to the token (`not_found`). |

#### Example

**curl**


```sh
curl "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/egress/agents/4a2c6e8b-0d1f-4c3e-9b5a-7d9f1b3e5a7c" \
  -H "Authorization: Bearer $OPENWAF_TOKEN"
```

**TypeScript**


```ts
import { OpenWAF } from "./openwaf";

const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token from OPENWAF_TOKEN
const result = await owf.getEgressAgent({
  agent: "4a2c6e8b-0d1f-4c3e-9b5a-7d9f1b3e5a7c"
});
```

**Python**


```py
from openwaf import OpenWAF

owf = OpenWAF(base_url="https://dash.openwaf.dev")  # token from OPENWAF_TOKEN
result = owf.get_egress_agent(agent="4a2c6e8b-0d1f-4c3e-9b5a-7d9f1b3e5a7c")
```



```json
{
  "id": "a5614527-0ce6-43be-ad1d-d012b7394867",
  "name": "example.com",
  "description": "Support assistant",
  "allowed_targets": [
    "openai"
  ],
  "enforce_injection": false,
  "block_dlp": false,
  "disabled": false,
  "token_prefix": "OWE_TOKEN_ab12cd",
  "token_rotated_at": "2026-10-27T09:30:00Z",
  "created_at": "2026-10-27T09:30:00Z",
  "created_by": "token:11111111-2222-4333-8444-555555555555",
  "updated_at": "2026-10-27T09:30:00Z",
  "base_urls": {
    "openrouter": "https://egress.openwaf.dev/v1/agent/support-bot/proxy/openrouter"
  }
}
```

## Update agent

```http
PATCH /v1/orgs/{org}/egress/agents/{agent}
```

Changes an agent. Fields left out keep their value; the name cannot change.

**Required role:** `admin` or higher. Organization-wide.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |
| `agent` | path | string (uuid) | Yes | Egress agent id. |

#### Request body

Content type `application/json`.

| Field | Type | Required | Description |
|---|---|---|---|
| `description` | string | No | At most 500 characters. |
| `allowed_targets` | array of string | No | 1 to 32 items. |
| `enforce_injection` | boolean | No |  |
| `block_dlp` | boolean | No |  |
| `disabled` | boolean | No |  |

#### Response

- `200`: Returns [EgressAgent](https://developers.openwaf.dev/api/schemas/#egress-agent).

| Field | Type | Description |
|---|---|---|
| `id` | string (uuid) | Id. |
| `name` | string | Name. |
| `description` | string |  |
| `allowed_targets` | array of string |  |
| `enforce_injection` | boolean |  |
| `block_dlp` | boolean |  |
| `disabled` | boolean |  |
| `token_prefix` | string | Start of the token (`OWE_TOKEN_` and 6 characters), to recognise it. |
| `token_rotated_at` | string (date-time) |  |
| `created_at` | string (date-time) | Creation time. |
| `created_by` | string | Who created it (actor). |
| `updated_at` | string (date-time) | Last change. |
| `base_urls` | map of string | SDK base URL for each allowed target. |

#### Errors

| Status | Description |
|---|---|
| `403` | The token's role or limits do not allow it (`forbidden`). |
| `404` | Not found, or not visible to the token (`not_found`). |
| `422` | Validation error (`invalid`). |

#### Example

**curl**


```sh
curl -X PATCH "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/egress/agents/4a2c6e8b-0d1f-4c3e-9b5a-7d9f1b3e5a7c" \
  -H "Authorization: Bearer $OPENWAF_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "allowed_targets": [
      "openai",
      "anthropic"
    ]
  }'
```

**TypeScript**


```ts
import { OpenWAF } from "./openwaf";

const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token from OPENWAF_TOKEN
const result = await owf.updateEgressAgent({
  agent: "4a2c6e8b-0d1f-4c3e-9b5a-7d9f1b3e5a7c",
  body: {
    allowed_targets: [
      "openai",
      "anthropic"
    ]
  }
});
```

**Python**


```py
from openwaf import OpenWAF

owf = OpenWAF(base_url="https://dash.openwaf.dev")  # token from OPENWAF_TOKEN
result = owf.update_egress_agent(
    agent="4a2c6e8b-0d1f-4c3e-9b5a-7d9f1b3e5a7c",
    body={
        "allowed_targets": [
            "openai",
            "anthropic"
        ]
    },
)
```



```json
{
  "id": "a5614527-0ce6-43be-ad1d-d012b7394867",
  "name": "example.com",
  "description": "Support assistant",
  "allowed_targets": [
    "openai"
  ],
  "enforce_injection": false,
  "block_dlp": false,
  "disabled": false,
  "token_prefix": "OWE_TOKEN_ab12cd",
  "token_rotated_at": "2026-10-27T09:30:00Z",
  "created_at": "2026-10-27T09:30:00Z",
  "created_by": "token:11111111-2222-4333-8444-555555555555",
  "updated_at": "2026-10-27T09:30:00Z",
  "base_urls": {
    "openrouter": "https://egress.openwaf.dev/v1/agent/support-bot/proxy/openrouter"
  }
}
```

## Delete agent

```http
DELETE /v1/orgs/{org}/egress/agents/{agent}
```

Deletes an egress agent; its token stops working.

**Required role:** `admin` or higher. Organization-wide.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |
| `agent` | path | string (uuid) | Yes | Egress agent id. |

#### Response

- `204`: Deleted. No body.

#### Errors

| Status | Description |
|---|---|
| `403` | The token's role or limits do not allow it (`forbidden`). |
| `404` | Not found, or not visible to the token (`not_found`). |

#### Example

**curl**


```sh
curl -X DELETE "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/egress/agents/4a2c6e8b-0d1f-4c3e-9b5a-7d9f1b3e5a7c" \
  -H "Authorization: Bearer $OPENWAF_TOKEN"
```

**TypeScript**


```ts
import { OpenWAF } from "./openwaf";

const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token from OPENWAF_TOKEN
const result = await owf.deleteEgressAgent({
  agent: "4a2c6e8b-0d1f-4c3e-9b5a-7d9f1b3e5a7c"
});
```

**Python**


```py
from openwaf import OpenWAF

owf = OpenWAF(base_url="https://dash.openwaf.dev")  # token from OPENWAF_TOKEN
result = owf.delete_egress_agent(agent="4a2c6e8b-0d1f-4c3e-9b5a-7d9f1b3e5a7c")
```



## Rotate agent token

```http
POST /v1/orgs/{org}/egress/agents/{agent}/rotate-token
```

Gives the agent a new substitute token, returned only in this answer. The previous one stops working as soon as the gateways load the new configuration.

**Required role:** `admin` or higher. Organization-wide.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |
| `agent` | path | string (uuid) | Yes | Egress agent id. |

#### Response

- `200`: OK; `token` is shown only once. Returns [IssuedEgressAgent](https://developers.openwaf.dev/api/schemas/#issued-egress-agent).

| Field | Type | Description |
|---|---|---|
| `agent` | [EgressAgent](https://developers.openwaf.dev/api/schemas/#egress-agent) |  |
| `token` | string | Substitute token `OWE_TOKEN_…`; shown only once (only its SHA-256 is stored). |

#### Errors

| Status | Description |
|---|---|
| `403` | The token's role or limits do not allow it (`forbidden`). |
| `404` | Not found, or not visible to the token (`not_found`). |

#### Example

**curl**


```sh
curl -X POST "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/egress/agents/4a2c6e8b-0d1f-4c3e-9b5a-7d9f1b3e5a7c/rotate-token" \
  -H "Authorization: Bearer $OPENWAF_TOKEN"
```

**TypeScript**


```ts
import { OpenWAF } from "./openwaf";

const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token from OPENWAF_TOKEN
const result = await owf.rotateEgressAgentToken({
  agent: "4a2c6e8b-0d1f-4c3e-9b5a-7d9f1b3e5a7c"
});
```

**Python**


```py
from openwaf import OpenWAF

owf = OpenWAF(base_url="https://dash.openwaf.dev")  # token from OPENWAF_TOKEN
result = owf.rotate_egress_agent_token(agent="4a2c6e8b-0d1f-4c3e-9b5a-7d9f1b3e5a7c")
```



```json
{
  "agent": {
    "id": "a5614527-0ce6-43be-ad1d-d012b7394867",
    "name": "example.com",
    "description": "Support assistant",
    "allowed_targets": [
      "openai"
    ],
    "enforce_injection": false,
    "block_dlp": false,
    "disabled": false,
    "token_prefix": "OWE_TOKEN_ab12cd",
    "token_rotated_at": "2026-10-27T09:30:00Z",
    "created_at": "2026-10-27T09:30:00Z",
    "created_by": "token:11111111-2222-4333-8444-555555555555",
    "updated_at": "2026-10-27T09:30:00Z",
    "base_urls": {
      "openrouter": "https://egress.openwaf.dev/v1/agent/support-bot/proxy/openrouter"
    }
  },
  "token": "owf_…"
}
```

## List egress events

```http
GET /v1/orgs/{org}/egress/events
```

Lists the requests blocked by the egress gateway, newest first, with the same filters and shape as [List events](https://developers.openwaf.dev/api/security-events/#list-events). Each block is an event with `action` `block`, `attack_type` `egress`, the code in `rule_name` (`injection_detected`, `data_leak_blocked`, `ssrf_blocked`, `egress_blocked`, `body_too_large`), the target in `host`, the agent name in `user_agent` and the detection ids in `msg`. The request body is never included.

**Required role:** `readonly` or higher. Organization-wide. Needs the egress feature.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |
| `since` | query | string (date-time) | No | RFC 3339; until minus 24 hours by default. |
| `until` | query | string (date-time) | No | RFC 3339, exclusive; now by default. At most 31 days of range. |
| `action` | query | string | No | Repeatable (any of the values, at most 20). One of `block`, `log`, `challenge`, `allow`. |
| `ip` | query | string | No | IPv4 or IPv6 (normalized); repeatable. |
| `host` | query | string | No | Exact name (case-insensitive); repeatable. 1 to 253 characters. |
| `path` | query | string | No | Exact path (1-2048 bytes); repeatable. 1 to 2048 characters. |
| `status` | query | integer | No | HTTP status of the response; repeatable. From 100 to 599. |
| `rule_name` | query | string | No | Exact rule_name (the code of an egress block, e.g. `injection_detected`); repeatable. 1 to 200 characters. |
| `not_action` | query | string | No | Excludes those actions; repeatable. One of `block`, `log`, `challenge`, `allow`. |
| `not_ip` | query | string | No | Excludes those IPs; repeatable. |
| `not_host` | query | string | No | Excludes those names; repeatable. 1 to 253 characters. |
| `not_path` | query | string | No | Excludes those exact paths; repeatable. 1 to 2048 characters. |
| `not_status` | query | integer | No | Excludes those HTTP statuses; repeatable. From 100 to 599. |
| `not_rule_name` | query | string | No | Excludes those rule_name values; repeatable. 1 to 200 characters. |
| `q` | query | string | No | Free text (case-insensitive) in host, path, IP, method, rule_name, attack_type, msg, user agent, country, rule_id and status. At most 200 characters. |
| `limit` | query | integer | No | Maximum number of items. Default `100`. From 1 to 1000. |
| `cursor` | query | string | No | next_cursor of the previous page. |

#### Response

- `200`: Returns an object with the fields below.

| Field | Type | Description |
|---|---|---|
| `items` | array of [EdgeEvent](https://developers.openwaf.dev/api/schemas/#edge-event) |  |
| `next_cursor` | string |  |

#### Errors

| Status | Description |
|---|---|
| `400` | Malformed request (`bad_request`). |
| `403` | The token's role or limits do not allow it (`forbidden`). |
| `503` | Not available right now (`unavailable`); retry later. |

#### Example

**curl**


```sh
curl "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/egress/events?rule_name=injection_detected" \
  -H "Authorization: Bearer $OPENWAF_TOKEN"
```

**TypeScript**


```ts
import { OpenWAF } from "./openwaf";

const owf = new OpenWAF({ baseUrl: "https://dash.openwaf.dev" }); // token from OPENWAF_TOKEN
const result = await owf.listEgressEvents({
  rule_name: "injection_detected"
});
```

**Python**


```py
from openwaf import OpenWAF

owf = OpenWAF(base_url="https://dash.openwaf.dev")  # token from OPENWAF_TOKEN
result = owf.list_egress_events(rule_name="injection_detected")
```



```json
{
  "items": [
    {
      "event_id": "8b3e5f7a-1c2d-4e6f-9a0b-3c5d7e9f1a2b",
      "zone_id": "6f1d2c3b-8a4e-4b7d-9c21-5e3f7a8b9c0d",
      "node_id": "edge-node",
      "ts": "2026-10-27T09:29:58Z",
      "host": "www.example.com",
      "ip": "203.0.113.10",
      "method": "POST",
      "path": "/login",
      "status": 429,
      "action": "block",
      "rule_id": 0,
      "rule_name": "rate_rule:login",
      "attack_type": "rate_limit",
      "msg": "",
      "country_code": "ES",
      "asn": 64500,
      "user_agent": "Mozilla/5.0",
      "tls_fingerprint": "",
      "received_at": "2026-10-27T09:29:59Z",
      "rate_rule": "login"
    }
  ],
  "next_cursor": ""
}
```

## Stream egress events

```http
GET /v1/orgs/{org}/egress/events/stream
```

Streams the egress gateway blocks as Server-Sent Events, with the same frames, resumption and limits as [Stream events](https://developers.openwaf.dev/api/security-events/#stream-events) and the events of [List egress events](https://developers.openwaf.dev/api/egress/#list-egress-events).

**Required role:** `readonly` or higher. Organization-wide. Needs the egress feature.

#### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `org` | path | string (uuid) | Yes | Organization id. Every route checks that it is the token's organization (otherwise `404`). |
| `Last-Event-ID` | header | string | No | `id` of the last event received from a stream; takes precedence over `cursor`. |
| `cursor` | query | string | No | `id` of an event of a previous stream: starts right after it. |
| `action` | query | string | No | Repeatable (any of the values, at most 20). One of `block`, `log`, `challenge`, `allow`. |
| `ip` | query | string | No | IPv4 or IPv6 (normalized); repeatable. |
| `host` | query | string | No | Exact name (case-insensitive); repeatable. 1 to 253 characters. |
| `path` | query | string | No | Exact path (1-2048 bytes); repeatable. 1 to 2048 characters. |
| `status` | query | integer | No | HTTP status of the response; repeatable. From 100 to 599. |
| `rule_name` | query | string | No | Exact rule_name (the code of an egress block, e.g. `injection_detected`); repeatable. 1 to 200 characters. |
| `not_action` | query | string | No | Excludes those actions; repeatable. One of `block`, `log`, `challenge`, `allow`. |
| `not_ip` | query | string | No | Excludes those IPs; repeatable. |
| `not_host` | query | string | No | Excludes those names; repeatable. 1 to 253 characters. |
| `not_path` | query | string | No | Excludes those exact paths; repeatable. 1 to 2048 characters. |
| `not_status` | query | integer | No | Excludes those HTTP statuses; repeatable. From 100 to 599. |
| `not_rule_name` | query | string | No | Excludes those rule_name values; repeatable. 1 to 200 characters. |
| `q` | query | string | No | Free text (case-insensitive) in host, path, IP, method, rule_name, attack_type, msg, user agent, country, rule_id and status. At most 200 characters. |

#### Response

- `200`: Server-Sent Events stream. Body of type `text/event-stream`.

#### Errors

| Status | Description |
|---|---|
| `400` | Malformed request (`bad_request`). |
| `403` | The token's role or limits do not allow it (`forbidden`). |
| `429` | Too many requests (`rate_limited`); wait `Retry-After` seconds. |
| `503` | Not available right now (`unavailable`); retry later. |

#### Example

Not in the SDKs: open the stream with `EventSource` or any Server-Sent Events client.

```sh
curl -N "https://dash.openwaf.dev/v1/orgs/$OPENWAF_ORG/egress/events/stream" \
  -H "Authorization: Bearer $OPENWAF_TOKEN"
```
