# Outbound destinations API

> Review the hosts your app calls out to, approve or flag them, manage approve and flag rules, turn destination watch on per bucket and choose which environments are production.

Source: https://dev.apitraffic.io/docs/api-reference/destinations

Destination watch keeps a list of every host each bucket's app calls, and alerts the first time it calls a new one. See [Watch for new outbound destinations](https://dev.apitraffic.io/docs/destinations) for how it works in the app.

**Plan:** needs a plan that includes **Outbound destination watch**. Reading destinations, rules, watch state and environments keeps working if the plan changes. **Permissions:** any member, or a `user` or `administrator` API token, can read and review destinations. Rules, turning watch on or off, pruning and the production marker need an owner or admin, or an `administrator` API token.

Destinations are kept per bucket: the same host called from two buckets is two destinations. Hosts are canonical: lowercase, internationalized names in punycode, IPv6 addresses in brackets, no port.

## The destination object

- **sid (string, required)**:
  The destination's identifier (`dst_` followed by 27 letters and digits).

- **bucketSid (string, required)**:
  The bucket that calls it.

- **host (string, required)**:
  The canonical hostname.

- **domain (string, required)**:
  The registrable domain, from the ICANN section of the Public Suffix List. For an IP address, the address.

- **sharedSuffix (string | null)**:
  The shared-hosting suffix the host sits under (for example `herokuapp.com`), where anyone can create hosts. An approve wildcard never covers it.

- **kind (string, required)**:
  `name`, `ipv4`, `ipv6`, `localhost`, `private` or `metadata`.

- **status (string, required)**:
  `pending` (in the review queue), `approved`, `flagged` or `baselined` (approved by the import that ran when watch was turned on).

- **ports (integer[], required)**:
  Non-default ports seen, up to 16.

- **portsOverflow (boolean, required)**:
  More than 16 non-default ports were seen.

- **sources (string[], required)**:
  Where the host was learned from: `sdk` (outbound records) and `span` (`http.out` spans).

- **environments (object[], required)**:
  Live sightings, one per environment: `environmentSid`, `name`, `isProduction`, `firstSeenAt` and `lastSeenAt`.

- **historyEnvironments (object[], required)**:
  The same, for sightings found by the import that ran when watch was turned on.

- **firstSeenAt (string | null)**:
  When the host was first called (ISO 8601).

- **lastSeenAt (string | null)**:
  When it was last called.

- **firstRequestSid (string | null)**:
  The request that first called it.

- **firstTrigger (object | null)**:
  The inbound route whose handler made the first call (`inboundMethod`, `inboundEndpoint`) when the call was seen inside a request; `{"history": true}` for a host found by the enablement import, `{"recovered": true}` for one recovered from stored traffic, and `null` when it isn't known (a host first seen on its own outbound record).

- **correlatedEventSid (string | null)**:
  The deploy event in the hour before the first call, if any.

- **risk (object, required)**:
  `reasons`: any of `ip_literal`, `ip_encoding`, `metadata_endpoint`, `non_ascii`, `non_standard_port` and `flag_rule`. A host with a reason is never approved by a rule or the import. `notes`: details about how the host was read.

- **callsTotal (integer, required)**:
  Calls seen so far. Approximate.

- **alertState (object, required)**:
  The host's alerts, one for production (`prod`) and one for every other environment (`preprod`): each a `state` (`firing` or `resolved`) and the time `at`.

- **alertDeferred (boolean, required)**:
  The host's alert is waiting for the import that runs when watch is turned on.

- **reviewedBy (string | null)**:
  Who last reviewed it.

- **reviewedAt (string | null)**:
  When.

- **reviewNote (string | null)**:
  The note left with the last review.

- **flaggedAt (string | null)**:
  When it was flagged.

- **flaggedByRuleSid (string | null)**:
  The flag rule that flagged it.

- **approvedByRuleSid (string | null)**:
  The approve rule that approved it.

- **createdAt (string | null)**:
  When it was added.

