Drift API

Read and triage API drift findings, their baselines and evidencing requests, check drift scan health, and generate AI investigation prompts.

This page as Markdown

Drift detection learns what each endpoint normally accepts and returns (its baseline) and raises a finding when that changes, for example a field that disappears from a response, a new required parameter or a new dependency. Detection only observes; it never changes traffic. See API drift for how it works in the app.

Plan: drift scans run for buckets with drift detection turned on (see Update bucket) on plans that include API drift detection. Reading and triaging existing findings keeps working if the plan changes. Permissions: any member, or a user or administrator API token.

Drift is identified per endpoint and method: /v1/orders/{order_id} with GET and with PUT are separate.

The drift finding object

  • sid (string, required): The finding’s identifier (drift_ followed by 27 letters and digits).

  • accountSid (string, required): The account.

  • bucketSid (string, required): The bucket.

  • environmentSid (string | null): The environment.

  • endpoint (string, required): The endpoint, for example /v1/orders/{order_id}.

  • method (string, required): The HTTP method.

  • changeType (string, required): breaking_request, breaking_response, additive, behavioral, dependency, new_endpoint, disappeared_endpoint or response_body_missing.

  • severity (string, required): high, medium or low. Breaking changes are high.

  • status (string, required): open, expected, acknowledged or resolved.

  • classification (string, required): Whether the change is explained (for example by a deploy) or not (unknown).

  • title (string | null): A one-line summary.

  • diff (object): Before and after detail. The shape depends on changeType.

  • baselineSid (string | null): The baseline the change was detected against, and baselineVersion its version.

  • correlatedEventSid (string | null): A deploy event that may explain the change.

  • sampleCount (number, required): Requests sampled for the finding.

  • onsetAt (string | null): When the change first appeared in traffic.

  • detectedAt (string | null): When the scan detected it.

  • createdAt (string | null): When the finding was created.

List drift findings

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

Returns a bucket’s drift findings.

Path parameters

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

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

Query parameters

  • environmentSid (query, string): Only this environment.

  • status (query, string): open, expected, acknowledged or resolved.

  • changeType (query, string): One of the change types above.

  • endpoint (query, string): Only this endpoint, as List endpoints returns it. Up to 500 characters.

  • method (query, string): Only this HTTP method.

  • limit (query, integer, default 250): Findings to return, 1 to 1000.

Response

  • hasMore (boolean, required): Whether more findings match than were returned.

  • records (object[], required): The findings, as drift finding objects.

bash
curl -G https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/buckets/k3m9p2x/driftFindings \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN" \
  --data-urlencode 'status=open' \
  --data-urlencode 'endpoint=/v1/orders/{order_id}'
js
const accountSid = 'acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa';
const params = new URLSearchParams({ status: 'open', endpoint: '/v1/orders/{order_id}' });
const response = await fetch(
  `https://api.apitraffic.io/v1/accounts/${accountSid}/buckets/k3m9p2x/driftFindings?${params}`,
  { headers: { Authorization: `Bearer ${process.env.APITRAFFIC_TOKEN}` } },
);
const { records } = await response.json();
json
{
  "hasMore": false,
  "records": [
    {
      "sid": "drift_2kM4nP6qR8sT1uV3wX5yZ7aB9cD",
      "accountSid": "acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa",
      "bucketSid": "k3m9p2x",
      "environmentSid": "prd7k2",
      "endpoint": "/v1/orders/{order_id}",
      "method": "GET",
      "baselineSid": "aeb_2pQ4rS6tU8vW1xY3zA5bC7dE9fG",
      "baselineVersion": 3,
      "changeType": "breaking_response",
      "severity": "high",
      "status": "open",
      "classification": "unknown",
      "title": "fulfillment.trackingNumber is no longer returned",
      "diff": {},
      "correlatedEventSid": "evt_2tG5yH7uJ9iK1oL3pZ6xC8vB4nM",
      "sampleCount": 214,
      "detectedAt": "2026-10-19T11:15:00.000Z",
      "onsetAt": "2026-10-19T10:02:41.000Z",
      "createdAt": "2026-10-19T11:15:00.000Z"
    }
  ]
}

