API reference

Targets

Read your targets and their live cap counters, change what a target is worth and how much it may take, pause and resume it, and reset its counters.

A target is one destination a buyer receives calls on: a phone number, a SIP address, or a bidding endpoint that prices each call as it arrives. Targets are what a routing plan orders, so this is the group an integration reaches for to pace spend, open and close a buyer's floor by the hour, or stop a target that is having a bad day. The concepts are in Targets.

Two surfaces

Five routes are on the REST API, taken with an API key. Creating a target, editing it in full, moving it through its whole status machine and testing it are the console's own routes, taken with a signed-in owner's or admin's session token. Each endpoint below says which credential it takes.

EndpointSurfaceCredential
GET /api/v1/targetsREST APIAPI key with targets:read
GET /api/v1/targets/:idREST APIAPI key with targets:read
PATCH /api/v1/targets/:idREST APIAPI key with targets:write
POST /api/v1/targets/:id/statusREST APIAPI key with targets:write
POST /api/v1/targets/:id/reset-capsREST APIAPI key with targets:write
POST /api/tracking/targetsConsoleSession token
PATCH /api/tracking/targets/:idConsoleSession token
POST /api/tracking/targets/:id/statusConsoleSession token
POST /api/tracking/targets/:id/testConsoleSession token
The console routes are the product's own, and may change with the console. The REST API is the stable surface to build on.

The target object

One shape, whatever the target's type. type is fixed when the target is created and can never be changed; kind is derived from it and from the price, and tells you which of the three sorts of target you are looking at.

FieldTypeMeaning
iduuidThe target's id, used in every path below.
namestringWhat you call it.
typestringnumber, sip or rtb. Immutable.
kindstringstatic for a number or SIP target with a price, delivery for one priced at 0, external_rtb for a bidder.
statusstringdraft, active, paused or archived.
externalRefstring or nullYour own reference for this target. It is frozen onto each call that is routed to it, so a later rename does not rewrite old records.
buyerId, buyeruuid, object or nullThe buyer that owns the target, as { id, name, status }.
healthstringunknown, healthy, degraded or down, from the target's recent calls and tests.
lastError, consecutiveFailures, suppressedUntilstring or null, integer, timestamp or nullThe circuit breaker. After enough failures in a row a target is switched off for a short time and skipped with the reason suppressed; it is retried automatically.
revenueCentsinteger or nullWhat a converted call on this target is worth. null on an rtb target, where the bid is the price.
durationThresholdSecondsintegerTalk time at which a call converts. 0 converts on connection.
destinationobject{ type, value, display } — a short description of where calls go. For a bidder it is the host of the bid URL.
endpointobject or nullThe dialling details of a number or sip target. null for a bidder. Secrets are never in it: hasSipSecret and sipSecretLast4 are all that comes back.
rtbobject or nullThe bidding configuration of an rtb target — see How a bidder reads to a key.
concurrencyCap, hourlyCap, dailyCap, monthlyCap, totalCap, dailyRevenueCapCentsintegerThe caps. 0 is unlimited, everywhere.
capCountsOnstringWhen a call counts against the call caps: claimed at the dial, connected when the buyer's line answers, converted at settlement. Revenue against dailyRevenueCapCents is always counted at settlement.
usageobjectThe live counters: { liveCalls, hour, day, month, total, dayRevenueCents }.
liveCallsintegerCalls on this target right now.
statesarray of stringsTwo-letter state codes the target accepts. Empty accepts every state.
timezone, hoursSchedulestring, object or nullWhen the target is open. null is always open.
dedupeWindowSecondsintegerA caller who already reached this target inside this window is skipped with the reason duplicate. 0 switches it off.
todayobjectOnly on a single-target read: the day's counts and money, on the workspace's calendar.
routesarrayOnly on a single-target read: the campaigns whose routing plan this target is on, each { id, campaignId, campaign, priority, weight, active, revenueOverrideCents }.
createdAt, updatedAttimestampWhen the target was created and last changed.

How a bidder reads to a key

Every response on this page that carries an rtb target has two fields blanked for an API key: each value in rtb.bidHeaders and, when it is set, rtb.bidBodyTemplate. Both come back as •••, and the header names stay so you can see which are in place. In practice those two fields are where a buyer's static token ends up — an X-Api-Key header, or a body template with a token inside it — and a key is a long-lived credential pasted into other people's tools. A key cannot write those fields either, so nothing round-trips through them. A signed-in owner sees them in full in the console.

Three sorts of target

typeWhere the call goesWhat it is worth
numberA phone number you dial, in E.164.revenueCents, fixed. A price of 0 makes it a delivery target: the call is handed over but books nothing.
sipA SIP address, with a transport, a port and optional credentials.As above.
rtbNowhere by itself. The buyer's endpoint is asked for a price and a destination as each call arrives.Whatever the buyer bids, clamped by minBidCents and maxBidCents. revenueCents is null and is refused on a write.
A target's type is chosen at creation and cannot be changed afterwards. To move a buyer from a fixed price to bidding, create a second target and re-point the routing plan.

Endpoints

List targets

GET/api/v1/targets

Every target in your workspace, filtered and paged, each with its caps and its live counters. Archived targets are left out unless you ask for them by name. Use campaignId to read only the targets on one campaign's routing plan.

API key. Send Authorization: Bearer <api key>. See Authentication.Scopetargets:read

Query parameters

NameTypeDescription
qOptionalstringMatches name or externalRef, case-insensitively, anywhere in the value.up to 120 characters
statusOptionalenumOne status.draft, active, paused, archived · default: every status except archived
buyerIdOptionaluuidOnly targets owned by this buyer.
typeOptionalenumThe sort of destination.number, sip, rtb
kindOptionalenumPriced, unpriced or bidding.static, delivery, external_rtb
healthOptionalenumThe target's health badge.unknown, healthy, degraded, down
campaignIdOptionaluuidOnly targets on this campaign's routing plan. A campaign that is not yours answers 404.
pageOptionalintegerPage number, from 1.default 1
pageSizeOptionalintegerRows per page.default 25 · at most 200; a larger value is clamped rather than refused
sortOptionalenumThe field to sort by. An unknown value falls back to the default rather than failing.createdAt, updatedAt, name, status · default createdAt
dirOptionalenumSort direction.asc, desc · default desc

Example request

curl "https://api.buy3.io/api/v1/targets?status=active&type=number&pageSize=25" \
  -H "Authorization: Bearer $BUY3_API_KEY"