## List destinations

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/destinations`

Lists destinations, newest first. `status=pending,flagged` is the review queue.

### Path parameters

- **accountSid (path, string, required)**:
  The account identifier.

### Query parameters

- **bucketSid (query, string)**:
  Only this bucket.

- **environmentSid (query, string)**:
  Only hosts this environment called.

- **status (query, string)**:
  Comma separated: `pending`, `approved`, `flagged`, `baselined`.

- **kind (query, string)**:
  `name`, `ipv4`, `ipv6`, `localhost`, `private` or `metadata`.

- **domain (query, string)**:
  A registrable domain or shared suffix.

- **q (query, string)**:
  Part of the host.

- **risk (query, string)**:
  Only hosts with this risk reason.

- **limit (query, integer, default 100)**:
  1 to 500.

- **cursor (query, string)**:
  `nextCursor` from the previous page.

### Response

`records`, a list of [destination objects](#the-destination-object), `hasMore` and `nextCursor`.

```bash cURL
curl "https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/destinations?bucketSid=k3m9p2x&status=pending,flagged" \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN"
```

```json 200
{
  "hasMore": false,
  "nextCursor": null,
  "records": [
    {
      "sid": "dst_2kM4nP6qR8sT1uV3wX5yZ7aB9cD",
      "bucketSid": "k3m9p2x",
      "host": "telemetry.leftpad-analytics.io",
      "domain": "leftpad-analytics.io",
      "sharedSuffix": null,
      "kind": "name",
      "status": "pending",
      "ports": [],
      "portsOverflow": false,
      "sources": ["sdk"],
      "environments": [
        { "environmentSid": "env_2pQ7rS9tU1vW3xY5zA7bC9dE1fG", "name": "production", "isProduction": true,
          "firstSeenAt": "2026-10-29T10:02:11.000Z", "lastSeenAt": "2026-10-29T11:40:03.000Z" }
      ],
      "historyEnvironments": [],
      "firstSeenAt": "2026-10-29T10:02:11.000Z",
      "lastSeenAt": "2026-10-29T11:40:03.000Z",
      "firstRequestSid": "req_2nB5cD7eF9gH1jK3lM5nP7qR9sT",
      "firstTrigger": { "inboundMethod": "POST", "inboundEndpoint": "/v1/checkout" },
      "correlatedEventSid": "evt_2rT6uV8wX1yZ3aB5cD7eF9gH1jK",
      "risk": { "reasons": [], "notes": [] },
      "callsTotal": 184,
      "alertState": { "prod": { "state": "firing", "at": "2026-10-29T10:02:26.000Z" } },
      "alertDeferred": false,
      "reviewedBy": null,
      "reviewedAt": null,
      "reviewNote": null,
      "flaggedAt": null,
      "flaggedByRuleSid": null,
      "approvedByRuleSid": null,
      "createdAt": "2026-10-29T10:02:26.000Z"
    }
  ]
}
```

## Get destination

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/destinations/{destinationSid}`

### Path parameters

- **accountSid (path, string, required)**:
  The account identifier.

- **destinationSid (path, string, required)**:
  The destination's identifier.

### Response