Get drift finding

GET https://api.apitraffic.io/v1/accounts/{accountSid}/buckets/{bucketSid}/driftFindings/{driftSid}

Returns one finding with a summary of the baseline it was detected against.

Path parameters

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

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

  • driftSid (path, string, required): The finding’s identifier (drift_…).

Response

A drift finding object, plus baseline: a summary of the baseline, or null.

bash
curl https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/buckets/k3m9p2x/driftFindings/drift_2kM4nP6qR8sT1uV3wX5yZ7aB9cD \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN"
js
const accountSid = 'acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa';
const driftSid = 'drift_2kM4nP6qR8sT1uV3wX5yZ7aB9cD';
const response = await fetch(
  `https://api.apitraffic.io/v1/accounts/${accountSid}/buckets/k3m9p2x/driftFindings/${driftSid}`,
  { headers: { Authorization: `Bearer ${process.env.APITRAFFIC_TOKEN}` } },
);
const finding = await response.json();
json
{
  "sid": "drift_2kM4nP6qR8sT1uV3wX5yZ7aB9cD",
  "accountSid": "acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa",
  "bucketSid": "k3m9p2x",
  "environmentSid": "prd7k2",
  "endpoint": "/v1/orders/{order_id}",
  "method": "GET",
  "baselineSid": "aeb_2pQ4rS6tU8vW1xY3zA5bC7dE9fG",
  "baselineVersion": 3,
  "changeType": "breaking_response",
  "severity": "high",
  "status": "open",
  "classification": "unknown",
  "title": "fulfillment.trackingNumber is no longer returned",
  "diff": {},
  "correlatedEventSid": "evt_2tG5yH7uJ9iK1oL3pZ6xC8vB4nM",
  "sampleCount": 214,
  "detectedAt": "2026-10-19T11:15:00.000Z",
  "onsetAt": "2026-10-19T10:02:41.000Z",
  "createdAt": "2026-10-19T11:15:00.000Z",
  "baseline": {}
}

The example shortens diff and baseline.

Update drift finding

PATCH https://api.apitraffic.io/v1/accounts/{accountSid}/buckets/{bucketSid}/driftFindings/{driftSid}

Changes a finding’s triage status. Mark a change you meant to make as expected, one you are looking at as acknowledged, and one that is fixed as resolved.

Path parameters

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

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

  • driftSid (path, string, required): The finding’s identifier.

Body parameters

  • status (body, string, required): open, expected, acknowledged or resolved.

Response

The updated drift finding object.