Responses

  • 200A page of target objects with today beside each one. routes is only on a single-target read. An rtb target's header values and body template are blanked.
{
  "data": [
    {
      "id": "a9b8c7d6-e5f4-4a3b-9c2d-1e0f9a8b7c6d",
      "name": "Acme Health — Dallas floor",
      "type": "number",
      "kind": "static",
      "status": "active",
      "externalRef": "acme-dal-01",
      "buyerId": "f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b",
      "buyer": {
        "id": "f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b",
        "name": "Acme Health",
        "status": "active"
      },
      "health": "healthy",
      "lastError": null,
      "consecutiveFailures": 0,
      "suppressedUntil": null,
      "revenueCents": 4200,
      "durationThresholdSeconds": 90,
      "destination": {
        "type": "number",
        "value": "+12145550188",
        "display": "+12145550188"
      },
      "endpoint": {
        "id": "5b4a3c2d-1e0f-4a9b-8c7d-6e5f4a3b2c1d",
        "mode": "pstn_did",
        "destinationE164": "+12145550188",
        "callerIdMode": "passthrough",
        "callerIdE164": null,
        "sendDigits": null,
        "sipUri": null,
        "sipTransport": null,
        "sipPort": null,
        "sipAuthType": null,
        "sipUsername": null,
        "sipRealm": null,
        "hasSipSecret": false,
        "sipSecretLast4": null,
        "ringTimeoutSeconds": 20,
        "lastHealthCheckAt": "2026-09-20T09:14:02.000Z"
      },
      "rtb": null,
      "concurrencyCap": 5,
      "hourlyCap": 0,
      "dailyCap": 40,
      "monthlyCap": 0,
      "totalCap": 0,
      "dailyRevenueCapCents": 0,
      "capCountsOn": "connected",
      "usage": {
        "liveCalls": 2,
        "hour": 4,
        "day": 31,
        "month": 612,
        "total": 4188,
        "dayRevenueCents": 130200
      },
      "liveCalls": 2,
      "states": [
        "TX",
        "OK"
      ],
      "timezone": "America/Chicago",
      "hoursSchedule": null,
      "dedupeWindowSeconds": 86400,
      "createdAt": "2026-07-02T16:20:11.000Z",
      "updatedAt": "2026-09-19T11:02:44.000Z",
      "today": {
        "calls": 31,
        "connected": 24,
        "converted": 14,
        "connectRate": 0.7742,
        "conversionRate": 0.5833,
        "revenueCents": 58800,
        "payoutCents": 38500
      }
    }
  ],
  "page": 1,
  "pageSize": 25,
  "total": 7,
  "totalPages": 1
}

Errors

StatusCodeWhen
400validation_errorA filter has the wrong type or is not one of the listed values. details names the field.
404not_foundcampaignId names a campaign that is not a tracking campaign of your workspace.
401missing_key, invalid_keyNo bearer key was sent, or the key is malformed, unknown, or revoked with its grace period over. See Authentication.
402subscription_inactive, plan_upgrade_requiredThe workspace's subscription is not active, or its plan does not include call tracking and API access.
403insufficient_scope, ip_not_allowedThe key does not hold targets:read, or the request came from an address outside the key's allowlist. insufficient_scope carries the scopes required and the ones held.
429rate_limitedThe key is over its per-minute limit. Wait for Retry-After seconds.

Read a target

GET/api/v1/targets/:id

One target, with today and with routes — the campaigns whose routing plan it sits on, and at what priority and weight. This is the read to make before changing a cap: usage tells you where the counters stand right now.

API key. Send Authorization: Bearer <api key>. See Authentication.Scopetargets:read

Path parameters

NameTypeDescription
idRequireduuidThe target's id, as returned by List targets.

Example request

curl "https://api.buy3.io/api/v1/targets/a9b8c7d6-e5f4-4a3b-9c2d-1e0f9a8b7c6d" \
  -H "Authorization: Bearer $BUY3_API_KEY"

Responses

  • 200The target, its day so far, and every route that points at it.
  • 200 (a bidder, read with a key)The same shape for an external RTB target. rtb.bidHeaders keeps its names and loses its values, and rtb.bidBodyTemplate reads ••• when one is set.
{
  "target": {
    "id": "a9b8c7d6-e5f4-4a3b-9c2d-1e0f9a8b7c6d",
    "name": "Acme Health — Dallas floor",
    "type": "number",
    "kind": "static",
    "status": "active",
    "externalRef": "acme-dal-01",
    "buyerId": "f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b",
    "buyer": {
      "id": "f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b",
      "name": "Acme Health",
      "status": "active"
    },
    "health": "healthy",
    "lastError": null,
    "consecutiveFailures": 0,
    "suppressedUntil": null,
    "revenueCents": 4200,
    "durationThresholdSeconds": 90,
    "destination": {
      "type": "number",
      "value": "+12145550188",
      "display": "+12145550188"
    },
    "endpoint": {
      "id": "5b4a3c2d-1e0f-4a9b-8c7d-6e5f4a3b2c1d",
      "mode": "pstn_did",
      "destinationE164": "+12145550188",
      "callerIdMode": "passthrough",
      "callerIdE164": null,
      "sendDigits": null,
      "sipUri": null,
      "sipTransport": null,
      "sipPort": null,
      "sipAuthType": null,
      "sipUsername": null,
      "sipRealm": null,
      "hasSipSecret": false,
      "sipSecretLast4": null,
      "ringTimeoutSeconds": 20,
      "lastHealthCheckAt": "2026-09-20T09:14:02.000Z"
    },
    "rtb": null,
    "concurrencyCap": 5,
    "hourlyCap": 0,
    "dailyCap": 40,
    "monthlyCap": 0,
    "totalCap": 0,
    "dailyRevenueCapCents": 0,
    "capCountsOn": "connected",
    "usage": {
      "liveCalls": 2,
      "hour": 4,
      "day": 31,
      "month": 612,
      "total": 4188,
      "dayRevenueCents": 130200
    },
    "liveCalls": 2,
    "states": [
      "TX",
      "OK"
    ],
    "timezone": "America/Chicago",
    "hoursSchedule": null,
    "dedupeWindowSeconds": 86400,
    "createdAt": "2026-07-02T16:20:11.000Z",
    "updatedAt": "2026-09-19T11:02:44.000Z",
    "today": {
      "calls": 31,
      "connected": 24,
      "converted": 14,
      "connectRate": 0.7742,
      "conversionRate": 0.5833,
      "revenueCents": 58800,
      "payoutCents": 38500
    },
    "routes": [
      {
        "id": "d0c1b2a3-9e8f-4d7c-b6a5-4e3f2d1c0b9a",
        "campaignId": "6a2d1f0e-8b7c-4c55-a1d3-0e9f8a7b6c5d",
        "campaign": {
          "id": "6a2d1f0e-8b7c-4c55-a1d3-0e9f8a7b6c5d",
          "name": "Health cover — inbound",
          "status": "live",
          "routingMode": "priority"
        },
        "priority": 1,
        "weight": 3,
        "active": true,
        "revenueOverrideCents": null
      }
    ]
  }
}

