API reference

Activity

Read and export the workspace activity log: every configuration change, who or what made it, and the values before and after.

The Activity API reads the workspace's activity log: who changed what, when, from where, and from what value to what value. It is what you reach for when a campaign stopped routing overnight, when a buyer disputes a cap, or when an integration started writing things nobody asked for.

It is read-only by construction. Entries are written by the platform as changes happen; the table itself refuses updates, and deletes outside the retention job. There is no route here that writes one, because there is no way to write one.

A console surface

All three endpoints are the console's own, under /api/tracking, called with the session token of a signed-in owner or admin. No API key can read the log — including the key whose own actions are in it.

Base URL
https://api.buy3.io/api/tracking/activity
  • Every request may carry an optional agencyId (a UUID, in the query string or the body). Leave it out when you administer one workspace.
  • All three are reads, so a workspace whose subscription has lapsed can still read and export its own history.
  • Entries are newest first, and the list and the export take exactly the same filters — so exporting what is on screen is the same query string with a different path.

An entry

FieldTypeMeaning
idstringA large integer, sent as a string.
atISO 8601When it happened.
kindstringThe noun the entry is about — see Kinds.
actionstringA sentence in the past tense: "changed the routing plan of Medicare — Inbound".
severitystringlow, medium or high.
actorstringA person's name, System, or an API key's prefix.
actorKindstringuser, api_key, publisher_member, system or staff.
actorRolestringThe seat the actor held.
actorUserIduuid | nullThe person. null for a staff actor.
apiKeyIduuid | nullThe key, when a key did it.
targetstringThe label of the thing that changed, falling back to its id, then to an empty string.
targetType, targetIdstring | nullWhat changed, by type and id.
changesobject | null{ field: [before, after] }. A secret reads ["•••", "•••"] — that it changed, never to what.
fieldsstring[]The field names touched or read. Never values.
metadataobject | nullExtra facts about the action. null for a staff actor.
ipstring | nullWhere the request came from. null for a staff actor.
requestIdstring | nullThe id of the request that made the change — the same id in that reply's error body, and on the matching row of an API key's request log.

Kinds

Every entry is filed under the noun it is about, so "everything that happened to my targets" is one filter. A status change is filed under the thing whose status changed, with changes.status on it, rather than under some generic kind of its own.

kindWritten when
workspaceThe workspace's own settings changed, such as its time zone.
campaignA campaign was created, edited or had its status changed; a tag filter was added, changed or removed.
routingA campaign's routing plan was saved — from the console or through the REST API.
buyerA buyer was created, edited or had its status changed.
targetA target was created, edited or had its status changed; its cap counters were reset; it was tested.
publisherA lane was opened onto a campaign, or its payout terms changed.
keyA publisher's routing key was issued or revoked with a lane, the single-step ping URL was switched on or off, or a key was widened onto the auction surface.
numberA number was bought, assigned, moved, relabelled, or a release was requested.
poolA number pool was created, edited, paused, resumed or deleted.
blocked_callerA caller was blocked or unblocked.
callA conversion was marked, tags were edited, or the books were adjusted — by a person or by an API key.
webhookAn endpoint was created, edited, paused, resumed or deleted; a test was sent; deliveries were replayed; a secret was rotated. Also the dispatcher marking an endpoint degraded, with system as the actor.
api_keyA key was created, edited, rotated or revoked.
exportA CSV left the building: calls, a report, pings, or this log.
GET /activity/summary returns this list as trackingKinds. A workspace's log can also hold kinds written by other parts of the platform about the same account — billing, wallet, publisher-portal seats — so build a filter menu from trackingKinds first and then add whatever kinds counts.

What is never in an entry

  • A secret's value. A rotated signing secret or key is recorded as ["•••", "•••"].
  • Field values you did not change. fields is names only.
  • The platform's own side of an action. Internal metadata — margins, provider costs, staff notes, risk and fraud figures — is stripped on the way out, by key, at any depth.
  • Another workspace's rows. Every read is pinned to your workspace before any filter is applied.

Endpoints

List activity

GET/api/tracking/activity

The workspace's entries, newest first, in the standard list envelope. Changes nothing and writes nothing.

Console session. Called by the console with the signed-in user's session. Use the REST API with an API key for your own integrations.

Query parameters

