Skip to content

Inbound queues ​

Generated from DialerDigital/core commit 0fc18008b3c8 — spec openapi/dialer-v1.yaml v0.134.0. Do not edit by hand; see How this reference is built. Download the OpenAPI spec.

Español

The tenant's inbound queues: created with a name, an optional overflow to another of its queues, retired when nothing uses them. A route with dest_type: queue names one in queue_id; an inbound IVR menu names one as queue:<id>.

Endpoints ​

MethodPathSummary
GET/v1/inbound-queuesThe tenant's active inbound queues, and whether queuing is on
POST/v1/inbound-queuesCreate an inbound queue
GET/v1/inbound-queues/liveHow many calls wait in each active inbound queue, and since when
GET/v1/inbound-queues/{id}One inbound queue, active or retired
GET/v1/inbound-queues/{id}/liveHow many calls wait in one inbound queue, and since when
GET/v1/inbound-queues/{id}/callback-offer/statsHow many callbacks one inbound queue offered and how many were accepted
PUT/v1/inbound-queues/{id}/overflowSet the queue's overflow to another of the tenant's queues
DELETE/v1/inbound-queues/{id}/overflowRemove the queue's overflow
PUT/v1/inbound-queues/{id}/callback-offerSet the wait after which the queue offers a callback
DELETE/v1/inbound-queues/{id}/callback-offerRemove the queue's callback-offer threshold
POST/v1/inbound-queues/{id}/retireRetire an inbound queue
GET/v1/inbound-vip-listsThe debt lists designated as VIP for the inbound queue
PUT/v1/inbound-vip-listsReplace the debt lists designated as VIP for the inbound queue
GET/v1/inbound-queues/{id}/skillsThe skills a queue demands
PUT/v1/inbound-queues/{id}/skillsReplace the skills a queue demands

The tenant's active inbound queues, and whether queuing is on ​

http
GET /v1/inbound-queues

Every queue that is not retired, ordered by name (case-insensitive; a queue created before names existed has name: null and comes last). Each carries its overflow and how many ACTIVE queue routes name it. A retired queue is not listed; GET /v1/inbound-queues/{id} still answers it.