Errors

StatusCodeWhen
404not_foundNo target with that id in your workspace. A malformed id, an id that does not exist and another workspace's target all answer exactly the same, before any query runs.
401missing_key, invalid_keyNo bearer key was sent, or the key is malformed, unknown, or revoked with its grace period over. See Authentication.
402subscription_inactive, plan_upgrade_requiredThe workspace's subscription is not active, or its plan does not include call tracking and API access.
403insufficient_scope, ip_not_allowedThe key does not hold targets:read, or the request came from an address outside the key's allowlist. insufficient_scope carries the scopes required and the ones held.
429rate_limitedThe key is over its per-minute limit. Wait for Retry-After seconds.

Update a target

PATCH/api/v1/targets/:id

Change what a target is worth and how much it may take. Nine fields are writable through a key — revenueCents, concurrencyCap, hourlyCap, dailyCap, monthlyCap, totalCap, dailyRevenueCapCents, hoursSchedule and states — and they are the ones that pace and price a buyer: the two things anybody automates a target for. Send only the fields you are changing; anything you leave out keeps its value. A field the console's form knows and a key may not write is refused, not quietly dropped, so a program that tries to move a destination and reads back 200 cannot exist. The write is recorded in the activity log under the key's name.

API key. Send Authorization: Bearer <api key>. See Authentication.Scopetargets:write

Path parameters

NameTypeDescription
idRequireduuidThe target's id, as returned by List targets.

Request body

NameTypeDescription
revenueCentsOptionalintegerWhat a converted call on this target is worth, in cents. Refused on an rtb target, where the bid is the price.0 to 100000000
concurrencyCapOptionalintegerHow many of this target's calls may be live at once.0 to 100000 · 0 is unlimited
hourlyCapOptionalintegerCalls this target may take in one UTC clock hour.0 to 1000000 · 0 is unlimited
dailyCapOptionalintegerCalls in one UTC day.0 to 1000000 · 0 is unlimited
monthlyCapOptionalintegerCalls in one UTC month.0 to 10000000 · 0 is unlimited
totalCapOptionalintegerCalls over the target's whole life. It never resets on its own.0 to 100000000 · 0 is unlimited
dailyRevenueCapCentsOptionalintegerRevenue this target may earn in one UTC day, in cents. Revenue is always counted at settlement, whatever capCountsOn says.0 to 100000000000 · 0 is unlimited
hoursScheduleOptionalobject or nullWhen the target accepts calls. { tz, days: { mon: [["09:00", "17:00"]], … } }, or null for always open. See Hours and caps.at most 6 windows a day · a schedule that closes all seven days is refused — send null instead
statesOptionalarray of strings or nullTwo-letter state codes the target accepts, from the caller's area code. An empty array accepts every state.at most 62 codes

Example request

curl -X PATCH "https://api.buy3.io/api/v1/targets/a9b8c7d6-e5f4-4a3b-9c2d-1e0f9a8b7c6d" \
  -H "Authorization: Bearer $BUY3_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "dailyCap": 75,
    "concurrencyCap": 8
  }'

Responses

  • 200The target as it now stands, with today and routes. A bidder's header values and body template are blanked as everywhere else.
{
  "target": {
    "id": "a9b8c7d6-e5f4-4a3b-9c2d-1e0f9a8b7c6d",
    "name": "Acme Health — Dallas floor",
    "type": "number",
    "kind": "static",
    "status": "active",
    "externalRef": "acme-dal-01",
    "buyerId": "f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b",
    "buyer": {
      "id": "f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b",
      "name": "Acme Health",
      "status": "active"
    },
    "health": "healthy",
    "lastError": null,
    "consecutiveFailures": 0,
    "suppressedUntil": null,
    "revenueCents": 4200,
    "durationThresholdSeconds": 90,
    "destination": {
      "type": "number",
      "value": "+12145550188",
      "display": "+12145550188"
    },
    "endpoint": {
      "id": "5b4a3c2d-1e0f-4a9b-8c7d-6e5f4a3b2c1d",
      "mode": "pstn_did",
      "destinationE164": "+12145550188",
      "callerIdMode": "passthrough",
      "callerIdE164": null,
      "sendDigits": null,
      "sipUri": null,
      "sipTransport": null,
      "sipPort": null,
      "sipAuthType": null,
      "sipUsername": null,
      "sipRealm": null,
      "hasSipSecret": false,
      "sipSecretLast4": null,
      "ringTimeoutSeconds": 20,
      "lastHealthCheckAt": "2026-09-20T09:14:02.000Z"
    },
    "rtb": null,
    "concurrencyCap": 8,
    "hourlyCap": 0,
    "dailyCap": 75,
    "monthlyCap": 0,
    "totalCap": 0,
    "dailyRevenueCapCents": 0,
    "capCountsOn": "connected",
    "usage": {
      "liveCalls": 2,
      "hour": 4,
      "day": 31,
      "month": 612,
      "total": 4188,
      "dayRevenueCents": 130200
    },
    "liveCalls": 2,
    "states": [
      "TX",
      "OK"
    ],
    "timezone": "America/Chicago",
    "hoursSchedule": null,
    "dedupeWindowSeconds": 86400,
    "createdAt": "2026-07-02T16:20:11.000Z",
    "updatedAt": "2026-09-20T18:31:07.000Z",
    "today": {
      "calls": 31,
      "connected": 24,
      "converted": 14,
      "connectRate": 0.7742,
      "conversionRate": 0.5833,
      "revenueCents": 58800,
      "payoutCents": 38500
    },
    "routes": [
      {
        "id": "d0c1b2a3-9e8f-4d7c-b6a5-4e3f2d1c0b9a",
        "campaignId": "6a2d1f0e-8b7c-4c55-a1d3-0e9f8a7b6c5d",
        "campaign": {
          "id": "6a2d1f0e-8b7c-4c55-a1d3-0e9f8a7b6c5d",
          "name": "Health cover — inbound",
          "status": "live",
          "routingMode": "priority"
        },
        "priority": 1,
        "weight": 3,
        "active": true,
        "revenueOverrideCents": null
      }
    ]
  }
}