NameTypeDescription
kindOptionalstringThe kind of thing the entry is about — see Kinds. A kind this workspace has no entries under is not an error: it simply matches nothing.a lowercase slug such as target or api_key · up to 40 characters
severityOptionalstringHow much the change mattered.low, medium or high
actorKindOptionalstringWhat kind of actor did it.staff, user, publisher_member, api_key or system
actorUserIdOptionaluuidOnly entries by this person.
apiKeyIdOptionaluuidOnly entries by this API key. This is how you answer "what has that integration changed".
targetTypeOptionalstringOnly entries about this type of record, such as campaign, rtb_target, phone_number, webhook_endpoint or api_key.up to 60 characters
targetIdOptionalstringOnly entries about one record. With targetType, this is the history of a single campaign or target.up to 120 characters
qOptionalstringMatches part of the action sentence. % and _ are ordinary characters here, not wildcards.up to 200 characters
fromOptionaldateOnly entries at or after this moment.
toOptionaldateOnly entries at or before this moment.
pageOptionalintegerThe page to return.from 1, default 1
pageSizeOptionalintegerRows per page. A larger value is clamped, not refused.1–200 · default 25

Example request

curl "https://api.buy3.io/api/tracking/activity?kind=target&severity=high&from=2026-09-13T00:00:00Z" \
  -H "Authorization: Bearer $BUY3_SESSION_TOKEN"

Responses

  • 200One page of entries.
{
  "data": [
    {
      "id": "8841207",
      "at": "2026-09-20T14:02:51.000Z",
      "kind": "target",
      "action": "updated the target Acme Health — Dallas floor",
      "severity": "medium",
      "actor": "Dana Okafor",
      "actorKind": "user",
      "actorRole": "admin",
      "actorUserId": "5e4d3c2b-1a09-4887-b6c5-d4e3f2a1b0c9",
      "apiKeyId": null,
      "target": "Acme Health — Dallas floor",
      "targetType": "rtb_target",
      "targetId": "a9b8c7d6-e5f4-4a3b-9c2d-1e0f9a8b7c6d",
      "changes": {
        "dailyCap": [
          50,
          80
        ],
        "status": [
          "paused",
          "active"
        ]
      },
      "fields": [
        "dailyCap",
        "status"
      ],
      "metadata": null,
      "ip": "203.0.113.24",
      "requestId": "5d1c0d2e-8a4f-4c0b-9e1d-2f3a4b5c6d7e"
    },
    {
      "id": "8841206",
      "at": "2026-09-20T13:58:02.000Z",
      "kind": "call",
      "action": "marked call CA-482137 converted",
      "severity": "medium",
      "actor": "b3_live_Qx7m",
      "actorKind": "api_key",
      "actorRole": "api_key",
      "actorUserId": null,
      "apiKeyId": "9b2f4c1d-3e5a-4f6b-8c7d-0a1b2c3d4e5f",
      "target": "CA-482137",
      "targetType": "call",
      "targetId": "0b9f6c1e-52a4-4a0e-9f0a-3d1c7e8b2a11",
      "changes": {
        "converted": [
          false,
          true
        ],
        "revenueCents": [
          0,
          5500
        ]
      },
      "fields": [
        "converted",
        "revenueCents"
      ],
      "metadata": {
        "source": "api"
      },
      "ip": "203.0.113.24",
      "requestId": "1f0a9b8c-7d6e-4f50-a1b2-c3d4e5f60718"
    }
  ],
  "page": 1,
  "pageSize": 25,
  "total": 2,
  "totalPages": 1
}

Errors

StatusCodeWhen
400validation_errorkind is not a lowercase slug, severity or actorKind is not one of the allowed words, an id filter is not a UUID, or from or to is not a date. details names the field.
401unauthorizedNo session token, or one that has expired.
402plan_upgrade_requiredThe workspace's plan does not include call tracking. details.feature is callTracking.
403forbiddenYou named no workspace and hold no owner or admin seat on any.
404not_foundAn agencyId that is not a workspace you administer answers the same 404.

Summarise activity

GET/api/tracking/activity/summary

Counts over a window, for the tiles and the filter menus above the list: how many entries, how many carried a before and after, and the breakdown by severity, kind and actor. It also returns the vocabularies a menu can offer before the window has any entries in it at all. Changes nothing.

Console session. Called by the console with the signed-in user's session. Use the REST API with an API key for your own integrations.

Query parameters

NameTypeDescription
daysOptionalintegerHow many days back to count.1–365 · default 7

Example request

curl "https://api.buy3.io/api/tracking/activity/summary?days=30" \
  -H "Authorization: Bearer $BUY3_SESSION_TOKEN"