bash
curl -X PATCH https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/buckets/k3m9p2x/driftFindings/drift_2kM4nP6qR8sT1uV3wX5yZ7aB9cD \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "status": "acknowledged" }'
js
const accountSid = 'acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa';
const driftSid = 'drift_2kM4nP6qR8sT1uV3wX5yZ7aB9cD';
const response = await fetch(
  `https://api.apitraffic.io/v1/accounts/${accountSid}/buckets/k3m9p2x/driftFindings/${driftSid}`,
  {
    method: 'PATCH',
    headers: {
      Authorization: `Bearer ${process.env.APITRAFFIC_TOKEN}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ status: 'acknowledged' }),
  },
);
const finding = await response.json();
json
{
  "sid": "drift_2kM4nP6qR8sT1uV3wX5yZ7aB9cD",
  "accountSid": "acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa",
  "bucketSid": "k3m9p2x",
  "environmentSid": "prd7k2",
  "endpoint": "/v1/orders/{order_id}",
  "method": "GET",
  "baselineSid": "aeb_2pQ4rS6tU8vW1xY3zA5bC7dE9fG",
  "baselineVersion": 3,
  "changeType": "breaking_response",
  "severity": "high",
  "status": "acknowledged",
  "classification": "unknown",
  "title": "fulfillment.trackingNumber is no longer returned",
  "diff": {},
  "correlatedEventSid": "evt_2tG5yH7uJ9iK1oL3pZ6xC8vB4nM",
  "sampleCount": 214,
  "detectedAt": "2026-10-19T11:15:00.000Z",
  "onsetAt": "2026-10-19T10:02:41.000Z",
  "createdAt": "2026-10-19T11:15:00.000Z"
}

List drift finding requests

GET https://api.apitraffic.io/v1/accounts/{accountSid}/buckets/{bucketSid}/driftFindings/{driftSid}/requests

Lists the captured requests that show the change. Open one with Get request.

Path parameters

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

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

  • driftSid (path, string, required): The finding’s identifier.

Response

  • hasMore (boolean, required): Whether more requests exist.

  • records (object[], required): One entry per request: sid, driftSid, requestSid, observedAt and role: exemplar (a typical example), onset (one of the first after the change) or clean (one from before it, for comparison).

bash
curl https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/buckets/k3m9p2x/driftFindings/drift_2kM4nP6qR8sT1uV3wX5yZ7aB9cD/requests \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN"
js
const accountSid = 'acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa';
const driftSid = 'drift_2kM4nP6qR8sT1uV3wX5yZ7aB9cD';
const response = await fetch(
  `https://api.apitraffic.io/v1/accounts/${accountSid}/buckets/k3m9p2x/driftFindings/${driftSid}/requests`,
  { headers: { Authorization: `Bearer ${process.env.APITRAFFIC_TOKEN}` } },
);
const { records } = await response.json();
json
{
  "hasMore": false,
  "records": [
    {
      "sid": "dar_2gH5jK7lM9nP1qR3sT6uV8wX4yZ",
      "driftSid": "drift_2kM4nP6qR8sT1uV3wX5yZ7aB9cD",
      "requestSid": "req_2jK5lM7nP9qR1sT3uV6wX8yZ4aB",
      "role": "onset",
      "observedAt": "2026-10-19T10:02:41.000Z"
    },
    {
      "sid": "dar_2hJ6kL8mN1pQ3rS5tU7vW9xY2zA",
      "driftSid": "drift_2kM4nP6qR8sT1uV3wX5yZ7aB9cD",
      "requestSid": "req_2kL6mN8pQ1rS3tU5vW7xY9zA2bC",
      "role": "clean",
      "observedAt": "2026-10-19T09:58:10.000Z"
    }
  ]
}

Get drift diagnosis

GET https://api.apitraffic.io/v1/accounts/{accountSid}/buckets/{bucketSid}/driftFindings/{driftSid}/diagnosis

Builds a prompt you can paste into an AI coding agent to investigate the change, with the baseline, the requests that show it and the deploys that landed shortly before. The prompt points the agent at the MCP server to fetch the captured requests, rather than including them.

Plan: needs AI diagnoses. Each call counts toward the plan’s monthly AI diagnoses allowance; when it is used up, the API answers 429 with code 2222.

Path parameters

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

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

  • driftSid (path, string, required): The finding’s identifier.

Query parameters

  • environmentSid (query, string): The environment to look for deploys in. Defaults to the finding’s own.

  • lookbackMinutes (query, number, default 180): How far before the change to look for deploys, 1 to 10080 minutes.

Response

  • prompt (string, required): The prompt, ready to paste.

  • requests (object[], required): The requests that show the change, as in List drift finding requests.

  • deploys (object[], required): Deploys found before the change, in the same shape as in Get fix prompt.

  • baseline (object | null): A summary of the baseline.

  • driftSid (string, required): The finding, with its bucketSid, endpoint, method, changeType, severity, classification, onsetAt and detectedAt.

bash
curl https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/buckets/k3m9p2x/driftFindings/drift_2kM4nP6qR8sT1uV3wX5yZ7aB9cD/diagnosis \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN"
js
const accountSid = 'acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa';
const driftSid = 'drift_2kM4nP6qR8sT1uV3wX5yZ7aB9cD';
const response = await fetch(
  `https://api.apitraffic.io/v1/accounts/${accountSid}/buckets/k3m9p2x/driftFindings/${driftSid}/diagnosis`,
  { headers: { Authorization: `Bearer ${process.env.APITRAFFIC_TOKEN}` } },
);
const { prompt } = await response.json();
json
{
  "driftSid": "drift_2kM4nP6qR8sT1uV3wX5yZ7aB9cD",
  "bucketSid": "k3m9p2x",
  "endpoint": "/v1/orders/{order_id}",
  "method": "GET",
  "changeType": "breaking_response",
  "severity": "high",
  "classification": "unknown",
  "onsetAt": "2026-10-19T10:02:41.000Z",
  "detectedAt": "2026-10-19T11:15:00.000Z",
  "baseline": {},
  "requests": [
    {
      "sid": "dar_2gH5jK7lM9nP1qR3sT6uV8wX4yZ",
      "driftSid": "drift_2kM4nP6qR8sT1uV3wX5yZ7aB9cD",
      "requestSid": "req_2jK5lM7nP9qR1sT3uV6wX8yZ4aB",
      "role": "onset",
      "observedAt": "2026-10-19T10:02:41.000Z"
    }
  ],
  "deploys": [],
  "prompt": "The response of GET /v1/orders/{order_id} changed at 2026-10-19T10:02:41Z ..."
}

List drift baselines

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

Returns the learned baselines: what each endpoint and method normally looks like.

Path parameters

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

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

Query parameters

  • environmentSid (query, string): Only this environment.

  • status (query, string): learning (still collecting samples), active (findings are raised against it) or superseded (replaced by a newer version).

  • endpoint (query, string): Only this endpoint.

  • method (query, string): Only this method.

  • limit (query, integer, default 250): Baselines to return, 1 to 1000.

Response

  • hasMore (boolean, required): Whether more baselines match.

  • records (object[], required): One entry per baseline: sid, accountSid, bucketSid, environmentSid, endpoint, method, version, status, schema (the request and response shape), behavior, dependencies, sampleCount, firstSeenAt and lastSeenAt.

bash
curl -G https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/buckets/k3m9p2x/driftBaselines \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN" \
  --data-urlencode 'status=active'
js
const accountSid = 'acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa';
const response = await fetch(
  `https://api.apitraffic.io/v1/accounts/${accountSid}/buckets/k3m9p2x/driftBaselines?status=active`,
  { headers: { Authorization: `Bearer ${process.env.APITRAFFIC_TOKEN}` } },
);
const { records } = await response.json();
json
{
  "hasMore": false,
  "records": [
    {
      "sid": "aeb_2pQ4rS6tU8vW1xY3zA5bC7dE9fG",
      "accountSid": "acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa",
      "bucketSid": "k3m9p2x",
      "environmentSid": "prd7k2",
      "endpoint": "/v1/orders/{order_id}",
      "method": "GET",
      "version": 3,
      "status": "active",
      "schema": {},
      "behavior": {},
      "dependencies": {},
      "sampleCount": 1840,
      "firstSeenAt": "2026-09-30T08:00:00.000Z",
      "lastSeenAt": "2026-10-19T09:58:10.000Z"
    }
  ]
}

Get drift health

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

Explains whether drift detection is running for a bucket and why the finding list looks the way it does: turned off, not yet scanned, failing, no traffic, still learning, watching or drifting.

Path parameters

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

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

Query parameters

  • environmentSid (query, string): Only this environment.

Response

  • state (string, required): disabled, never_scanned, failing, no_traffic, learning, watching or drifting.

  • summary (string, required): A one-line explanation of state, with more in detail.

  • lastRunAt (string | null): When the last scan ran, and nextRunAt when the next one is due. scanIntervalMs is the time between scans.

  • lastRun (object | null): The last scan run, and lastSuccessfulRun the last one that succeeded.

  • baselines (object, required): Baseline counts: total, active and learning.

  • openAlertCount (number, required): Open findings.

  • failedScopes (number, required): Scan scopes (bucket and environment) whose last scan failed.

  • totals (object, required): Totals across recent runs.

  • recentRuns (object[], required): Recent scan runs, newest first.

bash
curl https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/buckets/k3m9p2x/driftHealth \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN"
js
const accountSid = 'acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa';
const response = await fetch(`https://api.apitraffic.io/v1/accounts/${accountSid}/buckets/k3m9p2x/driftHealth`, {
  headers: { Authorization: `Bearer ${process.env.APITRAFFIC_TOKEN}` },
});
const { state, summary } = await response.json();
json
{
  "state": "drifting",
  "summary": "1 open finding on 15 watched endpoints.",
  "detail": null,
  "lastRunAt": "2026-10-20T11:15:00.000Z",
  "nextRunAt": "2026-10-20T12:15:00.000Z",
  "scanIntervalMs": 3600000,
  "lastRun": null,
  "lastSuccessfulRun": null,
  "totals": {},
  "baselines": { "total": 15, "active": 14, "learning": 1 },
  "openAlertCount": 1,
  "failedScopes": 0,
  "recentRuns": []
}

The example leaves out the run details; see List drift scan runs for their fields.

List drift scan runs

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

Returns recent drift scans, newest first, with what each one looked at.

Path parameters

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

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

Query parameters

  • environmentSid (query, string): Only this environment.

  • status (query, string): ok, no_traffic or failed.

  • limit (query, integer, default 50): Runs to return, 1 to 200.

Response

  • hasMore (boolean, required): Whether more runs exist.

  • records (object[], required): One entry per run.

run

  • sid (string): Run identifier.

  • environmentSid (string | null): The environment scanned.

  • status (string): ok, no_traffic or failed; errorMessage says why it failed.

  • windowFrom (string | null): Start of the traffic examined, and windowTo its end.

  • endpointsDiscovered (number): Endpoints found in the window.

  • endpointsProcessed (number): Endpoints sampled.

  • samplesCollected (number): Requests sampled.

  • endpointsDiffed (number): Endpoints compared against an established baseline.

  • baselinesWritten (number): Baselines created or updated. baselinesActive and baselinesLearning count them by status.

  • findingsWritten (number): Findings raised.

  • startedAt (string | null): When the run started, finishedAt when it ended, and durationMs how long it took.

bash
curl "https://api.apitraffic.io/v1/accounts/acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa/buckets/k3m9p2x/driftScanRuns?limit=5" \
  -H "Authorization: Bearer $APITRAFFIC_TOKEN"
js
const accountSid = 'acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa';
const response = await fetch(
  `https://api.apitraffic.io/v1/accounts/${accountSid}/buckets/k3m9p2x/driftScanRuns?limit=5`,
  { headers: { Authorization: `Bearer ${process.env.APITRAFFIC_TOKEN}` } },
);
const { records } = await response.json();
const failed = records.filter((run) => run.status === 'failed');
json
{
  "hasMore": true,
  "records": [
    {
      "sid": "dscan_2mN5pQ7rS9tU1vW3xY6zA8bC4dE",
      "accountSid": "acc_2mXq7RbT4kPz9WvN3cHd8LsYfQa",
      "bucketSid": "k3m9p2x",
      "environmentSid": "prd7k2",
      "status": "ok",
      "errorMessage": null,
      "windowFrom": "2026-10-20T10:15:00.000Z",
      "windowTo": "2026-10-20T11:15:00.000Z",
      "endpointsDiscovered": 15,
      "endpointsProcessed": 15,
      "samplesCollected": 412,
      "endpointsDiffed": 14,
      "baselinesWritten": 2,
      "baselinesActive": 14,
      "baselinesLearning": 1,
      "findingsWritten": 0,
      "startedAt": "2026-10-20T11:15:00.000Z",
      "finishedAt": "2026-10-20T11:15:09.000Z",
      "durationMs": 9120
    }
  ]
}

Errors

Status Code Meaning
400 1000 A parameter is invalid, for example a driftSid in the wrong format or an unknown status.
403 2221 The plan does not include AI diagnoses (diagnosis only).
403 2509 Changing a finding on the read-only sample bucket.
404 4000 No finding with that sid in this bucket.
429 2222 The monthly AI diagnoses allowance is used up.