Errors

StatusCodeWhen
400field_not_writableThe body named a field only the console may change — the destination, the SIP or bidding credentials, the buyer, the type, capCountsOn, timezone, durationThresholdSeconds, dedupeWindowSeconds, name and so on. details names every refused field and says what a key may change instead. Nothing was written.
400validation_errorA writable field has the wrong type or is out of range. details names the field.
400bad_requestNothing to update — the body carried no writable field. Or a cross-field rule failed: revenueCents on an rtb target, an hoursSchedule that closes all seven days, or a state code that is not two letters.
404not_foundNo target with that id in your workspace. A malformed id, an id that does not exist and another workspace's target all answer exactly the same, before any query runs.
409conflictThe target is archived. Restore it in the console first.
401missing_key, invalid_keyNo bearer key was sent, or the key is malformed, unknown, or revoked with its grace period over. See Authentication.
402subscription_inactive, plan_upgrade_requiredThe workspace's subscription is not active, or its plan does not include call tracking and API access.
403insufficient_scope, ip_not_allowedThe key does not hold targets:write, or the request came from an address outside the key's allowlist. insufficient_scope carries the scopes required and the ones held.
429rate_limitedThe key is over its per-minute limit. Wait for Retry-After seconds.

Pause or resume a target

POST/api/v1/targets/:id/status

Switch a target between active and paused, and nothing else. A paused target stays on every routing plan it is on and is skipped while it is paused — no route is deleted, so resuming it puts the calls back exactly where they were. Status is a request of its own, never a field on Update a target, so editing a cap can never switch a buyer off by accident. The change is recorded in the activity log.

API key. Send Authorization: Bearer <api key>. See Authentication.Scopetargets:write

Path parameters

NameTypeDescription
idRequireduuidThe target's id, as returned by List targets.

Request body

NameTypeDescription
statusRequiredenumThe status to move to.active or paused
noteOptionalstringWhy, for the activity log and for the person who reads it later.up to 500 characters

Example request

curl -X POST "https://api.buy3.io/api/v1/targets/a9b8c7d6-e5f4-4a3b-9c2d-1e0f9a8b7c6d/status" \
  -H "Authorization: Bearer $BUY3_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "paused",
    "note": "Queue backed up — pausing until 16:00"
  }'

Responses

  • 200The target, and changedfalse when it was already in that status, which is what a retry answers. removedRoutes is always 0 here: only archiving removes routes, and a key cannot archive.
{
  "target": {
    "id": "a9b8c7d6-e5f4-4a3b-9c2d-1e0f9a8b7c6d",
    "name": "Acme Health — Dallas floor",
    "type": "number",
    "kind": "static",
    "status": "paused",
    "externalRef": "acme-dal-01",
    "buyerId": "f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b",
    "buyer": {
      "id": "f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b",
      "name": "Acme Health",
      "status": "active"
    },
    "health": "healthy",
    "lastError": null,
    "consecutiveFailures": 0,
    "suppressedUntil": null,
    "revenueCents": 4200,
    "durationThresholdSeconds": 90,
    "destination": {
      "type": "number",
      "value": "+12145550188",
      "display": "+12145550188"
    },
    "endpoint": {
      "id": "5b4a3c2d-1e0f-4a9b-8c7d-6e5f4a3b2c1d",
      "mode": "pstn_did",
      "destinationE164": "+12145550188",
      "callerIdMode": "passthrough",
      "callerIdE164": null,
      "sendDigits": null,
      "sipUri": null,
      "sipTransport": null,
      "sipPort": null,
      "sipAuthType": null,
      "sipUsername": null,
      "sipRealm": null,
      "hasSipSecret": false,
      "sipSecretLast4": null,
      "ringTimeoutSeconds": 20,
      "lastHealthCheckAt": "2026-09-20T09:14:02.000Z"
    },
    "rtb": null,
    "concurrencyCap": 5,
    "hourlyCap": 0,
    "dailyCap": 40,
    "monthlyCap": 0,
    "totalCap": 0,
    "dailyRevenueCapCents": 0,
    "capCountsOn": "connected",
    "usage": {
      "liveCalls": 2,
      "hour": 4,
      "day": 31,
      "month": 612,
      "total": 4188,
      "dayRevenueCents": 130200
    },
    "liveCalls": 2,
    "states": [
      "TX",
      "OK"
    ],
    "timezone": "America/Chicago",
    "hoursSchedule": null,
    "dedupeWindowSeconds": 86400,
    "createdAt": "2026-07-02T16:20:11.000Z",
    "updatedAt": "2026-09-20T18:33:41.000Z"
  },
  "changed": true,
  "removedRoutes": 0
}

Errors

StatusCodeWhen
400validation_errorstatus is missing, or is not active or paused.
404not_foundNo target with that id in your workspace. A malformed id, an id that does not exist and another workspace's target all answer exactly the same, before any query runs.
409conflictThe target is draft or archived. The API pauses an active target and resumes a paused one; everything else is a console act. details carries the current status and the allowed list.
401missing_key, invalid_keyNo bearer key was sent, or the key is malformed, unknown, or revoked with its grace period over. See Authentication.
402subscription_inactive, plan_upgrade_requiredThe workspace's subscription is not active, or its plan does not include call tracking and API access.
403insufficient_scope, ip_not_allowedThe key does not hold targets:write, or the request came from an address outside the key's allowlist. insufficient_scope carries the scopes required and the ones held.
429rate_limitedThe key is over its per-minute limit. Wait for Retry-After seconds.

Reset a target's cap counters

POST/api/v1/targets/:id/reset-caps

Zero the target's hour, day, month and lifetime call counters and the day's revenue, and start each window from now. The caps themselves are untouched, so is liveCalls, and so are the buyer's counters — a buyer-level cap is reset on the buyer. Use it after a test run, or when a buyer agrees to take more today than their cap allows. It takes no body, and it is recorded in the activity log: the entry keeps the figures that were cleared, because a reset cannot be undone.

API key. Send Authorization: Bearer <api key>. See Authentication.Scopetargets:write

Path parameters

NameTypeDescription
idRequireduuidThe target's id, as returned by List targets.

Example request