capability says whether the inbound queue admits calls for this tenant, and which switch is missing when it does not (ADR #104 D7 and its core#1354 addendum): it takes TWO switches, both resolved for the tenant — inbound_queue_stream_enabled, the queue's own, and agent_session_journal_enabled, the agent seat journal without which no agent can be offered a call. enabled is true only with both ON; with either OFF, a call to a queue route is not admitted to any queue, is not answered and nobody is offered it, whatever the queue's configuration. This read changes neither switch. Readable by a dd_ key and by any dashboard login; a widget token (ddw_) is 403 forbidden.

Responses

200 ​

The active queues and the capability.

FieldTypeRequiredDescription
inbound_queuesarray of InboundQueueyes
inbound_queues[].idstring (uuid)yes
inbound_queues[].namestring,nullyesnull only for a queue created before names existed (core#1347).
inbound_queues[].statusactive · retiredyes
inbound_queues[].overflow_max_wait_msinteger,nullyesThe wait after which a call moves to overflow_queue_id; null = no overflow.
inbound_queues[].overflow_queue_idstring,null (uuid)yes
inbound_queues[].callback_offer_after_msinteger,nullyesThe MEASURED wait, in milliseconds, after which a caller of this queue would be offered a callback; null = this queue offers none. Alone it offers nothing, because the account's inbound_callback_offer_enabled flag has to be on too (core#1670).
inbound_queues[].active_route_countintegeryesHow many ACTIVE queue routes of the tenant name this queue.
inbound_queues[].created_atstring (date-time)yes
inbound_queues[].retired_atstring,null (date-time)yes
inbound_queues[].retired_bystring,nullyesThe user or agent id of the credential that retired it, or tenant-api-key.
inbound_queues[].required_skillsarray of stringnoThe skills an agent needs to be offered this queue's calls (sorted); [] = demands nothing. Set with PUT /v1/inbound-queues/{id}/skills.
inbound_queues[].warningsarray of required_skills_without_overflownorequired_skills_without_overflow: the queue demands skills and has no overflow, so a call nobody qualifies for waits with no way out (ADR #216 D6).
capabilityobject (InboundQueueCapability)yes
capability.flaginbound_queue_stream_enabledyesThe queue's own switch, the one turned on to turn the queue on.
capability.enabledbooleanyesWhether the inbound queue admits calls for this tenant — true only when BOTH switches are ON (core#1354). false is the default; this API does not change it.
capability.switchesobjectyesEach switch the queue needs, resolved for the tenant. With the queue ON and the seat journal OFF a call to a queue route is refused unanswered, because no agent could ever be offered it.
capability.switches.inbound_queue_stream_enabledbooleanyes
capability.switches.agent_session_journal_enabledbooleanyes

401 — Unauthorized ​

Missing, unknown or revoked API key (or, on /v1/admin/*, a bad/unset admin token; on webhooks, a bad/missing signature). A dashboard session (ddu_) that a newer login of the same person ended answers the code session_superseded instead (tenant flag single_session_enforced), so the screen can say why it was signed out; a logout, an expired or an unknown token stay unauthorized.

json
{
  "error": {
    "code": "unauthorized",
    "message": "invalid or revoked API key"
  }
}

403 — Forbidden ​

The tenant is suspended. A dashboard session (ddu_) of a tenant whose login policy (ADR 227) is in mode enforce answers 403 with the code login_policy_denied on a request from an address or at an hour the policy does not allow — the same body for both; the session is not revoked and a later request inside the policy goes through. A widget token (ddw_) of a seat is held to the same policy on every request (core#2406, flag widget_login_honors_policy). A synthetic (demo) tenant answers 403 with the code synthetic_tenant on every route that would reach a third party — manual dial, external transfer or conference leg, SMS send (core#2251, ADR #280 addendum). No payment changes it.

json
{
  "error": {
    "code": "forbidden",
    "message": "tenant is suspended"
  }
}

429 — ApiKeyRateLimited ​

This API key is over its request quota, or the tenant's keys together are over the tenant ceiling (core#2503) (code rate_limited). The request was not processed. Wait Retry-After seconds and retry; a refusal is not counted against the budget, so that wait is always enough. Bounded per API key and, above the keys, per tenant (api_tenant_requests_per_minute): a sibling key is unaffected until the tenant's keys together reach that ceiling. The quota applies to every operation reachable with a dd_ key, so the operations that name a more specific 429 (call control, dispositions, SMS, …) can ALSO answer this one with its X-RateLimit-* headers.

json
{
  "error": {
    "code": "rate_limited",
    "message": "API key request quota exceeded; retry after the interval in Retry-After"
  }
}

Create an inbound queue ​

http
POST /v1/inbound-queues

Creates an active queue named name, with no overflow. The name is trimmed and must be unique among this tenant's ACTIVE queues without regard to case (409 conflict otherwise); a retired queue's name is free again. A queue is never renamed.

Tenant management only: a dd_ key or an account_admin login. A member login is 403 role_forbidden; a widget token (ddw_) is 403 forbidden.

Request body (JSON, required)

FieldTypeRequiredDescription
namestringyesThe queue's name, for the operator (trimmed; blank is refused).
json
{
  "name": "Sales"
}

Responses

201 ​

Created.

FieldTypeRequiredDescription
inbound_queueobject (InboundQueue)yes
inbound_queue.idstring (uuid)yes
inbound_queue.namestring,nullyesnull only for a queue created before names existed (core#1347).
inbound_queue.statusactive · retiredyes
inbound_queue.overflow_max_wait_msinteger,nullyesThe wait after which a call moves to overflow_queue_id; null = no overflow.
inbound_queue.overflow_queue_idstring,null (uuid)yes
inbound_queue.callback_offer_after_msinteger,nullyesThe MEASURED wait, in milliseconds, after which a caller of this queue would be offered a callback; null = this queue offers none. Alone it offers nothing, because the account's inbound_callback_offer_enabled flag has to be on too (core#1670).
inbound_queue.active_route_countintegeryesHow many ACTIVE queue routes of the tenant name this queue.
inbound_queue.created_atstring (date-time)yes
inbound_queue.retired_atstring,null (date-time)yes
inbound_queue.retired_bystring,nullyesThe user or agent id of the credential that retired it, or tenant-api-key.
inbound_queue.required_skillsarray of stringnoThe skills an agent needs to be offered this queue's calls (sorted); [] = demands nothing. Set with PUT /v1/inbound-queues/{id}/skills.
inbound_queue.warningsarray of required_skills_without_overflownorequired_skills_without_overflow: the queue demands skills and has no overflow, so a call nobody qualifies for waits with no way out (ADR #216 D6).

400 — BadRequest ​

Malformed request (shape/type errors, invalid filters, bad timestamps).

json
{
  "error": {
    "code": "bad_request",
    "message": "from must be RFC-3339"
  }
}

401 — Unauthorized ​

Missing, unknown or revoked API key (or, on /v1/admin/*, a bad/unset admin token; on webhooks, a bad/missing signature). A dashboard session (ddu_) that a newer login of the same person ended answers the code session_superseded instead (tenant flag single_session_enforced), so the screen can say why it was signed out; a logout, an expired or an unknown token stay unauthorized.

json
{
  "error": {
    "code": "unauthorized",
    "message": "invalid or revoked API key"
  }
}

403 ​

role_forbidden: a dashboard login without the account_admin role; forbidden: a widget token or a suspended tenant.

json
{
  "error": {
    "code": "role_forbidden",
    "message": "a dashboard login needs the account_admin role to manage inbound queues"
  }
}

409 — Conflict ​

Invalid state transition, uniqueness conflict, or a seat that is busy/reserved.

json
{
  "error": {
    "code": "conflict",
    "message": "invalid state transition"
  }
}

429 — ApiKeyRateLimited ​

This API key is over its request quota, or the tenant's keys together are over the tenant ceiling (core#2503) (code rate_limited). The request was not processed. Wait Retry-After seconds and retry; a refusal is not counted against the budget, so that wait is always enough. Bounded per API key and, above the keys, per tenant (api_tenant_requests_per_minute): a sibling key is unaffected until the tenant's keys together reach that ceiling. The quota applies to every operation reachable with a dd_ key, so the operations that name a more specific 429 (call control, dispositions, SMS, …) can ALSO answer this one with its X-RateLimit-* headers.

json
{
  "error": {
    "code": "rate_limited",
    "message": "API key request quota exceeded; retry after the interval in Retry-After"
  }
}

How many calls wait in each active inbound queue, and since when ​

http
GET /v1/inbound-queues/live

The live state of every ACTIVE inbound queue of the tenant (core#1526): depth — the calls waiting now — and oldest_wait_ms — how long the longest-waiting one has waited. Both are DERIVED from the append-only queue stream, never from a counter: a call is waiting while its enqueued has no terminal (answered, abandoned, overflowed, callback_booked). A call that is being offered to an agent is still waiting and counts. A call that overflows to another queue stops counting here and counts in the destination, where its wait starts at the overflow.

Off is not zero. With the tenant's inbound_queue_stream_enabled OFF nobody writes the stream, so there is nothing to count: stream_enabled is false and depth and oldest_wait_ms are null — never 0. depth: 0 means the queue is on and empty, and then oldest_wait_ms is null too.

Orphans do not inflate it. A crash between the enqueued and its terminal leaves an admission nobody closes. An admission older than wait_bound_ms is read as orphaned and left out of both numbers: wait_bound_ms is the queue's overflow_max_wait_ms (the same limit its overflow uses) and, for a queue with no overflow configured, a fixed ceiling of one hour. The stream is append-only; nothing is closed, the read just stops counting it.

oldest_wait_ms is a live read taken with the wall clock (as_of minus the enqueued instant, never below 0), not the measured wait_duration_ms that history and reports use. ready_agents is the tenant-wide count of agents in Ready now (the agents are not per-queue), null when the agent seat journal is OFF. Readable by a dd_ key and by any dashboard login; a widget token (ddw_) is 403 forbidden.

VIP and skills (core#1677). Per queue, vip_depth and vip_oldest_wait_ms are the same two numbers counted over the VIP calls only (admissions sealed vip). They are null — never 0 — while the VIP is not active for the tenant (inbound_queue_vip_head_start_ms at 0, or inert because the head start reaches the service threshold) and while the queue stream is OFF; with the VIP active and no VIP waiting, vip_depth is 0 and vip_oldest_wait_ms is null. ready_matching is how many Ready agents meet THAT queue's skill requirement; it is null when the queue requires no skills, skill routing is OFF, the seat journal is OFF, or the skills could not be read. It counts the Ready agents of the journal, without discounting those already holding a live offer.

Responses

200 ​

The live state of the active queues.

FieldTypeRequiredDescription
as_ofstring (date-time)yesThe instant the read was taken.
stream_enabledbooleanyesfalse = the queue stream is OFF for the tenant: depth is unknown, not zero.
ready_agentsinteger,nullyesAgents in Ready now, tenant-wide; null when the seat journal is OFF.
inbound_queuesarray of InboundQueueLiveyes
inbound_queues[].queue_idstring (uuid)yes
inbound_queues[].namestring,nullyes
inbound_queues[].depthinteger,nullyesCalls waiting now (admissions with no terminal, inside wait_bound_ms). null when the tenant's queue stream is OFF — unknown, never 0.
inbound_queues[].oldest_wait_msinteger,nullyesHow long the longest-waiting call has waited, by the wall clock. null when depth is null or 0.
inbound_queues[].vip_depthinteger,nullyesOf depth, the VIP calls (admissions sealed vip). null while the VIP is not active (inbound_queue_vip_head_start_ms at 0, or inert) or the queue stream is OFF — never 0; 0 means the VIP is active and none waits.
inbound_queues[].vip_oldest_wait_msinteger,nullyesHow long the longest-waiting VIP call has waited, by the wall clock. null when vip_depth is null or 0.
inbound_queues[].ready_matchinginteger,nullyesHow many Ready agents meet THIS queue's skill requirement (all of them). null when the queue requires no skills, skill routing is OFF, the seat journal is OFF, or the skills could not be read — never 0 for "not measured". Counts Ready agents without discounting those already holding a live offer.
inbound_queues[].wait_bound_msintegeryesThe age past which an admission without a terminal is read as orphaned and left out. The queue's overflow_max_wait_ms when set; otherwise 3600000 (one hour).

401 — Unauthorized ​

Missing, unknown or revoked API key (or, on /v1/admin/*, a bad/unset admin token; on webhooks, a bad/missing signature). A dashboard session (ddu_) that a newer login of the same person ended answers the code session_superseded instead (tenant flag single_session_enforced), so the screen can say why it was signed out; a logout, an expired or an unknown token stay unauthorized.

json
{
  "error": {
    "code": "unauthorized",
    "message": "invalid or revoked API key"
  }
}

403 — Forbidden ​

The tenant is suspended. A dashboard session (ddu_) of a tenant whose login policy (ADR 227) is in mode enforce answers 403 with the code login_policy_denied on a request from an address or at an hour the policy does not allow — the same body for both; the session is not revoked and a later request inside the policy goes through. A widget token (ddw_) of a seat is held to the same policy on every request (core#2406, flag widget_login_honors_policy). A synthetic (demo) tenant answers 403 with the code synthetic_tenant on every route that would reach a third party — manual dial, external transfer or conference leg, SMS send (core#2251, ADR #280 addendum). No payment changes it.

json
{
  "error": {
    "code": "forbidden",
    "message": "tenant is suspended"
  }
}

429 — ApiKeyRateLimited ​

This API key is over its request quota, or the tenant's keys together are over the tenant ceiling (core#2503) (code rate_limited). The request was not processed. Wait Retry-After seconds and retry; a refusal is not counted against the budget, so that wait is always enough. Bounded per API key and, above the keys, per tenant (api_tenant_requests_per_minute): a sibling key is unaffected until the tenant's keys together reach that ceiling. The quota applies to every operation reachable with a dd_ key, so the operations that name a more specific 429 (call control, dispositions, SMS, …) can ALSO answer this one with its X-RateLimit-* headers.

json
{
  "error": {
    "code": "rate_limited",
    "message": "API key request quota exceeded; retry after the interval in Retry-After"
  }
}

One inbound queue, active or retired ​

http
GET /v1/inbound-queues/{id}

The queue — with status: retired once retired — and the tenant's capability, as in the list. A queue that is not this tenant's (or does not exist) is 404. Same readers as the list.

Parameters

NameInTypeRequiredDescription
idpathstring (uuid)yesResource UUID. Malformed or cross-tenant ids read as 404.

Responses

200 ​

The queue.

FieldTypeRequiredDescription
inbound_queueobject (InboundQueue)yes
inbound_queue.idstring (uuid)yes
inbound_queue.namestring,nullyesnull only for a queue created before names existed (core#1347).
inbound_queue.statusactive · retiredyes
inbound_queue.overflow_max_wait_msinteger,nullyesThe wait after which a call moves to overflow_queue_id; null = no overflow.
inbound_queue.overflow_queue_idstring,null (uuid)yes
inbound_queue.callback_offer_after_msinteger,nullyesThe MEASURED wait, in milliseconds, after which a caller of this queue would be offered a callback; null = this queue offers none. Alone it offers nothing, because the account's inbound_callback_offer_enabled flag has to be on too (core#1670).
inbound_queue.active_route_countintegeryesHow many ACTIVE queue routes of the tenant name this queue.
inbound_queue.created_atstring (date-time)yes
inbound_queue.retired_atstring,null (date-time)yes
inbound_queue.retired_bystring,nullyesThe user or agent id of the credential that retired it, or tenant-api-key.
inbound_queue.required_skillsarray of stringnoThe skills an agent needs to be offered this queue's calls (sorted); [] = demands nothing. Set with PUT /v1/inbound-queues/{id}/skills.
inbound_queue.warningsarray of required_skills_without_overflownorequired_skills_without_overflow: the queue demands skills and has no overflow, so a call nobody qualifies for waits with no way out (ADR #216 D6).
capabilityobject (InboundQueueCapability)yes
capability.flaginbound_queue_stream_enabledyesThe queue's own switch, the one turned on to turn the queue on.
capability.enabledbooleanyesWhether the inbound queue admits calls for this tenant — true only when BOTH switches are ON (core#1354). false is the default; this API does not change it.
capability.switchesobjectyesEach switch the queue needs, resolved for the tenant. With the queue ON and the seat journal OFF a call to a queue route is refused unanswered, because no agent could ever be offered it.
capability.switches.inbound_queue_stream_enabledbooleanyes
capability.switches.agent_session_journal_enabledbooleanyes

401 — Unauthorized ​

Missing, unknown or revoked API key (or, on /v1/admin/*, a bad/unset admin token; on webhooks, a bad/missing signature). A dashboard session (ddu_) that a newer login of the same person ended answers the code session_superseded instead (tenant flag single_session_enforced), so the screen can say why it was signed out; a logout, an expired or an unknown token stay unauthorized.

json
{
  "error": {
    "code": "unauthorized",
    "message": "invalid or revoked API key"
  }
}

403 — Forbidden ​

The tenant is suspended. A dashboard session (ddu_) of a tenant whose login policy (ADR 227) is in mode enforce answers 403 with the code login_policy_denied on a request from an address or at an hour the policy does not allow — the same body for both; the session is not revoked and a later request inside the policy goes through. A widget token (ddw_) of a seat is held to the same policy on every request (core#2406, flag widget_login_honors_policy). A synthetic (demo) tenant answers 403 with the code synthetic_tenant on every route that would reach a third party — manual dial, external transfer or conference leg, SMS send (core#2251, ADR #280 addendum). No payment changes it.

json
{
  "error": {
    "code": "forbidden",
    "message": "tenant is suspended"
  }
}

404 — NotFound ​

Unknown id, malformed (non-UUID) id OR another tenant's id — RLS returns zero rows, so all three are indistinguishable by design (no existence leak, never a 403 for foreign ids).

json
{
  "error": {
    "code": "not_found",
    "message": "resource not found for this tenant"
  }
}

429 — ApiKeyRateLimited ​

This API key is over its request quota, or the tenant's keys together are over the tenant ceiling (core#2503) (code rate_limited). The request was not processed. Wait Retry-After seconds and retry; a refusal is not counted against the budget, so that wait is always enough. Bounded per API key and, above the keys, per tenant (api_tenant_requests_per_minute): a sibling key is unaffected until the tenant's keys together reach that ceiling. The quota applies to every operation reachable with a dd_ key, so the operations that name a more specific 429 (call control, dispositions, SMS, …) can ALSO answer this one with its X-RateLimit-* headers.

json
{
  "error": {
    "code": "rate_limited",
    "message": "API key request quota exceeded; retry after the interval in Retry-After"
  }
}

How many calls wait in one inbound queue, and since when ​

http
GET /v1/inbound-queues/{id}/live

The same live read as GET /v1/inbound-queues/live, for one queue (same rules: derived from the stream, off is null and not 0, orphans past wait_bound_ms left out). A queue that is not this tenant's, does not exist or is retired is 404: a retired queue admits nobody, so there is nothing live to read. Same readers.

Parameters

NameInTypeRequiredDescription
idpathstring (uuid)yesResource UUID. Malformed or cross-tenant ids read as 404.

Responses

200 ​

The live state of the queue.

FieldTypeRequiredDescription
as_ofstring (date-time)yes
stream_enabledbooleanyes
ready_agentsinteger,nullyes
inbound_queueobject (InboundQueueLive)yes
inbound_queue.queue_idstring (uuid)yes
inbound_queue.namestring,nullyes
inbound_queue.depthinteger,nullyesCalls waiting now (admissions with no terminal, inside wait_bound_ms). null when the tenant's queue stream is OFF — unknown, never 0.
inbound_queue.oldest_wait_msinteger,nullyesHow long the longest-waiting call has waited, by the wall clock. null when depth is null or 0.
inbound_queue.vip_depthinteger,nullyesOf depth, the VIP calls (admissions sealed vip). null while the VIP is not active (inbound_queue_vip_head_start_ms at 0, or inert) or the queue stream is OFF — never 0; 0 means the VIP is active and none waits.
inbound_queue.vip_oldest_wait_msinteger,nullyesHow long the longest-waiting VIP call has waited, by the wall clock. null when vip_depth is null or 0.
inbound_queue.ready_matchinginteger,nullyesHow many Ready agents meet THIS queue's skill requirement (all of them). null when the queue requires no skills, skill routing is OFF, the seat journal is OFF, or the skills could not be read — never 0 for "not measured". Counts Ready agents without discounting those already holding a live offer.
inbound_queue.wait_bound_msintegeryesThe age past which an admission without a terminal is read as orphaned and left out. The queue's overflow_max_wait_ms when set; otherwise 3600000 (one hour).

401 — Unauthorized ​

Missing, unknown or revoked API key (or, on /v1/admin/*, a bad/unset admin token; on webhooks, a bad/missing signature). A dashboard session (ddu_) that a newer login of the same person ended answers the code session_superseded instead (tenant flag single_session_enforced), so the screen can say why it was signed out; a logout, an expired or an unknown token stay unauthorized.

json
{
  "error": {
    "code": "unauthorized",
    "message": "invalid or revoked API key"
  }
}

403 — Forbidden ​

The tenant is suspended. A dashboard session (ddu_) of a tenant whose login policy (ADR 227) is in mode enforce answers 403 with the code login_policy_denied on a request from an address or at an hour the policy does not allow — the same body for both; the session is not revoked and a later request inside the policy goes through. A widget token (ddw_) of a seat is held to the same policy on every request (core#2406, flag widget_login_honors_policy). A synthetic (demo) tenant answers 403 with the code synthetic_tenant on every route that would reach a third party — manual dial, external transfer or conference leg, SMS send (core#2251, ADR #280 addendum). No payment changes it.

json
{
  "error": {
    "code": "forbidden",
    "message": "tenant is suspended"
  }
}

404 — NotFound ​

Unknown id, malformed (non-UUID) id OR another tenant's id — RLS returns zero rows, so all three are indistinguishable by design (no existence leak, never a 403 for foreign ids).

json
{
  "error": {
    "code": "not_found",
    "message": "resource not found for this tenant"
  }
}

429 — ApiKeyRateLimited ​

This API key is over its request quota, or the tenant's keys together are over the tenant ceiling (core#2503) (code rate_limited). The request was not processed. Wait Retry-After seconds and retry; a refusal is not counted against the budget, so that wait is always enough. Bounded per API key and, above the keys, per tenant (api_tenant_requests_per_minute): a sibling key is unaffected until the tenant's keys together reach that ceiling. The quota applies to every operation reachable with a dd_ key, so the operations that name a more specific 429 (call control, dispositions, SMS, …) can ALSO answer this one with its X-RateLimit-* headers.

json
{
  "error": {
    "code": "rate_limited",
    "message": "API key request quota exceeded; retry after the interval in Retry-After"
  }
}

How many callbacks one inbound queue offered and how many were accepted ​

http
GET /v1/inbound-queues/{id}/callback-offer/stats

The callback offers made in [from, to) on one queue and how each ended (ADR #215 addendum, core#1884). Derived from the append-only queue stream (callback_offered, callback_booked and the other terminal events); nothing is accumulated. The cohort is the offers made in the window, so offered = accepted + declined_or_abandoned + open always:

  • accepted: the caller took the callback (a callback_booked closed the admission), even if it happened after to.
  • declined_or_abandoned: the admission closed any other way (answered, abandoned or overflowed) without a booking.
  • open: the admission has not closed yet.

Both from and to are required (RFC-3339). 400 when one is missing or malformed or from is not before to; 422 when the window is longer than 31 days. A queue that is not this tenant's or does not exist is 404; a retired queue keeps its history readable. Same readers as the other inbound-queue reads.

Parameters

NameInTypeRequiredDescription
idpathstring (uuid)yesResource UUID. Malformed or cross-tenant ids read as 404.
fromquerystring (date-time)yesStart of the window, inclusive.
toquerystring (date-time)yesEnd of the window, exclusive. At most 31 days after from.

Responses

200 ​

The counts for the window.

FieldTypeRequiredDescription
inbound_queue_idstring (uuid)yes
fromstring (date-time)yes
tostring (date-time)yes
callback_offerobjectyes
callback_offer.offeredintegeryes
callback_offer.acceptedintegeryes
callback_offer.declined_or_abandonedintegeryes
callback_offer.openintegeryes
json
{
  "inbound_queue_id": "0b6f5f8e-3f5c-4d0e-9a53-6a2f1f6a1c11",
  "from": "2026-10-01T00:00:00Z",
  "to": "2026-10-02T00:00:00Z",
  "callback_offer": {
    "offered": 6,
    "accepted": 2,
    "declined_or_abandoned": 3,
    "open": 1
  }
}

400 — BadRequest ​

Malformed request (shape/type errors, invalid filters, bad timestamps).

json
{
  "error": {
    "code": "bad_request",
    "message": "from must be RFC-3339"
  }
}

401 — Unauthorized ​

Missing, unknown or revoked API key (or, on /v1/admin/*, a bad/unset admin token; on webhooks, a bad/missing signature). A dashboard session (ddu_) that a newer login of the same person ended answers the code session_superseded instead (tenant flag single_session_enforced), so the screen can say why it was signed out; a logout, an expired or an unknown token stay unauthorized.

json
{
  "error": {
    "code": "unauthorized",
    "message": "invalid or revoked API key"
  }
}

403 — Forbidden ​

The tenant is suspended. A dashboard session (ddu_) of a tenant whose login policy (ADR 227) is in mode enforce answers 403 with the code login_policy_denied on a request from an address or at an hour the policy does not allow — the same body for both; the session is not revoked and a later request inside the policy goes through. A widget token (ddw_) of a seat is held to the same policy on every request (core#2406, flag widget_login_honors_policy). A synthetic (demo) tenant answers 403 with the code synthetic_tenant on every route that would reach a third party — manual dial, external transfer or conference leg, SMS send (core#2251, ADR #280 addendum). No payment changes it.

json
{
  "error": {
    "code": "forbidden",
    "message": "tenant is suspended"
  }
}

404 — NotFound ​

Unknown id, malformed (non-UUID) id OR another tenant's id — RLS returns zero rows, so all three are indistinguishable by design (no existence leak, never a 403 for foreign ids).

json
{
  "error": {
    "code": "not_found",
    "message": "resource not found for this tenant"
  }
}

422 — Unprocessable ​

Shape is fine, semantics are not (broken domain rule).

json
{
  "error": {
    "code": "unprocessable",
    "message": "scheduled_at is closer than the minimum notice for a callback (10 minutes unless the tenant's callback_min_notice_seconds says otherwise)"
  }
}

429 — ApiKeyRateLimited ​

This API key is over its request quota, or the tenant's keys together are over the tenant ceiling (core#2503) (code rate_limited). The request was not processed. Wait Retry-After seconds and retry; a refusal is not counted against the budget, so that wait is always enough. Bounded per API key and, above the keys, per tenant (api_tenant_requests_per_minute): a sibling key is unaffected until the tenant's keys together reach that ceiling. The quota applies to every operation reachable with a dd_ key, so the operations that name a more specific 429 (call control, dispositions, SMS, …) can ALSO answer this one with its X-RateLimit-* headers.

json
{
  "error": {
    "code": "rate_limited",
    "message": "API key request quota exceeded; retry after the interval in Retry-After"
  }
}

Set the queue's overflow to another of the tenant's queues ​

http
PUT /v1/inbound-queues/{id}/overflow

A call that has waited overflow_max_wait_ms in this queue moves to the queue overflow_queue_id (ADR #104 FASE 2c: the only overflow there is). Both fields are required. 400 invalid when the maximum is not a positive integer, when the destination is this same queue, is not an ACTIVE queue of this tenant (retired, another tenant's, one that does not exist, malformed), or already overflows — directly or through other queues — back to this one: an overflow cycle is refused. A queue that is not an active queue of this tenant is 404. Same roles as creating.

Parameters

NameInTypeRequiredDescription
idpathstring (uuid)yesResource UUID. Malformed or cross-tenant ids read as 404.

Request body (JSON, required)

FieldTypeRequiredDescription
overflow_max_wait_msintegeryes
overflow_queue_idstring (uuid)yes
json
{
  "overflow_max_wait_ms": 120000,
  "overflow_queue_id": "6f1c1b7e-2d7a-4c1e-9d3a-0b5e8f7a1c21"
}

Responses

200 ​

The queue with its overflow.

FieldTypeRequiredDescription
inbound_queueobject (InboundQueue)yes
inbound_queue.idstring (uuid)yes
inbound_queue.namestring,nullyesnull only for a queue created before names existed (core#1347).
inbound_queue.statusactive · retiredyes
inbound_queue.overflow_max_wait_msinteger,nullyesThe wait after which a call moves to overflow_queue_id; null = no overflow.
inbound_queue.overflow_queue_idstring,null (uuid)yes
inbound_queue.callback_offer_after_msinteger,nullyesThe MEASURED wait, in milliseconds, after which a caller of this queue would be offered a callback; null = this queue offers none. Alone it offers nothing, because the account's inbound_callback_offer_enabled flag has to be on too (core#1670).
inbound_queue.active_route_countintegeryesHow many ACTIVE queue routes of the tenant name this queue.
inbound_queue.created_atstring (date-time)yes
inbound_queue.retired_atstring,null (date-time)yes
inbound_queue.retired_bystring,nullyesThe user or agent id of the credential that retired it, or tenant-api-key.
inbound_queue.required_skillsarray of stringnoThe skills an agent needs to be offered this queue's calls (sorted); [] = demands nothing. Set with PUT /v1/inbound-queues/{id}/skills.
inbound_queue.warningsarray of required_skills_without_overflownorequired_skills_without_overflow: the queue demands skills and has no overflow, so a call nobody qualifies for waits with no way out (ADR #216 D6).

400 — BadRequest ​

Malformed request (shape/type errors, invalid filters, bad timestamps).

json
{
  "error": {
    "code": "bad_request",
    "message": "from must be RFC-3339"
  }
}

401 — Unauthorized ​

Missing, unknown or revoked API key (or, on /v1/admin/*, a bad/unset admin token; on webhooks, a bad/missing signature). A dashboard session (ddu_) that a newer login of the same person ended answers the code session_superseded instead (tenant flag single_session_enforced), so the screen can say why it was signed out; a logout, an expired or an unknown token stay unauthorized.

json
{
  "error": {
    "code": "unauthorized",
    "message": "invalid or revoked API key"
  }
}

403 ​

role_forbidden: a dashboard login without the account_admin role; forbidden: a widget token or a suspended tenant.

404 — NotFound ​

Unknown id, malformed (non-UUID) id OR another tenant's id — RLS returns zero rows, so all three are indistinguishable by design (no existence leak, never a 403 for foreign ids).

json
{
  "error": {
    "code": "not_found",
    "message": "resource not found for this tenant"
  }
}

429 — ApiKeyRateLimited ​

This API key is over its request quota, or the tenant's keys together are over the tenant ceiling (core#2503) (code rate_limited). The request was not processed. Wait Retry-After seconds and retry; a refusal is not counted against the budget, so that wait is always enough. Bounded per API key and, above the keys, per tenant (api_tenant_requests_per_minute): a sibling key is unaffected until the tenant's keys together reach that ceiling. The quota applies to every operation reachable with a dd_ key, so the operations that name a more specific 429 (call control, dispositions, SMS, …) can ALSO answer this one with its X-RateLimit-* headers.

json
{
  "error": {
    "code": "rate_limited",
    "message": "API key request quota exceeded; retry after the interval in Retry-After"
  }
}

Remove the queue's overflow ​

http
DELETE /v1/inbound-queues/{id}/overflow

Both overflow fields back to null: a call waits in this queue as long as it takes. A queue that is not an active queue of this tenant is 404. Same roles as creating. No body.

Parameters

NameInTypeRequiredDescription
idpathstring (uuid)yesResource UUID. Malformed or cross-tenant ids read as 404.

Responses

200 ​

The queue without overflow.

FieldTypeRequiredDescription
inbound_queueobject (InboundQueue)yes
inbound_queue.idstring (uuid)yes
inbound_queue.namestring,nullyesnull only for a queue created before names existed (core#1347).
inbound_queue.statusactive · retiredyes
inbound_queue.overflow_max_wait_msinteger,nullyesThe wait after which a call moves to overflow_queue_id; null = no overflow.
inbound_queue.overflow_queue_idstring,null (uuid)yes
inbound_queue.callback_offer_after_msinteger,nullyesThe MEASURED wait, in milliseconds, after which a caller of this queue would be offered a callback; null = this queue offers none. Alone it offers nothing, because the account's inbound_callback_offer_enabled flag has to be on too (core#1670).
inbound_queue.active_route_countintegeryesHow many ACTIVE queue routes of the tenant name this queue.
inbound_queue.created_atstring (date-time)yes
inbound_queue.retired_atstring,null (date-time)yes
inbound_queue.retired_bystring,nullyesThe user or agent id of the credential that retired it, or tenant-api-key.
inbound_queue.required_skillsarray of stringnoThe skills an agent needs to be offered this queue's calls (sorted); [] = demands nothing. Set with PUT /v1/inbound-queues/{id}/skills.
inbound_queue.warningsarray of required_skills_without_overflownorequired_skills_without_overflow: the queue demands skills and has no overflow, so a call nobody qualifies for waits with no way out (ADR #216 D6).

401 — Unauthorized ​

Missing, unknown or revoked API key (or, on /v1/admin/*, a bad/unset admin token; on webhooks, a bad/missing signature). A dashboard session (ddu_) that a newer login of the same person ended answers the code session_superseded instead (tenant flag single_session_enforced), so the screen can say why it was signed out; a logout, an expired or an unknown token stay unauthorized.

json
{
  "error": {
    "code": "unauthorized",
    "message": "invalid or revoked API key"
  }
}

403 ​

role_forbidden: a dashboard login without the account_admin role; forbidden: a widget token or a suspended tenant.

404 — NotFound ​

Unknown id, malformed (non-UUID) id OR another tenant's id — RLS returns zero rows, so all three are indistinguishable by design (no existence leak, never a 403 for foreign ids).

json
{
  "error": {
    "code": "not_found",
    "message": "resource not found for this tenant"
  }
}

429 — ApiKeyRateLimited ​

This API key is over its request quota, or the tenant's keys together are over the tenant ceiling (core#2503) (code rate_limited). The request was not processed. Wait Retry-After seconds and retry; a refusal is not counted against the budget, so that wait is always enough. Bounded per API key and, above the keys, per tenant (api_tenant_requests_per_minute): a sibling key is unaffected until the tenant's keys together reach that ceiling. The quota applies to every operation reachable with a dd_ key, so the operations that name a more specific 429 (call control, dispositions, SMS, …) can ALSO answer this one with its X-RateLimit-* headers.

json
{
  "error": {
    "code": "rate_limited",
    "message": "API key request quota exceeded; retry after the interval in Retry-After"
  }
}

Set the wait after which the queue offers a callback ​

http
PUT /v1/inbound-queues/{id}/callback-offer

Sets callback_offer_after_ms, the MEASURED wait in this queue after which a caller would be offered a callback instead of waiting on (ADR #215, core#1636). The field is required. 400 invalid when it is not an integer from 1 to 9223372036854775807. A queue that is not an active queue of this tenant is 404. Same roles as creating.

This only stores the threshold: nothing is offered until the account's inbound_callback_offer_enabled flag is on and the offer itself ships.

Parameters

NameInTypeRequiredDescription
idpathstring (uuid)yesResource UUID. Malformed or cross-tenant ids read as 404.

Request body (JSON, required)

FieldTypeRequiredDescription
callback_offer_after_msintegeryes
json
{
  "callback_offer_after_ms": 90000
}

Responses

200 ​

The queue with its callback-offer threshold.

FieldTypeRequiredDescription
inbound_queueobject (InboundQueue)yes
inbound_queue.idstring (uuid)yes
inbound_queue.namestring,nullyesnull only for a queue created before names existed (core#1347).
inbound_queue.statusactive · retiredyes
inbound_queue.overflow_max_wait_msinteger,nullyesThe wait after which a call moves to overflow_queue_id; null = no overflow.
inbound_queue.overflow_queue_idstring,null (uuid)yes
inbound_queue.callback_offer_after_msinteger,nullyesThe MEASURED wait, in milliseconds, after which a caller of this queue would be offered a callback; null = this queue offers none. Alone it offers nothing, because the account's inbound_callback_offer_enabled flag has to be on too (core#1670).
inbound_queue.active_route_countintegeryesHow many ACTIVE queue routes of the tenant name this queue.
inbound_queue.created_atstring (date-time)yes
inbound_queue.retired_atstring,null (date-time)yes
inbound_queue.retired_bystring,nullyesThe user or agent id of the credential that retired it, or tenant-api-key.
inbound_queue.required_skillsarray of stringnoThe skills an agent needs to be offered this queue's calls (sorted); [] = demands nothing. Set with PUT /v1/inbound-queues/{id}/skills.
inbound_queue.warningsarray of required_skills_without_overflownorequired_skills_without_overflow: the queue demands skills and has no overflow, so a call nobody qualifies for waits with no way out (ADR #216 D6).

400 — BadRequest ​

Malformed request (shape/type errors, invalid filters, bad timestamps).

json
{
  "error": {
    "code": "bad_request",
    "message": "from must be RFC-3339"
  }
}

401 — Unauthorized ​

Missing, unknown or revoked API key (or, on /v1/admin/*, a bad/unset admin token; on webhooks, a bad/missing signature). A dashboard session (ddu_) that a newer login of the same person ended answers the code session_superseded instead (tenant flag single_session_enforced), so the screen can say why it was signed out; a logout, an expired or an unknown token stay unauthorized.

json
{
  "error": {
    "code": "unauthorized",
    "message": "invalid or revoked API key"
  }
}

403 ​

role_forbidden: a dashboard login without the account_admin role; forbidden: a widget token or a suspended tenant.

404 — NotFound ​

Unknown id, malformed (non-UUID) id OR another tenant's id — RLS returns zero rows, so all three are indistinguishable by design (no existence leak, never a 403 for foreign ids).

json
{
  "error": {
    "code": "not_found",
    "message": "resource not found for this tenant"
  }
}

429 — ApiKeyRateLimited ​

This API key is over its request quota, or the tenant's keys together are over the tenant ceiling (core#2503) (code rate_limited). The request was not processed. Wait Retry-After seconds and retry; a refusal is not counted against the budget, so that wait is always enough. Bounded per API key and, above the keys, per tenant (api_tenant_requests_per_minute): a sibling key is unaffected until the tenant's keys together reach that ceiling. The quota applies to every operation reachable with a dd_ key, so the operations that name a more specific 429 (call control, dispositions, SMS, …) can ALSO answer this one with its X-RateLimit-* headers.

json
{
  "error": {
    "code": "rate_limited",
    "message": "API key request quota exceeded; retry after the interval in Retry-After"
  }
}

Remove the queue's callback-offer threshold ​

http
DELETE /v1/inbound-queues/{id}/callback-offer

callback_offer_after_ms back to null: this queue offers no callback. A queue that is not an active queue of this tenant is 404. Same roles as creating. No body.

Parameters

NameInTypeRequiredDescription
idpathstring (uuid)yesResource UUID. Malformed or cross-tenant ids read as 404.

Responses

200 ​

The queue without a callback-offer threshold.

FieldTypeRequiredDescription
inbound_queueobject (InboundQueue)yes
inbound_queue.idstring (uuid)yes
inbound_queue.namestring,nullyesnull only for a queue created before names existed (core#1347).
inbound_queue.statusactive · retiredyes
inbound_queue.overflow_max_wait_msinteger,nullyesThe wait after which a call moves to overflow_queue_id; null = no overflow.
inbound_queue.overflow_queue_idstring,null (uuid)yes
inbound_queue.callback_offer_after_msinteger,nullyesThe MEASURED wait, in milliseconds, after which a caller of this queue would be offered a callback; null = this queue offers none. Alone it offers nothing, because the account's inbound_callback_offer_enabled flag has to be on too (core#1670).
inbound_queue.active_route_countintegeryesHow many ACTIVE queue routes of the tenant name this queue.
inbound_queue.created_atstring (date-time)yes
inbound_queue.retired_atstring,null (date-time)yes
inbound_queue.retired_bystring,nullyesThe user or agent id of the credential that retired it, or tenant-api-key.
inbound_queue.required_skillsarray of stringnoThe skills an agent needs to be offered this queue's calls (sorted); [] = demands nothing. Set with PUT /v1/inbound-queues/{id}/skills.
inbound_queue.warningsarray of required_skills_without_overflownorequired_skills_without_overflow: the queue demands skills and has no overflow, so a call nobody qualifies for waits with no way out (ADR #216 D6).

401 — Unauthorized ​

Missing, unknown or revoked API key (or, on /v1/admin/*, a bad/unset admin token; on webhooks, a bad/missing signature). A dashboard session (ddu_) that a newer login of the same person ended answers the code session_superseded instead (tenant flag single_session_enforced), so the screen can say why it was signed out; a logout, an expired or an unknown token stay unauthorized.

json
{
  "error": {
    "code": "unauthorized",
    "message": "invalid or revoked API key"
  }
}

403 ​

role_forbidden: a dashboard login without the account_admin role; forbidden: a widget token or a suspended tenant.

404 — NotFound ​

Unknown id, malformed (non-UUID) id OR another tenant's id — RLS returns zero rows, so all three are indistinguishable by design (no existence leak, never a 403 for foreign ids).

json
{
  "error": {
    "code": "not_found",
    "message": "resource not found for this tenant"
  }
}

429 — ApiKeyRateLimited ​

This API key is over its request quota, or the tenant's keys together are over the tenant ceiling (core#2503) (code rate_limited). The request was not processed. Wait Retry-After seconds and retry; a refusal is not counted against the budget, so that wait is always enough. Bounded per API key and, above the keys, per tenant (api_tenant_requests_per_minute): a sibling key is unaffected until the tenant's keys together reach that ceiling. The quota applies to every operation reachable with a dd_ key, so the operations that name a more specific 429 (call control, dispositions, SMS, …) can ALSO answer this one with its X-RateLimit-* headers.

json
{
  "error": {
    "code": "rate_limited",
    "message": "API key request quota exceeded; retry after the interval in Retry-After"
  }
}

Retire an inbound queue ​

http
POST /v1/inbound-queues/{id}/retire

Retires the queue for good: it leaves the list, cannot be named by a route, a menu or an overflow, and cannot be configured; its history stays. An id that is not an active queue of this tenant (unknown, already retired, or another tenant's) is 404. While something active still names the queue — an ACTIVE queue route, a current inbound IVR menu, or another active queue's overflow — it is 409 conflict naming each of them: disable or re-point them first. Same roles as creating. No body.

Parameters

NameInTypeRequiredDescription
idpathstring (uuid)yesResource UUID. Malformed or cross-tenant ids read as 404.

Responses

200 ​

Retired.

FieldTypeRequiredDescription
inbound_queueobject (InboundQueue)yes
inbound_queue.idstring (uuid)yes
inbound_queue.namestring,nullyesnull only for a queue created before names existed (core#1347).
inbound_queue.statusactive · retiredyes
inbound_queue.overflow_max_wait_msinteger,nullyesThe wait after which a call moves to overflow_queue_id; null = no overflow.
inbound_queue.overflow_queue_idstring,null (uuid)yes
inbound_queue.callback_offer_after_msinteger,nullyesThe MEASURED wait, in milliseconds, after which a caller of this queue would be offered a callback; null = this queue offers none. Alone it offers nothing, because the account's inbound_callback_offer_enabled flag has to be on too (core#1670).
inbound_queue.active_route_countintegeryesHow many ACTIVE queue routes of the tenant name this queue.
inbound_queue.created_atstring (date-time)yes
inbound_queue.retired_atstring,null (date-time)yes
inbound_queue.retired_bystring,nullyesThe user or agent id of the credential that retired it, or tenant-api-key.
inbound_queue.required_skillsarray of stringnoThe skills an agent needs to be offered this queue's calls (sorted); [] = demands nothing. Set with PUT /v1/inbound-queues/{id}/skills.
inbound_queue.warningsarray of required_skills_without_overflownorequired_skills_without_overflow: the queue demands skills and has no overflow, so a call nobody qualifies for waits with no way out (ADR #216 D6).

401 — Unauthorized ​

Missing, unknown or revoked API key (or, on /v1/admin/*, a bad/unset admin token; on webhooks, a bad/missing signature). A dashboard session (ddu_) that a newer login of the same person ended answers the code session_superseded instead (tenant flag single_session_enforced), so the screen can say why it was signed out; a logout, an expired or an unknown token stay unauthorized.

json
{
  "error": {
    "code": "unauthorized",
    "message": "invalid or revoked API key"
  }
}

403 ​

role_forbidden: a dashboard login without the account_admin role; forbidden: a widget token or a suspended tenant.

404 — NotFound ​

Unknown id, malformed (non-UUID) id OR another tenant's id — RLS returns zero rows, so all three are indistinguishable by design (no existence leak, never a 403 for foreign ids).

json
{
  "error": {
    "code": "not_found",
    "message": "resource not found for this tenant"
  }
}

409 — Conflict ​

Invalid state transition, uniqueness conflict, or a seat that is busy/reserved.

json
{
  "error": {
    "code": "conflict",
    "message": "invalid state transition"
  }
}

429 — ApiKeyRateLimited ​

This API key is over its request quota, or the tenant's keys together are over the tenant ceiling (core#2503) (code rate_limited). The request was not processed. Wait Retry-After seconds and retry; a refusal is not counted against the budget, so that wait is always enough. Bounded per API key and, above the keys, per tenant (api_tenant_requests_per_minute): a sibling key is unaffected until the tenant's keys together reach that ceiling. The quota applies to every operation reachable with a dd_ key, so the operations that name a more specific 429 (call control, dispositions, SMS, …) can ALSO answer this one with its X-RateLimit-* headers.

json
{
  "error": {
    "code": "rate_limited",
    "message": "API key request quota exceeded; retry after the interval in Retry-After"
  }
}

The debt lists designated as VIP for the inbound queue ​

http
GET /v1/inbound-vip-lists

The designated lists, by name then id, each with its name and when it was designated. vip_lists: [] when none is designated. Admin only, like the write.

Responses

200 ​

The designated lists.

FieldTypeRequiredDescription
vip_listsarray of objectyes
vip_lists[].list_idstring (uuid)yes
vip_lists[].namestringyes
vip_lists[].designated_atstring (date-time)yes

401 — Unauthorized ​

Missing, unknown or revoked API key (or, on /v1/admin/*, a bad/unset admin token; on webhooks, a bad/missing signature). A dashboard session (ddu_) that a newer login of the same person ended answers the code session_superseded instead (tenant flag single_session_enforced), so the screen can say why it was signed out; a logout, an expired or an unknown token stay unauthorized.

json
{
  "error": {
    "code": "unauthorized",
    "message": "invalid or revoked API key"
  }
}

403 ​

role_forbidden: a dashboard login without the account_admin role; forbidden: a widget token or a suspended tenant.

429 — ApiKeyRateLimited ​

This API key is over its request quota, or the tenant's keys together are over the tenant ceiling (core#2503) (code rate_limited). The request was not processed. Wait Retry-After seconds and retry; a refusal is not counted against the budget, so that wait is always enough. Bounded per API key and, above the keys, per tenant (api_tenant_requests_per_minute): a sibling key is unaffected until the tenant's keys together reach that ceiling. The quota applies to every operation reachable with a dd_ key, so the operations that name a more specific 429 (call control, dispositions, SMS, …) can ALSO answer this one with its X-RateLimit-* headers.

json
{
  "error": {
    "code": "rate_limited",
    "message": "API key request quota exceeded; retry after the interval in Retry-After"
  }
}

Replace the debt lists designated as VIP for the inbound queue ​

http
PUT /v1/inbound-vip-lists

Declares which of the tenant's debt lists count as VIP for the inbound queue (ADR #216 D9). A caller is VIP when their number belongs to a debt that is in any of these lists; who is in a list is managed with /v1/debt-lists and the import, nothing else changes. The body REPLACES the whole set; a repeated id counts once and [] designates nothing. 422 unprocessable when list_ids is not an array of UUID strings, has more than 50, or names a list that is not a list of this tenant; nothing is written then. Writing works with inbound_queue_vip_head_start_ms at 0: what is stored stays inert until the head start is turned on. Deleting a list retires its designation. Admin only: dd_ or a dashboard login with the account_admin role.

Request body (JSON, required)

FieldTypeRequiredDescription
list_idsarray of string (uuid)yes
json
{
  "list_ids": [
    "6f1c1f0e-8f4e-4c3e-9a61-0d7c1b6f2a10"
  ]
}

Responses

200 ​

The designated lists after the write, by name.

FieldTypeRequiredDescription
vip_listsarray of objectyes
vip_lists[].list_idstring (uuid)yes
vip_lists[].namestringyes
vip_lists[].designated_atstring (date-time)yes

400 — BadRequest ​

Malformed request (shape/type errors, invalid filters, bad timestamps).

json
{
  "error": {
    "code": "bad_request",
    "message": "from must be RFC-3339"
  }
}

401 — Unauthorized ​

Missing, unknown or revoked API key (or, on /v1/admin/*, a bad/unset admin token; on webhooks, a bad/missing signature). A dashboard session (ddu_) that a newer login of the same person ended answers the code session_superseded instead (tenant flag single_session_enforced), so the screen can say why it was signed out; a logout, an expired or an unknown token stay unauthorized.

json
{
  "error": {
    "code": "unauthorized",
    "message": "invalid or revoked API key"
  }
}

403 ​

role_forbidden: a dashboard login without the account_admin role; forbidden: a widget token or a suspended tenant.

422 — Unprocessable ​

Shape is fine, semantics are not (broken domain rule).

json
{
  "error": {
    "code": "unprocessable",
    "message": "scheduled_at is closer than the minimum notice for a callback (10 minutes unless the tenant's callback_min_notice_seconds says otherwise)"
  }
}

429 — ApiKeyRateLimited ​

This API key is over its request quota, or the tenant's keys together are over the tenant ceiling (core#2503) (code rate_limited). The request was not processed. Wait Retry-After seconds and retry; a refusal is not counted against the budget, so that wait is always enough. Bounded per API key and, above the keys, per tenant (api_tenant_requests_per_minute): a sibling key is unaffected until the tenant's keys together reach that ceiling. The quota applies to every operation reachable with a dd_ key, so the operations that name a more specific 429 (call control, dispositions, SMS, …) can ALSO answer this one with its X-RateLimit-* headers.

json
{
  "error": {
    "code": "rate_limited",
    "message": "API key request quota exceeded; retry after the interval in Retry-After"
  }
}

The skills a queue demands ​

http
GET /v1/inbound-queues/{id}/skills

The queue's required skills, sorted, and its warnings. [] when it demands nothing (and for a retired queue, whose skills were deleted). A queue that is not this tenant's is 404. Admin only, like the write.

Parameters

NameInTypeRequiredDescription
idpathstring (uuid)yesResource UUID. Malformed or cross-tenant ids read as 404.

Responses

200 ​

The queue's required skills and warnings.

FieldTypeRequiredDescription
queue_idstring (uuid)yes
skillsarray of stringyes
warningsarray of required_skills_without_overflowyes

401 — Unauthorized ​

Missing, unknown or revoked API key (or, on /v1/admin/*, a bad/unset admin token; on webhooks, a bad/missing signature). A dashboard session (ddu_) that a newer login of the same person ended answers the code session_superseded instead (tenant flag single_session_enforced), so the screen can say why it was signed out; a logout, an expired or an unknown token stay unauthorized.

json
{
  "error": {
    "code": "unauthorized",
    "message": "invalid or revoked API key"
  }
}

403 ​

role_forbidden: a dashboard login without the account_admin role; forbidden: a widget token or a suspended tenant.

404 — NotFound ​

Unknown id, malformed (non-UUID) id OR another tenant's id — RLS returns zero rows, so all three are indistinguishable by design (no existence leak, never a 403 for foreign ids).

json
{
  "error": {
    "code": "not_found",
    "message": "resource not found for this tenant"
  }
}

429 — ApiKeyRateLimited ​

This API key is over its request quota, or the tenant's keys together are over the tenant ceiling (core#2503) (code rate_limited). The request was not processed. Wait Retry-After seconds and retry; a refusal is not counted against the budget, so that wait is always enough. Bounded per API key and, above the keys, per tenant (api_tenant_requests_per_minute): a sibling key is unaffected until the tenant's keys together reach that ceiling. The quota applies to every operation reachable with a dd_ key, so the operations that name a more specific 429 (call control, dispositions, SMS, …) can ALSO answer this one with its X-RateLimit-* headers.

json
{
  "error": {
    "code": "rate_limited",
    "message": "API key request quota exceeded; retry after the interval in Retry-After"
  }
}

Replace the skills a queue demands ​

http
PUT /v1/inbound-queues/{id}/skills

Declares which skills an agent must have to be offered this queue's calls (ADR #216 D4-D5): ALL of them (an agent needs every skill). An empty set means the queue demands nothing. The body REPLACES the whole set; a repeated skill counts once. 422 unprocessable when any skill is malformed (^[a-z0-9][a-z0-9_-]{0,39}$), skills is not an array of strings, or there are more than 50; nothing is written then. A queue that is not an active queue of this tenant is 404. The requirement is hard: a call nobody qualifies for keeps waiting, and the way out is the queue's overflow. So a queue that demands skills and has no overflow is SAVED and the answer carries the warning required_skills_without_overflow (ADR #216 D6); it never refuses the write. Writing works with inbound_queue_skill_routing_enabled OFF: what is stored stays inert. Retiring the queue deletes its skills. Same roles as the agent skills: admin only.

Parameters

NameInTypeRequiredDescription
idpathstring (uuid)yesResource UUID. Malformed or cross-tenant ids read as 404.

Request body (JSON, required)

FieldTypeRequiredDescription
skillsarray of stringyes
json
{
  "skills": [
    "idioma_es"
  ]
}

Responses

200 ​

The queue's required skills after the write, sorted, and its warnings.

FieldTypeRequiredDescription
queue_idstring (uuid)yes
skillsarray of stringyes
warningsarray of required_skills_without_overflowyes

400 — BadRequest ​

Malformed request (shape/type errors, invalid filters, bad timestamps).

json
{
  "error": {
    "code": "bad_request",
    "message": "from must be RFC-3339"
  }
}

401 — Unauthorized ​

Missing, unknown or revoked API key (or, on /v1/admin/*, a bad/unset admin token; on webhooks, a bad/missing signature). A dashboard session (ddu_) that a newer login of the same person ended answers the code session_superseded instead (tenant flag single_session_enforced), so the screen can say why it was signed out; a logout, an expired or an unknown token stay unauthorized.

json
{
  "error": {
    "code": "unauthorized",
    "message": "invalid or revoked API key"
  }
}

403 ​

role_forbidden: a dashboard login without the account_admin role; forbidden: a widget token or a suspended tenant.

404 — NotFound ​

Unknown id, malformed (non-UUID) id OR another tenant's id — RLS returns zero rows, so all three are indistinguishable by design (no existence leak, never a 403 for foreign ids).

json
{
  "error": {
    "code": "not_found",
    "message": "resource not found for this tenant"
  }
}

422 — Unprocessable ​

Shape is fine, semantics are not (broken domain rule).

json
{
  "error": {
    "code": "unprocessable",
    "message": "scheduled_at is closer than the minimum notice for a callback (10 minutes unless the tenant's callback_min_notice_seconds says otherwise)"
  }
}

429 — ApiKeyRateLimited ​

This API key is over its request quota, or the tenant's keys together are over the tenant ceiling (core#2503) (code rate_limited). The request was not processed. Wait Retry-After seconds and retry; a refusal is not counted against the budget, so that wait is always enough. Bounded per API key and, above the keys, per tenant (api_tenant_requests_per_minute): a sibling key is unaffected until the tenant's keys together reach that ceiling. The quota applies to every operation reachable with a dd_ key, so the operations that name a more specific 429 (call control, dispositions, SMS, …) can ALSO answer this one with its X-RateLimit-* headers.

json
{
  "error": {
    "code": "rate_limited",
    "message": "API key request quota exceeded; retry after the interval in Retry-After"
  }
}

Nothing in these docs is legal advice — always confirm compliance posture with your own counsel.