The [destination object](#the-destination-object), with `history`: each review, rule application and automatic change (`action`, `actor`, `reason`, `note`, `at`), newest first, up to 100.

```bash cURL
curl "https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/destinations/dst_2kM4nP6qR8sT1uV3wX5yZ7aB9cD" \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN"
```

## Review destination

`PATCH https://api.apitraffic.io/v1/accounts/{accountSid}/destinations/{destinationSid}`

Approves, flags or reopens one destination. Approving resolves its alerts. Flagging alerts at critical severity until the host has gone 24 hours without a call.

### Path parameters

- **accountSid (path, string, required)**:
  The account identifier.

- **destinationSid (path, string, required)**:
  The destination's identifier.

### Body parameters

- **status (body, string, required)**:
  `approved`, `flagged` or `pending` (reopen).

- **note (body, string)**:
  Up to 500 characters. Required to flag.

### Response

The updated [destination object](#the-destination-object). Approving a host a flag rule flagged needs an owner or admin; anyone else gets `403`.

```bash cURL
curl -X PATCH "https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/destinations/dst_2kM4nP6qR8sT1uV3wX5yZ7aB9cD" \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "status": "flagged", "note": "Not a service we use" }'
```

## Review destinations in bulk

`POST https://api.apitraffic.io/v1/accounts/{accountSid}/destinations/review`

The same review for up to 500 destinations at once. All or nothing: if one can't be changed, none are.

### Path parameters

- **accountSid (path, string, required)**:
  The account identifier.

### Body parameters

- **sids (body, string[], required)**:
  1 to 500 destination identifiers.

- **status (body, string, required)**:
  `approved`, `flagged` or `pending`.

- **note (body, string)**:
  Required to flag.

### Response

`records`, the updated [destination objects](#the-destination-object).

```bash cURL
curl -X POST "https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/destinations/review" \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "sids": ["dst_2kM4nP6qR8sT1uV3wX5yZ7aB9cD"], "status": "approved" }'
```

## Prune destinations

`POST https://api.apitraffic.io/v1/accounts/{accountSid}/destinations/prune`

Deletes destinations that are no longer called, to make room under the limits. Approved and baselined destinations by default. Pending ones only after 30 days without a call, and only with a note. Flagged destinations are never pruned. A pruned host that is called again is new again.

**Permissions:** owner or admin, or an `administrator` API token.

### Path parameters

- **accountSid (path, string, required)**:
  The account identifier.

### Body parameters

- **bucketSid (body, string)**:
  Only this bucket.

- **sids (body, string[])**:
  Only these destinations (up to 500).

- **statuses (body, string[])**:
  Any of `approved`, `baselined` and `pending`.

- **notSeenForDays (body, integer)**:
  Only destinations not called for this many days. Required unless `sids` is given, and at least 30 to prune pending destinations.

- **note (body, string)**:
  Required when pruning pending destinations.

### Response

`deleted`, how many destinations were deleted (at most 500 per call), and `hasMore`: when `true`, more match, so call again.

```bash cURL
curl -X POST "https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/destinations/prune" \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "bucketSid": "k3m9p2x", "notSeenForDays": 90 }'
```

```json 200
{ "deleted": 12, "hasMore": false }
```

## The rule object

- **sid (string, required)**:
  The rule's identifier (`dsr_` followed by 27 letters and digits).

- **pattern (string, required)**:
  An exact host, or `*.domain` for a domain and every name under it.

- **effect (string, required)**:
  `approve` or `flag`. Flag beats approve.

- **bucketSids (string[] | null)**:
  Only these buckets; `null` means every bucket.

- **note (string | null)**:
  Why the rule exists.

- **createdBy (string | null)**:
  Who created it.

- **createdAt (string | null)**:
  When.

- **updatedAt (string | null)**:
  When it last changed.

- **applied (integer)**:
  On create and update only: how many existing destinations the save changed.

## List rules

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/destinationRules`

### Path parameters

- **accountSid (path, string, required)**:
  The account identifier.

### Response

`records`, a list of [rule objects](#the-rule-object).

```bash cURL
curl "https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/destinationRules" \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN"
```

## Preview rule

`POST https://api.apitraffic.io/v1/accounts/{accountSid}/destinationRules/preview`

Shows which current destinations a rule would change, without saving it.

### Path parameters

- **accountSid (path, string, required)**:
  The account identifier.

### Body parameters

The same as [Create rule](#create-rule).

### Response

`pattern` (as it would be saved), `matching` (destinations the pattern matches), `changing` (those saving it would change) and `sample`, up to 50 of them (`sid`, `host`, `status`).

```bash cURL
curl -X POST "https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/destinationRules/preview" \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "pattern": "*.stripe.com", "effect": "approve" }'
```

```json 200
{
  "pattern": "*.stripe.com",
  "matching": 3,
  "changing": 2,
  "sample": [
    { "sid": "dst_2kM4nP6qR8sT1uV3wX5yZ7aB9cD", "host": "api.stripe.com", "status": "pending" }
  ]
}
```

## Create rule

`POST https://api.apitraffic.io/v1/accounts/{accountSid}/destinationRules`

Creates a rule and applies it to existing destinations straight away: a flag rule flags every matching destination; an approve rule approves matching pending ones without a risk reason.

**Permissions:** owner or admin, or an `administrator` API token.

### Path parameters

- **accountSid (path, string, required)**:
  The account identifier.

### Body parameters

- **pattern (body, string, required)**:
  An exact host (`api.stripe.com`) or `*.domain` (`*.stripe.com`). An approve wildcard over a shared-hosting suffix (`*.herokuapp.com`) or a public suffix (`*.com`) is refused with `400`.

- **effect (body, string, required)**:
  `approve` or `flag`.

- **bucketSids (body, string[])**:
  Only these buckets (up to 200). Leave out for every bucket.

- **note (body, string)**:
  Up to 500 characters.

### Response

The [rule object](#the-rule-object), with `applied`.

```bash cURL
curl -X POST "https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/destinationRules" \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "pattern": "*.stripe.com", "effect": "approve", "note": "Payments provider" }'
```

```json 200
{
  "sid": "dsr_2kM4nP6qR8sT1uV3wX5yZ7aB9cE",
  "pattern": "*.stripe.com",
  "effect": "approve",
  "bucketSids": null,
  "note": "Payments provider",
  "createdBy": "usr_2aB4cD6eF8gH1jK3lM5nP7qR9sT",
  "createdAt": "2026-10-29T12:00:00.000Z",
  "updatedAt": "2026-10-29T12:00:00.000Z",
  "applied": 2
}
```

## Update rule

`PATCH https://api.apitraffic.io/v1/accounts/{accountSid}/destinationRules/{ruleSid}`

Changes any of a rule's fields. When the pattern, effect or buckets change, the rule is applied again: hosts it no longer covers lose the rule's flag (they stay flagged, and members can review them again), and hosts it still covers keep it, along with any admin's approval over it. Changing only the note applies nothing.

**Permissions:** owner or admin, or an `administrator` API token.

### Path parameters

- **accountSid (path, string, required)**:
  The account identifier.

- **ruleSid (path, string, required)**:
  The rule's identifier.

### Body parameters

Any of `pattern`, `effect`, `bucketSids` and `note`, as in [Create rule](#create-rule).

### Response

The [rule object](#the-rule-object), with `applied`.

```bash cURL
curl -X PATCH "https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/destinationRules/dsr_2kM4nP6qR8sT1uV3wX5yZ7aB9cE" \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "note": "Payments and billing" }'
```

## Delete rule

`DELETE https://api.apitraffic.io/v1/accounts/{accountSid}/destinationRules/{ruleSid}`

Destinations a deleted flag rule flagged stay flagged, and members can review them again.

**Permissions:** owner or admin, or an `administrator` API token.

### Path parameters

- **accountSid (path, string, required)**:
  The account identifier.

- **ruleSid (path, string, required)**:
  The rule's identifier.

### Response

`sid` and `deleted: true`.

```bash cURL
curl -X DELETE "https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/destinationRules/dsr_2kM4nP6qR8sT1uV3wX5yZ7aB9cE" \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN"
```

## The watch object

- **bucketSid (string, required)**:
  The bucket.

- **state (string, required)**:
  `off`, `backfilling` (importing the last 30 days of hosts), `releasing` (finishing the import) or `watching`.

- **enabled (boolean, required)**:
  Whether watch is on.

- **startedAt (string | null)**:
  When watch was last turned on.

- **backfillMode (string, required)**:
  `baseline` or `review_all`: what the import does with the hosts it finds.

- **reconciledAt (string | null)**:
  When stored history was last checked for hosts live capture missed.

## Get bucket watch

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/buckets/{bucketSid}/destinationWatch`

### Path parameters

- **accountSid (path, string, required)**:
  The account identifier.

- **bucketSid (path, string, required)**:
  The bucket identifier.

### Response

The [watch object](#the-watch-object).

```bash cURL
curl "https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/buckets/k3m9p2x/destinationWatch" \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN"
```

## Update bucket watch

`PATCH https://api.apitraffic.io/v1/accounts/{accountSid}/buckets/{bucketSid}/destinationWatch`

Turns watch on or off for a bucket. Turning it on imports the last 30 days of hosts first, so an existing app doesn't start with every host it calls alerting as new. Alerts for new hosts wait for the import, at most 30 minutes; risky hosts alert straight away. Turning it off resolves the bucket's destination alerts and keeps its destinations.

**Permissions:** owner or admin, or an `administrator` API token.

### Path parameters

- **accountSid (path, string, required)**:
  The account identifier.

- **bucketSid (path, string, required)**:
  The bucket identifier.

### Body parameters

- **enabled (body, boolean, required)**:
  `true` to turn watch on, `false` to turn it off.

- **backfillMode (body, string, default baseline)**:
  `baseline` approves the imported hosts (apart from risky ones); `review_all` puts every one in the review queue.

### Response

The [watch object](#the-watch-object).

```bash cURL
curl -X PATCH "https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/buckets/k3m9p2x/destinationWatch" \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "enabled": true, "backfillMode": "baseline" }'
```

```json 200
{
  "bucketSid": "k3m9p2x",
  "state": "backfilling",
  "enabled": true,
  "startedAt": "2026-10-29T12:05:00.000Z",
  "backfillMode": "baseline",
  "reconciledAt": null
}
```

## List environments

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/destinations/environments`

Lists the account's environments and whether each counts as production for destination alerts. A host first called from production alerts at a higher severity.

### Path parameters

- **accountSid (path, string, required)**:
  The account identifier.

### Response

`records`: each `environmentSid`, `name`, `isProduction` and `source` (`inferred` from the environment's name, or `manual`).

```bash cURL
curl "https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/destinations/environments" \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN"
```

## Mark environment as production

`PATCH https://api.apitraffic.io/v1/accounts/{accountSid}/destinations/environments/{environmentSid}`

A choice made here is kept, and never replaced by inference from the environment's name.

**Permissions:** owner or admin, or an `administrator` API token.

### Path parameters

- **accountSid (path, string, required)**:
  The account identifier.

- **environmentSid (path, string, required)**:
  The environment identifier.

### Body parameters

- **isProduction (body, boolean, required)**:
  Whether the environment is production.

### Response

The environment's record, with `source: "manual"`.

```bash cURL
curl -X PATCH "https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/destinations/environments/env_2pQ7rS9tU1vW3xY5zA7bC9dE1fG" \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "isProduction": true }'
```

## Events

Every review, rule change, watch change and production marker is recorded in the account's activity and sent to webhooks as a `security.destination_*` event. See the [webhook event reference](https://dev.apitraffic.io/docs/webhooks/reference).