curl -X POST "https://api.buy3.io/api/v1/targets/a9b8c7d6-e5f4-4a3b-9c2d-1e0f9a8b7c6d/reset-caps" \
  -H "Authorization: Bearer $BUY3_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

Responses

  • 200The target with its counters at zero, and reset — what they read before. Retrying is safe: the second call zeroes what is already zero and answers reset full of zeroes.
{
  "target": {
    "id": "a9b8c7d6-e5f4-4a3b-9c2d-1e0f9a8b7c6d",
    "name": "Acme Health — Dallas floor",
    "type": "number",
    "kind": "static",
    "status": "active",
    "externalRef": "acme-dal-01",
    "buyerId": "f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b",
    "buyer": {
      "id": "f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b",
      "name": "Acme Health",
      "status": "active"
    },
    "health": "healthy",
    "lastError": null,
    "consecutiveFailures": 0,
    "suppressedUntil": null,
    "revenueCents": 4200,
    "durationThresholdSeconds": 90,
    "destination": {
      "type": "number",
      "value": "+12145550188",
      "display": "+12145550188"
    },
    "endpoint": {
      "id": "5b4a3c2d-1e0f-4a9b-8c7d-6e5f4a3b2c1d",
      "mode": "pstn_did",
      "destinationE164": "+12145550188",
      "callerIdMode": "passthrough",
      "callerIdE164": null,
      "sendDigits": null,
      "sipUri": null,
      "sipTransport": null,
      "sipPort": null,
      "sipAuthType": null,
      "sipUsername": null,
      "sipRealm": null,
      "hasSipSecret": false,
      "sipSecretLast4": null,
      "ringTimeoutSeconds": 20,
      "lastHealthCheckAt": "2026-09-20T09:14:02.000Z"
    },
    "rtb": null,
    "concurrencyCap": 5,
    "hourlyCap": 0,
    "dailyCap": 40,
    "monthlyCap": 0,
    "totalCap": 0,
    "dailyRevenueCapCents": 0,
    "capCountsOn": "connected",
    "usage": {
      "liveCalls": 2,
      "hour": 0,
      "day": 0,
      "month": 0,
      "total": 0,
      "dayRevenueCents": 0
    },
    "liveCalls": 2,
    "states": [
      "TX",
      "OK"
    ],
    "timezone": "America/Chicago",
    "hoursSchedule": null,
    "dedupeWindowSeconds": 86400,
    "createdAt": "2026-07-02T16:20:11.000Z",
    "updatedAt": "2026-09-20T18:35:02.000Z"
  },
  "reset": {
    "liveCalls": 2,
    "hour": 4,
    "day": 31,
    "month": 612,
    "total": 4188,
    "dayRevenueCents": 130200
  }
}

Errors

StatusCodeWhen
404not_foundNo target with that id in your workspace. A malformed id, an id that does not exist and another workspace's target all answer exactly the same, before any query runs.
401missing_key, invalid_keyNo bearer key was sent, or the key is malformed, unknown, or revoked with its grace period over. See Authentication.
402subscription_inactive, plan_upgrade_requiredThe workspace's subscription is not active, or its plan does not include call tracking and API access.
403insufficient_scope, ip_not_allowedThe key does not hold targets:write, or the request came from an address outside the key's allowlist. insufficient_scope carries the scopes required and the ones held.
429rate_limitedThe key is over its per-minute limit. Wait for Retry-After seconds.

Console API · Create a target

POST/api/tracking/targets

Console API. This route takes a signed-in owner's or admin's session token, not an API key, and it may change with the console — treat the REST endpoints above as the stable surface. A target and its destination are created together in one request, so there is never a target pointing at nothing. type is chosen here and is immutable afterwards. Fields that belong to a different type are refused rather than ignored. How many targets a workspace may hold depends on its plan; see pricing.

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
agencyIdOptionaluuidThe workspace to act in. Only needed when you hold an owner or admin seat on more than one.

Request body

NameTypeDescription
nameRequiredstringWhat you call the target.2 to 200 characters
buyerIdRequireduuidThe buyer that owns it. It must be yours and must not be archived.
typeRequiredenumThe sort of destination. Immutable once created.number, sip or rtb
statusOptionalenumThe status to create it in. Create only — afterwards use the status route.draft, active, paused · default active
externalRefOptionalstringYour own reference. It is frozen onto each call routed to this target.up to 200 characters
destinationE164OptionalstringThe number to dial, in E.164. Required for a number target.
callerIdModeOptionalenumWhat the buyer sees as the calling number.passthrough, tracking_number, fixednumber targets only
callerIdE164OptionalstringThe number to show. Required when callerIdMode is fixed.
sendDigitsOptionalstringDTMF to send once the call is answered, for an extension or an IVR.up to 40 characters · digits, *, #, w and ,
sipUriOptionalstringThe SIP address. Required for a sip target. The host must resolve to a public address.up to 500 characters · sip:user@host or sips:user@host
sipTransportOptionalenumSIP transport.udp, tcp, tls
sipPortOptionalintegerSIP port.1 to 65535
sipAuthTypeOptionalenumHow the SIP endpoint authenticates. none clears any stored secret.none, basic, bearer, api_key_header, hmac_sha256, oauth2_client_credentials, ip_acl, digest
sipUsernameOptionalstringSIP username.up to 200 characters
sipRealmOptionalstringSIP realm.up to 200 characters
sipSecretOptionalstringThe SIP secret. Write-only — no response ever returns it, and the activity log records only that it changed. On an edit, sending it blank keeps the stored one.1 to 400 characters
ringTimeoutSecondsOptionalintegerHow long one attempt on this target may ring.5 to 120 · default 20 · number and sip targets only
revenueCentsOptionalintegerWhat a converted call is worth. 0 files the target as delivery — calls are handed over and book nothing. Refused on an rtb target.0 to 100000000
rtbOptionalobjectThe bidding configuration of an rtb target. See External RTB targets for what each path means; errors on it are keyed rtb.<field>.bidUrl is required and must pass the public-URL check · bidPath and destinationPath are required, though a preset may supply them · a preset of ringba, retreaver, trackdrive or custom fills blank paths only, and never overrides what you sent
durationThresholdSecondsOptionalintegerTalk time at which a call on this target converts.0 to 7200
concurrencyCapOptionalintegerHow many of this target's calls may be live at once.0 to 100000 · 0 is unlimited
hourlyCapOptionalintegerCalls this target may take in one UTC clock hour.0 to 1000000 · 0 is unlimited
dailyCapOptionalintegerCalls in one UTC day.0 to 1000000 · 0 is unlimited
monthlyCapOptionalintegerCalls in one UTC month.0 to 10000000 · 0 is unlimited
totalCapOptionalintegerCalls over the target's whole life. It never resets on its own.0 to 100000000 · 0 is unlimited
dailyRevenueCapCentsOptionalintegerRevenue this target may earn in one UTC day, in cents. Revenue is always counted at settlement, whatever capCountsOn says.0 to 100000000000 · 0 is unlimited
hoursScheduleOptionalobject or nullWhen the target accepts calls. { tz, days: { mon: [["09:00", "17:00"]], … } }, or null for always open. See Hours and caps.at most 6 windows a day · a schedule that closes all seven days is refused — send null instead
statesOptionalarray of strings or nullTwo-letter state codes the target accepts, from the caller's area code. An empty array accepts every state.at most 62 codes
capCountsOnOptionalenumWhen a call counts against the call caps.claimed, connected, converted
timezoneOptionalstringAn IANA zone for the target's hours.up to 64 characters
dedupeWindowSecondsOptionalintegerHow long a caller who already reached this target is skipped for.0 to 2592000 · 0 switches it off

