Appearance
Inbound queues
Generated from
DialerDigital/corecommit0fc18008b3c8— specopenapi/dialer-v1.yamlv0.134.0. Do not edit by hand; see How this reference is built. Download the OpenAPI spec.
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
The tenant's active inbound queues, and whether queuing is on
http
GET /v1/inbound-queuesEvery 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.
| Field | Type | Required | Description |
|---|---|---|---|
inbound_queues | array of InboundQueue | yes | |
inbound_queues[].id | string (uuid) | yes | |
inbound_queues[].name | string,null | yes | null only for a queue created before names existed (core#1347). |
inbound_queues[].status | active · retired | yes | |
inbound_queues[].overflow_max_wait_ms | integer,null | yes | The wait after which a call moves to overflow_queue_id; null = no overflow. |
inbound_queues[].overflow_queue_id | string,null (uuid) | yes | |
inbound_queues[].callback_offer_after_ms | integer,null | yes | The 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_count | integer | yes | How many ACTIVE queue routes of the tenant name this queue. |
inbound_queues[].created_at | string (date-time) | yes | |
inbound_queues[].retired_at | string,null (date-time) | yes | |
inbound_queues[].retired_by | string,null | yes | The user or agent id of the credential that retired it, or tenant-api-key. |
inbound_queues[].required_skills | array of string | no | The skills an agent needs to be offered this queue's calls (sorted); [] = demands nothing. Set with PUT /v1/inbound-queues/{id}/skills. |
inbound_queues[].warnings | array of required_skills_without_overflow | no | required_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). |
capability | object (InboundQueueCapability) | yes | |
capability.flag | inbound_queue_stream_enabled | yes | The queue's own switch, the one turned on to turn the queue on. |
capability.enabled | boolean | yes | Whether 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.switches | object | yes | Each 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_enabled | boolean | yes | |
capability.switches.agent_session_journal_enabled | boolean | 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 — 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-queuesCreates 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)
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | The queue's name, for the operator (trimmed; blank is refused). |
json
{
"name": "Sales"
}Responses
201
Created.
| Field | Type | Required | Description |
|---|---|---|---|
inbound_queue | object (InboundQueue) | yes | |
inbound_queue.id | string (uuid) | yes | |
inbound_queue.name | string,null | yes | null only for a queue created before names existed (core#1347). |
inbound_queue.status | active · retired | yes | |
inbound_queue.overflow_max_wait_ms | integer,null | yes | The wait after which a call moves to overflow_queue_id; null = no overflow. |
inbound_queue.overflow_queue_id | string,null (uuid) | yes | |
inbound_queue.callback_offer_after_ms | integer,null | yes | The 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_count | integer | yes | How many ACTIVE queue routes of the tenant name this queue. |
inbound_queue.created_at | string (date-time) | yes | |
inbound_queue.retired_at | string,null (date-time) | yes | |
inbound_queue.retired_by | string,null | yes | The user or agent id of the credential that retired it, or tenant-api-key. |
inbound_queue.required_skills | array of string | no | The skills an agent needs to be offered this queue's calls (sorted); [] = demands nothing. Set with PUT /v1/inbound-queues/{id}/skills. |
inbound_queue.warnings | array of required_skills_without_overflow | no | required_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/liveThe 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.
| Field | Type | Required | Description |
|---|---|---|---|
as_of | string (date-time) | yes | The instant the read was taken. |
stream_enabled | boolean | yes | false = the queue stream is OFF for the tenant: depth is unknown, not zero. |
ready_agents | integer,null | yes | Agents in Ready now, tenant-wide; null when the seat journal is OFF. |
inbound_queues | array of InboundQueueLive | yes | |
inbound_queues[].queue_id | string (uuid) | yes | |
inbound_queues[].name | string,null | yes | |
inbound_queues[].depth | integer,null | yes | Calls 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_ms | integer,null | yes | How long the longest-waiting call has waited, by the wall clock. null when depth is null or 0. |
inbound_queues[].vip_depth | integer,null | yes | Of 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_ms | integer,null | yes | How long the longest-waiting VIP call has waited, by the wall clock. null when vip_depth is null or 0. |
inbound_queues[].ready_matching | integer,null | yes | How 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_ms | integer | yes | The 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string (uuid) | yes | Resource UUID. Malformed or cross-tenant ids read as 404. |
Responses
200
The queue.
| Field | Type | Required | Description |
|---|---|---|---|
inbound_queue | object (InboundQueue) | yes | |
inbound_queue.id | string (uuid) | yes | |
inbound_queue.name | string,null | yes | null only for a queue created before names existed (core#1347). |
inbound_queue.status | active · retired | yes | |
inbound_queue.overflow_max_wait_ms | integer,null | yes | The wait after which a call moves to overflow_queue_id; null = no overflow. |
inbound_queue.overflow_queue_id | string,null (uuid) | yes | |
inbound_queue.callback_offer_after_ms | integer,null | yes | The 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_count | integer | yes | How many ACTIVE queue routes of the tenant name this queue. |
inbound_queue.created_at | string (date-time) | yes | |
inbound_queue.retired_at | string,null (date-time) | yes | |
inbound_queue.retired_by | string,null | yes | The user or agent id of the credential that retired it, or tenant-api-key. |
inbound_queue.required_skills | array of string | no | The skills an agent needs to be offered this queue's calls (sorted); [] = demands nothing. Set with PUT /v1/inbound-queues/{id}/skills. |
inbound_queue.warnings | array of required_skills_without_overflow | no | required_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). |
capability | object (InboundQueueCapability) | yes | |
capability.flag | inbound_queue_stream_enabled | yes | The queue's own switch, the one turned on to turn the queue on. |
capability.enabled | boolean | yes | Whether 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.switches | object | yes | Each 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_enabled | boolean | yes | |
capability.switches.agent_session_journal_enabled | boolean | 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 — 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}/liveThe 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string (uuid) | yes | Resource UUID. Malformed or cross-tenant ids read as 404. |
Responses
200
The live state of the queue.
| Field | Type | Required | Description |
|---|---|---|---|
as_of | string (date-time) | yes | |
stream_enabled | boolean | yes | |
ready_agents | integer,null | yes | |
inbound_queue | object (InboundQueueLive) | yes | |
inbound_queue.queue_id | string (uuid) | yes | |
inbound_queue.name | string,null | yes | |
inbound_queue.depth | integer,null | yes | Calls 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_ms | integer,null | yes | How long the longest-waiting call has waited, by the wall clock. null when depth is null or 0. |
inbound_queue.vip_depth | integer,null | yes | Of 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_ms | integer,null | yes | How long the longest-waiting VIP call has waited, by the wall clock. null when vip_depth is null or 0. |
inbound_queue.ready_matching | integer,null | yes | How 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_ms | integer | yes | The 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/statsThe 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 (acallback_bookedclosed the admission), even if it happened afterto.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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string (uuid) | yes | Resource UUID. Malformed or cross-tenant ids read as 404. |
from | query | string (date-time) | yes | Start of the window, inclusive. |
to | query | string (date-time) | yes | End of the window, exclusive. At most 31 days after from. |
Responses
200
The counts for the window.
| Field | Type | Required | Description |
|---|---|---|---|
inbound_queue_id | string (uuid) | yes | |
from | string (date-time) | yes | |
to | string (date-time) | yes | |
callback_offer | object | yes | |
callback_offer.offered | integer | yes | |
callback_offer.accepted | integer | yes | |
callback_offer.declined_or_abandoned | integer | yes | |
callback_offer.open | integer | yes |
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}/overflowA 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string (uuid) | yes | Resource UUID. Malformed or cross-tenant ids read as 404. |
Request body (JSON, required)
| Field | Type | Required | Description |
|---|---|---|---|
overflow_max_wait_ms | integer | yes | |
overflow_queue_id | string (uuid) | yes |
json
{
"overflow_max_wait_ms": 120000,
"overflow_queue_id": "6f1c1b7e-2d7a-4c1e-9d3a-0b5e8f7a1c21"
}Responses
200
The queue with its overflow.
| Field | Type | Required | Description |
|---|---|---|---|
inbound_queue | object (InboundQueue) | yes | |
inbound_queue.id | string (uuid) | yes | |
inbound_queue.name | string,null | yes | null only for a queue created before names existed (core#1347). |
inbound_queue.status | active · retired | yes | |
inbound_queue.overflow_max_wait_ms | integer,null | yes | The wait after which a call moves to overflow_queue_id; null = no overflow. |
inbound_queue.overflow_queue_id | string,null (uuid) | yes | |
inbound_queue.callback_offer_after_ms | integer,null | yes | The 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_count | integer | yes | How many ACTIVE queue routes of the tenant name this queue. |
inbound_queue.created_at | string (date-time) | yes | |
inbound_queue.retired_at | string,null (date-time) | yes | |
inbound_queue.retired_by | string,null | yes | The user or agent id of the credential that retired it, or tenant-api-key. |
inbound_queue.required_skills | array of string | no | The skills an agent needs to be offered this queue's calls (sorted); [] = demands nothing. Set with PUT /v1/inbound-queues/{id}/skills. |
inbound_queue.warnings | array of required_skills_without_overflow | no | required_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}/overflowBoth 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string (uuid) | yes | Resource UUID. Malformed or cross-tenant ids read as 404. |
Responses
200
The queue without overflow.
| Field | Type | Required | Description |
|---|---|---|---|
inbound_queue | object (InboundQueue) | yes | |
inbound_queue.id | string (uuid) | yes | |
inbound_queue.name | string,null | yes | null only for a queue created before names existed (core#1347). |
inbound_queue.status | active · retired | yes | |
inbound_queue.overflow_max_wait_ms | integer,null | yes | The wait after which a call moves to overflow_queue_id; null = no overflow. |
inbound_queue.overflow_queue_id | string,null (uuid) | yes | |
inbound_queue.callback_offer_after_ms | integer,null | yes | The 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_count | integer | yes | How many ACTIVE queue routes of the tenant name this queue. |
inbound_queue.created_at | string (date-time) | yes | |
inbound_queue.retired_at | string,null (date-time) | yes | |
inbound_queue.retired_by | string,null | yes | The user or agent id of the credential that retired it, or tenant-api-key. |
inbound_queue.required_skills | array of string | no | The skills an agent needs to be offered this queue's calls (sorted); [] = demands nothing. Set with PUT /v1/inbound-queues/{id}/skills. |
inbound_queue.warnings | array of required_skills_without_overflow | no | required_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-offerSets 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string (uuid) | yes | Resource UUID. Malformed or cross-tenant ids read as 404. |
Request body (JSON, required)
| Field | Type | Required | Description |
|---|---|---|---|
callback_offer_after_ms | integer | yes |
json
{
"callback_offer_after_ms": 90000
}Responses
200
The queue with its callback-offer threshold.
| Field | Type | Required | Description |
|---|---|---|---|
inbound_queue | object (InboundQueue) | yes | |
inbound_queue.id | string (uuid) | yes | |
inbound_queue.name | string,null | yes | null only for a queue created before names existed (core#1347). |
inbound_queue.status | active · retired | yes | |
inbound_queue.overflow_max_wait_ms | integer,null | yes | The wait after which a call moves to overflow_queue_id; null = no overflow. |
inbound_queue.overflow_queue_id | string,null (uuid) | yes | |
inbound_queue.callback_offer_after_ms | integer,null | yes | The 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_count | integer | yes | How many ACTIVE queue routes of the tenant name this queue. |
inbound_queue.created_at | string (date-time) | yes | |
inbound_queue.retired_at | string,null (date-time) | yes | |
inbound_queue.retired_by | string,null | yes | The user or agent id of the credential that retired it, or tenant-api-key. |
inbound_queue.required_skills | array of string | no | The skills an agent needs to be offered this queue's calls (sorted); [] = demands nothing. Set with PUT /v1/inbound-queues/{id}/skills. |
inbound_queue.warnings | array of required_skills_without_overflow | no | required_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-offercallback_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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string (uuid) | yes | Resource UUID. Malformed or cross-tenant ids read as 404. |
Responses
200
The queue without a callback-offer threshold.
| Field | Type | Required | Description |
|---|---|---|---|
inbound_queue | object (InboundQueue) | yes | |
inbound_queue.id | string (uuid) | yes | |
inbound_queue.name | string,null | yes | null only for a queue created before names existed (core#1347). |
inbound_queue.status | active · retired | yes | |
inbound_queue.overflow_max_wait_ms | integer,null | yes | The wait after which a call moves to overflow_queue_id; null = no overflow. |
inbound_queue.overflow_queue_id | string,null (uuid) | yes | |
inbound_queue.callback_offer_after_ms | integer,null | yes | The 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_count | integer | yes | How many ACTIVE queue routes of the tenant name this queue. |
inbound_queue.created_at | string (date-time) | yes | |
inbound_queue.retired_at | string,null (date-time) | yes | |
inbound_queue.retired_by | string,null | yes | The user or agent id of the credential that retired it, or tenant-api-key. |
inbound_queue.required_skills | array of string | no | The skills an agent needs to be offered this queue's calls (sorted); [] = demands nothing. Set with PUT /v1/inbound-queues/{id}/skills. |
inbound_queue.warnings | array of required_skills_without_overflow | no | required_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}/retireRetires 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string (uuid) | yes | Resource UUID. Malformed or cross-tenant ids read as 404. |
Responses
200
Retired.
| Field | Type | Required | Description |
|---|---|---|---|
inbound_queue | object (InboundQueue) | yes | |
inbound_queue.id | string (uuid) | yes | |
inbound_queue.name | string,null | yes | null only for a queue created before names existed (core#1347). |
inbound_queue.status | active · retired | yes | |
inbound_queue.overflow_max_wait_ms | integer,null | yes | The wait after which a call moves to overflow_queue_id; null = no overflow. |
inbound_queue.overflow_queue_id | string,null (uuid) | yes | |
inbound_queue.callback_offer_after_ms | integer,null | yes | The 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_count | integer | yes | How many ACTIVE queue routes of the tenant name this queue. |
inbound_queue.created_at | string (date-time) | yes | |
inbound_queue.retired_at | string,null (date-time) | yes | |
inbound_queue.retired_by | string,null | yes | The user or agent id of the credential that retired it, or tenant-api-key. |
inbound_queue.required_skills | array of string | no | The skills an agent needs to be offered this queue's calls (sorted); [] = demands nothing. Set with PUT /v1/inbound-queues/{id}/skills. |
inbound_queue.warnings | array of required_skills_without_overflow | no | required_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-listsThe 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.
| Field | Type | Required | Description |
|---|---|---|---|
vip_lists | array of object | yes | |
vip_lists[].list_id | string (uuid) | yes | |
vip_lists[].name | string | yes | |
vip_lists[].designated_at | string (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-listsDeclares 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)
| Field | Type | Required | Description |
|---|---|---|---|
list_ids | array of string (uuid) | yes |
json
{
"list_ids": [
"6f1c1f0e-8f4e-4c3e-9a61-0d7c1b6f2a10"
]
}Responses
200
The designated lists after the write, by name.
| Field | Type | Required | Description |
|---|---|---|---|
vip_lists | array of object | yes | |
vip_lists[].list_id | string (uuid) | yes | |
vip_lists[].name | string | yes | |
vip_lists[].designated_at | string (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}/skillsThe 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string (uuid) | yes | Resource UUID. Malformed or cross-tenant ids read as 404. |
Responses
200
The queue's required skills and warnings.
| Field | Type | Required | Description |
|---|---|---|---|
queue_id | string (uuid) | yes | |
skills | array of string | yes | |
warnings | array of required_skills_without_overflow | 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.
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}/skillsDeclares 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string (uuid) | yes | Resource UUID. Malformed or cross-tenant ids read as 404. |
Request body (JSON, required)
| Field | Type | Required | Description |
|---|---|---|---|
skills | array of string | yes |
json
{
"skills": [
"idioma_es"
]
}Responses
200
The queue's required skills after the write, sorted, and its warnings.
| Field | Type | Required | Description |
|---|---|---|---|
queue_id | string (uuid) | yes | |
skills | array of string | yes | |
warnings | array of required_skills_without_overflow | 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.
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"
}
}