Responses

  • 200kinds and actorKinds say what the workspace has in the window; trackingKinds, knownKinds and knownActorKinds say what a menu may offer. actors holds at most 50, busiest first.
{
  "days": 7,
  "since": "2026-09-13T14:22:09.412Z",
  "total": 412,
  "configChanges": 188,
  "severity": {
    "low": 210,
    "medium": 172,
    "high": 30
  },
  "kinds": {
    "target": 96,
    "campaign": 54,
    "call": 180,
    "webhook": 42,
    "api_key": 6,
    "export": 34
  },
  "actorKinds": {
    "user": 318,
    "api_key": 82,
    "system": 12
  },
  "actors": [
    {
      "name": "Dana Okafor",
      "kind": "user",
      "role": "admin",
      "entries": 204
    },
    {
      "name": "b3_live_Qx7m",
      "kind": "api_key",
      "role": "api_key",
      "entries": 82
    }
  ],
  "trackingKinds": [
    "workspace",
    "campaign",
    "routing",
    "buyer",
    "target",
    "publisher",
    "key",
    "number",
    "pool",
    "blocked_caller",
    "call",
    "webhook",
    "api_key",
    "export"
  ],
  "knownKinds": [
    "billing",
    "wallet",
    "member",
    "campaign",
    "target",
    "call",
    "webhook",
    "api_key",
    "export"
  ],
  "knownActorKinds": [
    "staff",
    "user",
    "publisher_member",
    "api_key",
    "system"
  ]
}

Errors

StatusCodeWhen
400validation_errordays is not an integer between 1 and 365.
401unauthorizedNo session token, or one that has expired.
402plan_upgrade_requiredThe workspace's plan does not include call tracking. details.feature is callTracking.
403forbiddenYou named no workspace and hold no owner or admin seat on any.
404not_foundAn agencyId that is not a workspace you administer answers the same 404.

Export activity as CSV

GET/api/tracking/activity/export.csv

The filtered log as a file — the same filters as the list, so this is "export what I am looking at". It writes its own entry before it answers (export, medium severity) with the filter that produced it, so the trail says what left the building and not merely that something did. That entry is the only write on this page. It is still a read for gating purposes, so a lapsed workspace can export its history.

Console session. Called by the console with the signed-in user's session. Use the REST API with an API key for your own integrations.

Query parameters

NameTypeDescription
kindOptionalstringThe kind of thing the entry is about — see Kinds. A kind this workspace has no entries under is not an error: it simply matches nothing.a lowercase slug such as target or api_key · up to 40 characters
severityOptionalstringHow much the change mattered.low, medium or high
actorKindOptionalstringWhat kind of actor did it.staff, user, publisher_member, api_key or system
actorUserIdOptionaluuidOnly entries by this person.
apiKeyIdOptionaluuidOnly entries by this API key. This is how you answer "what has that integration changed".
targetTypeOptionalstringOnly entries about this type of record, such as campaign, rtb_target, phone_number, webhook_endpoint or api_key.up to 60 characters
targetIdOptionalstringOnly entries about one record. With targetType, this is the history of a single campaign or target.up to 120 characters
qOptionalstringMatches part of the action sentence. % and _ are ordinary characters here, not wildcards.up to 200 characters
fromOptionaldateOnly entries at or after this moment.
toOptionaldateOnly entries at or before this moment.
limitOptionalintegerThe most entries to write. Narrow the filter rather than raising this if a file is cut off.1–50000 · default 10000

Example request

curl "https://api.buy3.io/api/tracking/activity/export.csv?kind=target&from=2026-03-01T00:00:00Z&limit=50000" \
  -H "Authorization: Bearer $BUY3_SESSION_TOKEN" \
  -o activity.csv

Responses

  • 200Content-Type: text/csv; charset=utf-8, sent as an attachment named activity-<YYYY-MM-DD>.csv. UTF-8 with a byte-order mark, RFC 4180 quoting, and a leading apostrophe on any cell a spreadsheet would read as a formula — the rules are in The file. changes is flattened into one readable cell, field: before → after; …, and fields is a space-separated list.
id,at,severity,kind,actor,actorKind,action,targetType,target,targetId,changes,fields,ip,requestId
8841207,2026-09-20T14:02:51.000Z,medium,target,Dana Okafor,user,updated the target Acme Health — Dallas floor,rtb_target,Acme Health — Dallas floor,a9b8c7d6-e5f4-4a3b-9c2d-1e0f9a8b7c6d,dailyCap: 50 → 80; status: paused → active,dailyCap status,203.0.113.24,5d1c0d2e-8a4f-4c0b-9e1d-2f3a4b5c6d7e

Errors

StatusCodeWhen
400validation_errorA filter has the wrong type, or limit is outside 1–50000. A bad query is refused before anything is written to the log.
401unauthorizedNo session token, or one that has expired.
402plan_upgrade_requiredThe workspace's plan does not include call tracking. details.feature is callTracking.
403forbiddenYou named no workspace and hold no owner or admin seat on any.
404not_foundAn agencyId that is not a workspace you administer answers the same 404.