Example request

curl -X POST "https://api.buy3.io/api/tracking/targets" \
  -H "Authorization: Bearer $BUY3_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Health — Dallas floor",
    "buyerId": "f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b",
    "type": "number",
    "destinationE164": "+12145550188",
    "revenueCents": 4200,
    "durationThresholdSeconds": 90,
    "concurrencyCap": 5,
    "dailyCap": 40,
    "capCountsOn": "connected",
    "states": [
      "TX",
      "OK"
    ]
  }'

Responses

  • 201The target that was created, with an empty routes — add it to a routing plan to start sending it calls.
{
  "target": {
    "id": "a9b8c7d6-e5f4-4a3b-9c2d-1e0f9a8b7c6d",
    "name": "Acme Health — Dallas floor",
    "type": "number",
    "kind": "static",
    "status": "active",
    "externalRef": "acme-dal-01",
    "buyerId": "f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b",
    "buyer": {
      "id": "f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b",
      "name": "Acme Health",
      "status": "active"
    },
    "health": "unknown",
    "lastError": null,
    "consecutiveFailures": 0,
    "suppressedUntil": null,
    "revenueCents": 4200,
    "durationThresholdSeconds": 90,
    "destination": {
      "type": "number",
      "value": "+12145550188",
      "display": "+12145550188"
    },
    "endpoint": {
      "id": "5b4a3c2d-1e0f-4a9b-8c7d-6e5f4a3b2c1d",
      "mode": "pstn_did",
      "destinationE164": "+12145550188",
      "callerIdMode": "passthrough",
      "callerIdE164": null,
      "sendDigits": null,
      "sipUri": null,
      "sipTransport": null,
      "sipPort": null,
      "sipAuthType": null,
      "sipUsername": null,
      "sipRealm": null,
      "hasSipSecret": false,
      "sipSecretLast4": null,
      "ringTimeoutSeconds": 20,
      "lastHealthCheckAt": "2026-09-20T09:14:02.000Z"
    },
    "rtb": null,
    "concurrencyCap": 5,
    "hourlyCap": 0,
    "dailyCap": 40,
    "monthlyCap": 0,
    "totalCap": 0,
    "dailyRevenueCapCents": 0,
    "capCountsOn": "connected",
    "usage": {
      "liveCalls": 0,
      "hour": 0,
      "day": 0,
      "month": 0,
      "total": 0,
      "dayRevenueCents": 0
    },
    "liveCalls": 0,
    "states": [
      "TX",
      "OK"
    ],
    "timezone": "America/Chicago",
    "hoursSchedule": null,
    "dedupeWindowSeconds": 86400,
    "createdAt": "2026-07-02T16:20:11.000Z",
    "updatedAt": "2026-09-19T11:02:44.000Z",
    "routes": []
  }
}

Errors

StatusCodeWhen
400validation_errorA field has the wrong type or is out of range. details names it.
400bad_requestA field belongs to a different type than the one you sent, a required field for this type is missing, or a cross-field rule failed. details names each field.
400unsafe_urlA rtb.bidUrl or rtb.authTokenUrl is not a public https address. details.rule says which rule it broke.
402plan_upgrade_requiredThe workspace has as many targets as its plan allows. details carries the limit and the current count.
404not_foundbuyerId is not a buyer of this workspace.
401unauthorizedNo session token, or one that has expired.
402subscription_inactiveThe workspace's subscription is not active, and this is a write. details carries status, planId and agencyId.
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_foundNo target with that id in this workspace, or you named a workspace with ?agencyId= that is not yours.

Console API · Update a target in full

PATCH/api/tracking/targets/:id

Console API. The same path as Update a target but with a session token behind it, and every field of the create form is writable — the destination, the SIP or bidding credentials, the buyer and the rest. This is the route to change where a target's calls go. type is tolerated when it states what the target already is and refused when it does not. A URL is re-checked against the public-address rules only when it changes.

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.

Path parameters

NameTypeDescription
idRequireduuidThe target's id, as returned by List targets.

Query parameters

NameTypeDescription
agencyIdOptionaluuidThe workspace to act in.

Request body

NameTypeDescription
any create fieldOptionalEvery field of Create a target except status, which has its own route. Cross-field rules are judged on the row as it will be after the change, not as it is now.at least one field

Example request

curl -X PATCH "https://api.buy3.io/api/tracking/targets/a9b8c7d6-e5f4-4a3b-9c2d-1e0f9a8b7c6d" \
  -H "Authorization: Bearer $BUY3_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "destinationE164": "+12145550190",
    "ringTimeoutSeconds": 25
  }'

Responses

  • 200The target as it now stands, with today and routes.
{
  "target": {
    "id": "a9b8c7d6-e5f4-4a3b-9c2d-1e0f9a8b7c6d",
    "name": "Acme Health — Dallas floor",
    "type": "number",
    "kind": "static",
    "status": "active",
    "externalRef": "acme-dal-01",
    "buyerId": "f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b",
    "buyer": {
      "id": "f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b",
      "name": "Acme Health",
      "status": "active"
    },
    "health": "healthy",
    "lastError": null,
    "consecutiveFailures": 0,
    "suppressedUntil": null,
    "revenueCents": 4200,
    "durationThresholdSeconds": 90,
    "destination": {
      "type": "number",
      "value": "+12145550190",
      "display": "+12145550190"
    },
    "endpoint": {
      "id": "5b4a3c2d-1e0f-4a9b-8c7d-6e5f4a3b2c1d",
      "mode": "pstn_did",
      "destinationE164": "+12145550188",
      "callerIdMode": "passthrough",
      "callerIdE164": null,
      "sendDigits": null,
      "sipUri": null,
      "sipTransport": null,
      "sipPort": null,
      "sipAuthType": null,
      "sipUsername": null,
      "sipRealm": null,
      "hasSipSecret": false,
      "sipSecretLast4": null,
      "ringTimeoutSeconds": 20,
      "lastHealthCheckAt": "2026-09-20T09:14:02.000Z"
    },
    "rtb": null,
    "concurrencyCap": 5,
    "hourlyCap": 0,
    "dailyCap": 40,
    "monthlyCap": 0,
    "totalCap": 0,
    "dailyRevenueCapCents": 0,
    "capCountsOn": "connected",
    "usage": {
      "liveCalls": 2,
      "hour": 4,
      "day": 31,
      "month": 612,
      "total": 4188,
      "dayRevenueCents": 130200
    },
    "liveCalls": 2,
    "states": [
      "TX",
      "OK"
    ],
    "timezone": "America/Chicago",
    "hoursSchedule": null,
    "dedupeWindowSeconds": 86400,
    "createdAt": "2026-07-02T16:20:11.000Z",
    "updatedAt": "2026-09-20T18:40:19.000Z",
    "today": {
      "calls": 31,
      "connected": 24,
      "converted": 14,
      "connectRate": 0.7742,
      "conversionRate": 0.5833,
      "revenueCents": 58800,
      "payoutCents": 38500
    },
    "routes": [
      {
        "id": "d0c1b2a3-9e8f-4d7c-b6a5-4e3f2d1c0b9a",
        "campaignId": "6a2d1f0e-8b7c-4c55-a1d3-0e9f8a7b6c5d",
        "campaign": {
          "id": "6a2d1f0e-8b7c-4c55-a1d3-0e9f8a7b6c5d",
          "name": "Health cover — inbound",
          "status": "live",
          "routingMode": "priority"
        },
        "priority": 1,
        "weight": 3,
        "active": true,
        "revenueOverrideCents": null
      }
    ]
  }
}

Errors

StatusCodeWhen
400validation_error, bad_request, unsafe_urlAs for create, plus bad_request with "Nothing to update" when the body carried no change, and a refused type that does not match the target.
409conflictThe target is archived.
401unauthorizedNo session token, or one that has expired.
402subscription_inactiveThe workspace's subscription is not active, and this is a write. details carries status, planId and agencyId.
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_foundNo target with that id in this workspace, or you named a workspace with ?agencyId= that is not yours.

Console API · Move a target through its statuses

POST/api/tracking/targets/:id/status

Console API. The whole state machine, not just pause and resume. Activating a target clears its circuit breakersuppressedUntil and consecutiveFailures go back to nothing on both the target and its endpoint — so a target that was switched off after repeated failures is given a clean start. Archiving removes the target from every routing plan it is on, in the same transaction, and the response counts them: those routes are gone, and restoring the target later does not put them back.

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.

Path parameters

NameTypeDescription
idRequireduuidThe target's id, as returned by List targets.

Query parameters

NameTypeDescription
agencyIdOptionaluuidThe workspace to act in.

Request body

NameTypeDescription
statusRequiredenumThe status to move to.draft, active, paused, archived
noteOptionalstringWhy, for the activity log.up to 1000 characters

Example request

curl -X POST "https://api.buy3.io/api/tracking/targets/a9b8c7d6-e5f4-4a3b-9c2d-1e0f9a8b7c6d/status" \
  -H "Authorization: Bearer $BUY3_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "archived",
    "note": "Buyer ended the contract"
  }'

Responses

  • 200The target, whether anything changed, and how many routes archiving removed.
{
  "target": {
    "id": "a9b8c7d6-e5f4-4a3b-9c2d-1e0f9a8b7c6d",
    "name": "Acme Health — Dallas floor",
    "type": "number",
    "kind": "static",
    "status": "archived",
    "externalRef": "acme-dal-01",
    "buyerId": "f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b",
    "buyer": {
      "id": "f1e2d3c4-b5a6-4978-8a9b-0c1d2e3f4a5b",
      "name": "Acme Health",
      "status": "active"
    },
    "health": "healthy",
    "lastError": null,
    "consecutiveFailures": 0,
    "suppressedUntil": null,
    "revenueCents": 4200,
    "durationThresholdSeconds": 90,
    "destination": {
      "type": "number",
      "value": "+12145550188",
      "display": "+12145550188"
    },
    "endpoint": {
      "id": "5b4a3c2d-1e0f-4a9b-8c7d-6e5f4a3b2c1d",
      "mode": "pstn_did",
      "destinationE164": "+12145550188",
      "callerIdMode": "passthrough",
      "callerIdE164": null,
      "sendDigits": null,
      "sipUri": null,
      "sipTransport": null,
      "sipPort": null,
      "sipAuthType": null,
      "sipUsername": null,
      "sipRealm": null,
      "hasSipSecret": false,
      "sipSecretLast4": null,
      "ringTimeoutSeconds": 20,
      "lastHealthCheckAt": "2026-09-20T09:14:02.000Z"
    },
    "rtb": null,
    "concurrencyCap": 5,
    "hourlyCap": 0,
    "dailyCap": 40,
    "monthlyCap": 0,
    "totalCap": 0,
    "dailyRevenueCapCents": 0,
    "capCountsOn": "connected",
    "usage": {
      "liveCalls": 2,
      "hour": 4,
      "day": 31,
      "month": 612,
      "total": 4188,
      "dayRevenueCents": 130200
    },
    "liveCalls": 2,
    "states": [
      "TX",
      "OK"
    ],
    "timezone": "America/Chicago",
    "hoursSchedule": null,
    "dedupeWindowSeconds": 86400,
    "createdAt": "2026-07-02T16:20:11.000Z",
    "updatedAt": "2026-09-20T18:42:55.000Z"
  },
  "changed": true,
  "removedRoutes": 2
}

Errors

StatusCodeWhen
400validation_errorstatus is missing or is not one of the four.
402plan_upgrade_requiredRestoring an archived target would take the workspace past the number of targets its plan allows.
409conflictYou are activating a target whose buyer is archived. Restore the buyer first.
401unauthorizedNo session token, or one that has expired.
402subscription_inactiveThe workspace's subscription is not active, and this is a write. details carries status, planId and agencyId.
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_foundNo target with that id in this workspace, or you named a workspace with ?agencyId= that is not yours.

Console API · Test a target

POST/api/tracking/targets/:id/test

Console API. A real check against the buyer, run before you trust a target with live callers. For an rtb target it sends one real bid request through the router's own code and shows you the request, the raw response and how each configured path was read — the fastest way to find a bidPath that points at the wrong field. No auction, bid or call is written, though the target's health counters do move. For a number or sip target it climbs a reachability ladder and stops at the first rung that fails. Nothing is dialled either way. The test is recorded in the activity log.

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.

Path parameters

NameTypeDescription
idRequireduuidThe target's id, as returned by List targets.

Query parameters

NameTypeDescription
agencyIdOptionaluuidThe workspace to act in.

Request body

NameTypeDescription
callerIdOptionalstringA caller's number to put in the bid request. rtb targets.up to 32 characters
stateOptionalstringA two-letter state for the pretend caller. rtb targets.
zipOptionalstringA postal code for the pretend caller. rtb targets.up to 12 characters
tagsOptionalobjectTags to send with the bid request, so a buyer's rules can be exercised. rtb targets.
campaignIdOptionaluuidTest as if the call had arrived on this campaign, so the route's maxBidCents and the campaign's ping timeout apply. It must be a tracking campaign of yours. rtb targets.
levelOptionalenumRun one rung of the ladder instead of all of them. number and sip targets.static, dns, tcp_tls, sip_options, sip_auth, hours, caps · omitted runs the whole ladder: static for a number; static, dns, tcp_tls and sip_options for SIP

Example request

curl -X POST "https://api.buy3.io/api/tracking/targets/c7b6a5d4-e3f2-4a1b-8c9d-0e1f2a3b4c5d/test" \
  -H "Authorization: Bearer $BUY3_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "callerId": "+15555550142",
    "state": "TX",
    "tags": {
      "utm_source": "search"
    }
  }'

Responses

  • 200 (rtb target)What was sent, what came back, and how it was read. passed is true only when the buyer actually bid. Authorization header values are replaced before the request is shown back to you.
  • 200 (number or sip target)One entry per rung that ran, in order, stopping at the first failure. A full SIP ladder also refreshes the target's health badge.
{
  "test": true,
  "type": "rtb",
  "passed": true,
  "status": "bid",
  "request": {
    "method": "POST",
    "url": "https://bids.example.com/v1/ping",
    "headers": {
      "Content-Type": "application/json",
      "X-Api-Key": "«redacted»"
    },
    "body": "{\"callerId\":\"+15555550142\",\"state\":\"TX\"}"
  },
  "response": {
    "httpStatus": 200,
    "latencyMs": 214,
    "body": {
      "bidAmount": 38.5,
      "phoneNumber": "+12145550190",
      "bidTerms": [
        {
          "callMinDuration": 90
        }
      ]
    }
  },
  "parsed": {
    "status": "bid",
    "rawBidCents": 3850,
    "bidCents": 3850,
    "durationSeconds": 90,
    "destinationKind": "did",
    "destinationSip": null,
    "destinationE164": "+12145550190",
    "rejectReason": null
  },
  "note": "The buyer bid 3850 cents and gave a number to send the call to.",
  "target": {
    "id": "c7b6a5d4-e3f2-4a1b-8c9d-0e1f2a3b4c5d",
    "name": "BlueSky Legal — bidder",
    "type": "rtb",
    "kind": "external_rtb",
    "status": "active",
    "externalRef": null,
    "buyerId": "e5d4c3b2-a1f0-4e9d-8c7b-6a5f4e3d2c1b",
    "buyer": {
      "id": "e5d4c3b2-a1f0-4e9d-8c7b-6a5f4e3d2c1b",
      "name": "BlueSky Legal",
      "status": "active"
    },
    "health": "healthy",
    "lastError": null,
    "consecutiveFailures": 0,
    "suppressedUntil": null,
    "revenueCents": null,
    "durationThresholdSeconds": 60,
    "destination": {
      "type": "rtb",
      "value": "bids.example.com",
      "display": "Bids at bids.example.com"
    },
    "endpoint": null,
    "rtb": {
      "preset": "ringba",
      "bidUrl": "https://bids.example.com/v1/ping",
      "bidMethod": "POST",
      "bidContentType": "application/json",
      "bidHeaders": {
        "X-Api-Key": "•••"
      },
      "bidBodyTemplate": "•••",
      "pingTimeoutMs": 1200,
      "authType": "none",
      "authUsername": null,
      "authHeaderName": null,
      "authTokenUrl": null,
      "hasAuthSecret": false,
      "authSecretLast4": null,
      "acceptMode": "http_2xx",
      "acceptPath": null,
      "acceptEquals": null,
      "bidPath": "bidAmount",
      "bidUnit": "dollars",
      "durationPath": "bidTerms.0.callMinDuration",
      "durationOffsetSeconds": 0,
      "destinationPath": "phoneNumber",
      "destinationKind": "did",
      "rejectReasonPath": "rejectReason",
      "minBidCents": 0,
      "maxBidCents": 0,
      "bidMultiplier": null,
      "lastBidAt": "2026-09-20T18:19:55.000Z",
      "lastWinAt": "2026-09-20T18:12:03.000Z"
    },
    "concurrencyCap": 10,
    "hourlyCap": 0,
    "dailyCap": 0,
    "monthlyCap": 0,
    "totalCap": 0,
    "dailyRevenueCapCents": 0,
    "capCountsOn": "converted",
    "usage": {
      "liveCalls": 0,
      "hour": 1,
      "day": 9,
      "month": 188,
      "total": 1042,
      "dayRevenueCents": 41000
    },
    "liveCalls": 0,
    "states": [],
    "timezone": "America/New_York",
    "hoursSchedule": null,
    "dedupeWindowSeconds": 0,
    "createdAt": "2026-08-11T12:00:00.000Z",
    "updatedAt": "2026-09-18T08:31:20.000Z"
  }
}

Errors

StatusCodeWhen
400bad_requestThe target is an rtb target with no bidUrl configured.
400unsafe_urlThe bid URL no longer resolves to a public address. It is re-checked at send time, not only when it was saved.
401unauthorizedNo session token, or one that has expired.
402subscription_inactiveThe workspace's subscription is not active, and this is a write. details carries status, planId and agencyId.
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_foundNo target with that id in this workspace, or you named a workspace with ?agencyId= that is not yours.