Appearance
Supervisión
Generado desde
DialerDigital/corecommit0fc18008b3c8— especificaciónopenapi/dialer-v1.yamlv0.134.0. No se edita a mano; consulta Cómo se construye esta referencia. Descargar la especificación OpenAPI.
Traducción en curso
Esta referencia se genera desde la especificación OpenAPI. Las cadenas que todavía no tienen traducción aparecen en inglés.
Audio de supervisor (escuchar/susurrar/intervenir/tomar el control), con evidencia primero.
Endpoints
| Método | Ruta | Resumen |
|---|---|---|
POST | /v1/supervision/calls/{call_id}/listen | Monitoreo silencioso (no lo oye nadie) |
POST | /v1/supervision/calls/{call_id}/whisper | Susurro (lo oye solo la pierna del agente) |
POST | /v1/supervision/calls/{call_id}/barge | Intervención (tripartita, la oyen ambas partes) |
POST | /v1/supervision/calls/{call_id}/takeover | Toma de control (el deudor se transfiere al supervisor) |
Monitoreo silencioso (no lo oye nadie)
http
POST /v1/supervision/calls/{call_id}/listenOrigina una pierna de supervisión hacia el endpoint REGISTRADO del supervisor ejecutando eavesdrop de FreeSWITCH sobre la llamada. EVIDENCIA PRIMERO: cada intento — éxito o falla, incluidas las sondas a uuids desconocidos — escribe una fila durable de supervision_actions ANTES de cualquier comando al switch (las fallas la pasan a failed, los rechazos a refused, nunca se borra). {call_id} es el uuid de FreeSWITCH de la llamada en vivo (= call_attempts.call_uuid). Los uuids de otro tenant son indistinguibles de los inexistentes y disparan CERO comandos al switch. Un modo activo por supervisor por llamada: un modo nuevo cuelga la pierna anterior.
QUIÉN puede supervisar (ADR #116): supervisor_ext debe resolver a un agente activo cuyo role sea supervisor o admin; un agent simple recibe 403role_forbidden (con evidencia como refused, CERO comandos al switch), para todo principal (dd_, ddu_). La comprobación de rol decide antes de actuar según el resultado de la búsqueda de la llamada (una llamada desconocida es 403, no 404, para quien llama sin autorización: no hay oráculo 404-vs-403). Gobernado por tenant mediante la clave de catálogo supervision_role_enforced (activada por defecto; desactivada restablece "cualquier extensión activa"). Un principal de agente (ddw_) es detenido por la lista de permitidos del widget, denegada por defecto, antes de esta operación; detrás de ella, solo puede nombrar su propia extensión (403 forbidden).
QUIÉN puede actuar COMO esa extensión (ADR #135, core#1037 fase 3): el agente detrás de supervisor_ext es el agente que nombra el cuerpo y queda acotado por la misma regla de principal que todo verbo con agent_id, decidida ANTES de la comprobación de rol y con evidencia del mismo modo. Un inicio de sesión ddu_ vinculado a un puesto puede nombrar solo su propio puesto (403 forbidden, sin flag); un inicio de sesión ddu_ sin puesto puede nombrar a un tercero solo como account_admin — un member recibe 403role_forbidden una vez que ddu_author_role_enforced del tenant está activado (nace desactivado). Una clave dd_ nombra a cualquiera. La misma compuerta se aplica a whisper, barge, takeover y POST /v1/ai/conversations/{id}/takeover.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
call_id | path | string (uuid) | sí | El uuid de FreeSWITCH de la llamada en vivo (= call_attempts.call_uuid, también el call_id de los eventos call.* del piso). |
Cuerpo de la petición (JSON, obligatorio)
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
supervisor_ext | string | sí | Debe ser una extensión ACTIVA de la lista de ESTE tenant con rol supervisor o admin (ADR #116; 403 role_forbidden en caso contrario), y una como la que el principal puede actuar (ADR #135; un ddu_ con puesto solo su propio puesto, 403 forbidden); su dispositivo con check-in recibe la pierna de supervisión (contestar en 20 s). |
json
{
"supervisor_ext": "2000"
}Respuestas
200
Pierna de supervisión originada (fila de auditoría durable).
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
supervision | object (SupervisionResult) | sí | |
supervision.action | listen · whisper · barge · takeover | no | |
supervision.call_id | string | no | |
supervision.supervisor_ext | string | no | |
supervision.session_id | string | null | no | uuid de la pierna del supervisor; null para takeover (sin pierna eavesdrop). |
supervision.audit_id | string (uuid) | no | La fila durable de supervision_actions. |
supervision.to_number | string | no | Últimos 4 enmascarados (***0184) — el E.164 completo nunca cruza esta superficie. |
json
{
"supervision": {
"action": "listen",
"call_id": "6f0a1b2c-3d4e-5f6a-7b8c-9d0e1f2a3b4c",
"supervisor_ext": "2000",
"session_id": "7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d",
"audit_id": "9d0e1f2a-3b4c-5d6e-7f8a-9b0c1d2e3f4a",
"to_number": "***1001"
}
}400 — BadRequest
Petición mal formada (errores de forma/tipo, filtros no válidos, marcas de tiempo erróneas).
json
{
"error": {
"code": "bad_request",
"message": "from must be RFC-3339"
}
}401 — Unauthorized
Clave de API ausente, desconocida o revocada (o, en /v1/admin/*, un token de administración incorrecto o sin definir; en webhooks, una firma incorrecta o ausente). Una sesión del dashboard (ddu_) que un inicio de sesión más reciente de la misma persona haya cerrado responde en cambio con el código session_superseded (indicador de tenant single_session_enforced), para que la pantalla pueda explicar por qué se cerró la sesión; un cierre de sesión, un token vencido o uno desconocido siguen siendo unauthorized.
json
{
"error": {
"code": "unauthorized",
"message": "invalid or revoked API key"
}
}402 — PlanInactive
El plan del tenant se LEYÓ y no está efectivamente active, por lo que la acción queda bloqueada (code plan_inactive). En la superficie de SUPERVISIÓN este estado significa que el plan realmente se leyó: un plan que NO se pudo leer pasa en lugar de rechazar (ADR #37). Es deliberadamente lo opuesto a la postura fail-CLOSED de la compuerta de entrantes — una pierna de supervisión va al registrar propio del tenant y no compra minutos de carrier, así que el costo de un falso rechazo (un oficial de cumplimiento a ciegas durante una llamada en vivo) supera el costo de una falsa admisión.
Nota sobre qué verbos pueden devolverlo: solo los tres modos EAVESDROP. takeover está exento y nunca devuelve plan_inactive, bajo la regla "bloquea lo que AGREGA exposición, nunca lo que la CORRIGE" — listen/whisper/barge abren cada uno una pierna nueva, mientras que takeover le quita la llamada al agente y mata la pierna del agente. Un plan que caduca a mitad de turno no debe dejar varada una llamada en vivo que el supervisor intenta terminar. La exención es estrecha, no una laguna de facturación: un tenant apagado sigue sin poder abrir supervisión NUEVA, solo conserva la palanca para terminar correctamente lo que ya está en marcha.
json
{
"error": {
"code": "plan_inactive",
"message": "tenant plan is not active; traffic is gated"
}
}403 — SupervisionRoleForbidden
Quien llama no puede supervisar con ese supervisor_ext (ADR #116, core#928; ADR #135, core#1037 fase 3). code role_forbidden: la extensión resuelve a un agente activo cuyo role no es supervisor ni admin — o un inicio de sesión ddu_ sin puesto vinculado nombró la extensión de otra persona sin el rol account_admin (una vez que ddu_author_role_enforced está activado). codeforbidden: un principal ligado a UN agente — un token ddw_, o un inicio de sesión ddu_ vinculado a un puesto — nombró una extensión que no es la suya. En cualquier caso el intento QUEDA con evidencia — una fila de supervision_actions con result: refused — y se ejecutaron CERO comandos al switch. Por tenant, supervision_role_enforced = false desactiva la comprobación de rol de la extensión (la vinculación de identidad y la regla de principal se mantienen).
role_forbidden
json
{
"error": {
"code": "role_forbidden",
"message": "supervisor_ext must belong to an agent with role supervisor or admin"
}
}forbidden
json
{
"error": {
"code": "forbidden",
"message": "supervisor_ext must be the agent bound to this token"
}
}404 — NotFound
Id desconocido, mal formado (no UUID) O id de otro tenant: RLS devuelve cero filas, así que los tres son indistinguibles por diseño (sin fuga de existencia, nunca un 403 para ids ajenos).
json
{
"error": {
"code": "not_found",
"message": "resource not found for this tenant"
}
}429 — SupervisionQuotaFull
La cuota de SUPERVISIÓN del tenant está llena (code supervision_capacity): ya hay abiertas max_supervision_channels sesiones de supervisión concurrentes. Es un tope APARTE de max_concurrent_channels (ADR #37) e independiente en AMBAS direcciones: un piso de marcación saturado nunca rechaza la supervisión, y una cuota de supervisión agotada nunca rechaza una marcación. La unidad es la sesión (llamada, supervisor), de modo que pasar de escuchar a intervenir en la misma llamada no consume un segundo cupo. Se puede reintentar en cuanto termine una llamada supervisada. No se envía la cabecera Retry-After.
json
{
"error": {
"code": "supervision_capacity",
"message": "tenant supervision quota is full; retry when a supervised call ends"
}
}502 — SupervisionFailed
El switch rechazó el comando de supervisión (la llamada ya terminó / el dispositivo del supervisor no está registrado).
json
{
"error": {
"code": "supervision_failed",
"message": "the switch rejected the supervision command"
}
}503 — SupervisionUnavailable
code audit_unavailable: no se pudo escribir la fila de evidencia, por lo que NO se envió ningún comando al switch (evidencia primero, fail-closed). codeesl_unavailable: el enlace de control del switch está caído. Ambos son reintentables.
audit_unavailable
json
{
"error": {
"code": "audit_unavailable",
"message": "supervision audit unavailable, retry"
}
}esl_unavailable
json
{
"error": {
"code": "esl_unavailable",
"message": "telephony control unavailable, retry"
}
}Susurro (lo oye solo la pierna del agente)
http
POST /v1/supervision/calls/{call_id}/whisperMismo contrato y semántica de evidencia primero que listen; el audio de coaching llega solo al agente.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
call_id | path | string (uuid) | sí | El uuid de FreeSWITCH de la llamada en vivo (= call_attempts.call_uuid, también el call_id de los eventos call.* del piso). |
Cuerpo de la petición (JSON, obligatorio)
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
supervisor_ext | string | sí | Debe ser una extensión ACTIVA de la lista de ESTE tenant con rol supervisor o admin (ADR #116; 403 role_forbidden en caso contrario), y una como la que el principal puede actuar (ADR #135; un ddu_ con puesto solo su propio puesto, 403 forbidden); su dispositivo con check-in recibe la pierna de supervisión (contestar en 20 s). |
Respuestas
200
Pierna de supervisión originada (fila de auditoría durable).
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
supervision | object (SupervisionResult) | sí | |
supervision.action | listen · whisper · barge · takeover | no | |
supervision.call_id | string | no | |
supervision.supervisor_ext | string | no | |
supervision.session_id | string | null | no | uuid de la pierna del supervisor; null para takeover (sin pierna eavesdrop). |
supervision.audit_id | string (uuid) | no | La fila durable de supervision_actions. |
supervision.to_number | string | no | Últimos 4 enmascarados (***0184) — el E.164 completo nunca cruza esta superficie. |
400 — BadRequest
Petición mal formada (errores de forma/tipo, filtros no válidos, marcas de tiempo erróneas).
json
{
"error": {
"code": "bad_request",
"message": "from must be RFC-3339"
}
}401 — Unauthorized
Clave de API ausente, desconocida o revocada (o, en /v1/admin/*, un token de administración incorrecto o sin definir; en webhooks, una firma incorrecta o ausente). Una sesión del dashboard (ddu_) que un inicio de sesión más reciente de la misma persona haya cerrado responde en cambio con el código session_superseded (indicador de tenant single_session_enforced), para que la pantalla pueda explicar por qué se cerró la sesión; un cierre de sesión, un token vencido o uno desconocido siguen siendo unauthorized.
json
{
"error": {
"code": "unauthorized",
"message": "invalid or revoked API key"
}
}402 — PlanInactive
El plan del tenant se LEYÓ y no está efectivamente active, por lo que la acción queda bloqueada (code plan_inactive). En la superficie de SUPERVISIÓN este estado significa que el plan realmente se leyó: un plan que NO se pudo leer pasa en lugar de rechazar (ADR #37). Es deliberadamente lo opuesto a la postura fail-CLOSED de la compuerta de entrantes — una pierna de supervisión va al registrar propio del tenant y no compra minutos de carrier, así que el costo de un falso rechazo (un oficial de cumplimiento a ciegas durante una llamada en vivo) supera el costo de una falsa admisión.
Nota sobre qué verbos pueden devolverlo: solo los tres modos EAVESDROP. takeover está exento y nunca devuelve plan_inactive, bajo la regla "bloquea lo que AGREGA exposición, nunca lo que la CORRIGE" — listen/whisper/barge abren cada uno una pierna nueva, mientras que takeover le quita la llamada al agente y mata la pierna del agente. Un plan que caduca a mitad de turno no debe dejar varada una llamada en vivo que el supervisor intenta terminar. La exención es estrecha, no una laguna de facturación: un tenant apagado sigue sin poder abrir supervisión NUEVA, solo conserva la palanca para terminar correctamente lo que ya está en marcha.
json
{
"error": {
"code": "plan_inactive",
"message": "tenant plan is not active; traffic is gated"
}
}403 — SupervisionRoleForbidden
Quien llama no puede supervisar con ese supervisor_ext (ADR #116, core#928; ADR #135, core#1037 fase 3). code role_forbidden: la extensión resuelve a un agente activo cuyo role no es supervisor ni admin — o un inicio de sesión ddu_ sin puesto vinculado nombró la extensión de otra persona sin el rol account_admin (una vez que ddu_author_role_enforced está activado). codeforbidden: un principal ligado a UN agente — un token ddw_, o un inicio de sesión ddu_ vinculado a un puesto — nombró una extensión que no es la suya. En cualquier caso el intento QUEDA con evidencia — una fila de supervision_actions con result: refused — y se ejecutaron CERO comandos al switch. Por tenant, supervision_role_enforced = false desactiva la comprobación de rol de la extensión (la vinculación de identidad y la regla de principal se mantienen).
role_forbidden
json
{
"error": {
"code": "role_forbidden",
"message": "supervisor_ext must belong to an agent with role supervisor or admin"
}
}forbidden
json
{
"error": {
"code": "forbidden",
"message": "supervisor_ext must be the agent bound to this token"
}
}404 — NotFound
Id desconocido, mal formado (no UUID) O id de otro tenant: RLS devuelve cero filas, así que los tres son indistinguibles por diseño (sin fuga de existencia, nunca un 403 para ids ajenos).
json
{
"error": {
"code": "not_found",
"message": "resource not found for this tenant"
}
}429 — SupervisionQuotaFull
La cuota de SUPERVISIÓN del tenant está llena (code supervision_capacity): ya hay abiertas max_supervision_channels sesiones de supervisión concurrentes. Es un tope APARTE de max_concurrent_channels (ADR #37) e independiente en AMBAS direcciones: un piso de marcación saturado nunca rechaza la supervisión, y una cuota de supervisión agotada nunca rechaza una marcación. La unidad es la sesión (llamada, supervisor), de modo que pasar de escuchar a intervenir en la misma llamada no consume un segundo cupo. Se puede reintentar en cuanto termine una llamada supervisada. No se envía la cabecera Retry-After.
json
{
"error": {
"code": "supervision_capacity",
"message": "tenant supervision quota is full; retry when a supervised call ends"
}
}502 — SupervisionFailed
El switch rechazó el comando de supervisión (la llamada ya terminó / el dispositivo del supervisor no está registrado).
json
{
"error": {
"code": "supervision_failed",
"message": "the switch rejected the supervision command"
}
}503 — SupervisionUnavailable
code audit_unavailable: no se pudo escribir la fila de evidencia, por lo que NO se envió ningún comando al switch (evidencia primero, fail-closed). codeesl_unavailable: el enlace de control del switch está caído. Ambos son reintentables.
audit_unavailable
json
{
"error": {
"code": "audit_unavailable",
"message": "supervision audit unavailable, retry"
}
}esl_unavailable
json
{
"error": {
"code": "esl_unavailable",
"message": "telephony control unavailable, retry"
}
}Intervención (tripartita, la oyen ambas partes)
http
POST /v1/supervision/calls/{call_id}/bargeMismo contrato y semántica de evidencia primero que listen; el supervisor se escucha tanto con el agente como con el deudor.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
call_id | path | string (uuid) | sí | El uuid de FreeSWITCH de la llamada en vivo (= call_attempts.call_uuid, también el call_id de los eventos call.* del piso). |
Cuerpo de la petición (JSON, obligatorio)
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
supervisor_ext | string | sí | Debe ser una extensión ACTIVA de la lista de ESTE tenant con rol supervisor o admin (ADR #116; 403 role_forbidden en caso contrario), y una como la que el principal puede actuar (ADR #135; un ddu_ con puesto solo su propio puesto, 403 forbidden); su dispositivo con check-in recibe la pierna de supervisión (contestar en 20 s). |
Respuestas
200
Pierna de supervisión originada (fila de auditoría durable).
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
supervision | object (SupervisionResult) | sí | |
supervision.action | listen · whisper · barge · takeover | no | |
supervision.call_id | string | no | |
supervision.supervisor_ext | string | no | |
supervision.session_id | string | null | no | uuid de la pierna del supervisor; null para takeover (sin pierna eavesdrop). |
supervision.audit_id | string (uuid) | no | La fila durable de supervision_actions. |
supervision.to_number | string | no | Últimos 4 enmascarados (***0184) — el E.164 completo nunca cruza esta superficie. |
400 — BadRequest
Petición mal formada (errores de forma/tipo, filtros no válidos, marcas de tiempo erróneas).
json
{
"error": {
"code": "bad_request",
"message": "from must be RFC-3339"
}
}401 — Unauthorized
Clave de API ausente, desconocida o revocada (o, en /v1/admin/*, un token de administración incorrecto o sin definir; en webhooks, una firma incorrecta o ausente). Una sesión del dashboard (ddu_) que un inicio de sesión más reciente de la misma persona haya cerrado responde en cambio con el código session_superseded (indicador de tenant single_session_enforced), para que la pantalla pueda explicar por qué se cerró la sesión; un cierre de sesión, un token vencido o uno desconocido siguen siendo unauthorized.
json
{
"error": {
"code": "unauthorized",
"message": "invalid or revoked API key"
}
}402 — PlanInactive
El plan del tenant se LEYÓ y no está efectivamente active, por lo que la acción queda bloqueada (code plan_inactive). En la superficie de SUPERVISIÓN este estado significa que el plan realmente se leyó: un plan que NO se pudo leer pasa en lugar de rechazar (ADR #37). Es deliberadamente lo opuesto a la postura fail-CLOSED de la compuerta de entrantes — una pierna de supervisión va al registrar propio del tenant y no compra minutos de carrier, así que el costo de un falso rechazo (un oficial de cumplimiento a ciegas durante una llamada en vivo) supera el costo de una falsa admisión.
Nota sobre qué verbos pueden devolverlo: solo los tres modos EAVESDROP. takeover está exento y nunca devuelve plan_inactive, bajo la regla "bloquea lo que AGREGA exposición, nunca lo que la CORRIGE" — listen/whisper/barge abren cada uno una pierna nueva, mientras que takeover le quita la llamada al agente y mata la pierna del agente. Un plan que caduca a mitad de turno no debe dejar varada una llamada en vivo que el supervisor intenta terminar. La exención es estrecha, no una laguna de facturación: un tenant apagado sigue sin poder abrir supervisión NUEVA, solo conserva la palanca para terminar correctamente lo que ya está en marcha.
json
{
"error": {
"code": "plan_inactive",
"message": "tenant plan is not active; traffic is gated"
}
}403 — SupervisionRoleForbidden
Quien llama no puede supervisar con ese supervisor_ext (ADR #116, core#928; ADR #135, core#1037 fase 3). code role_forbidden: la extensión resuelve a un agente activo cuyo role no es supervisor ni admin — o un inicio de sesión ddu_ sin puesto vinculado nombró la extensión de otra persona sin el rol account_admin (una vez que ddu_author_role_enforced está activado). codeforbidden: un principal ligado a UN agente — un token ddw_, o un inicio de sesión ddu_ vinculado a un puesto — nombró una extensión que no es la suya. En cualquier caso el intento QUEDA con evidencia — una fila de supervision_actions con result: refused — y se ejecutaron CERO comandos al switch. Por tenant, supervision_role_enforced = false desactiva la comprobación de rol de la extensión (la vinculación de identidad y la regla de principal se mantienen).
role_forbidden
json
{
"error": {
"code": "role_forbidden",
"message": "supervisor_ext must belong to an agent with role supervisor or admin"
}
}forbidden
json
{
"error": {
"code": "forbidden",
"message": "supervisor_ext must be the agent bound to this token"
}
}404 — NotFound
Id desconocido, mal formado (no UUID) O id de otro tenant: RLS devuelve cero filas, así que los tres son indistinguibles por diseño (sin fuga de existencia, nunca un 403 para ids ajenos).
json
{
"error": {
"code": "not_found",
"message": "resource not found for this tenant"
}
}429 — SupervisionQuotaFull
La cuota de SUPERVISIÓN del tenant está llena (code supervision_capacity): ya hay abiertas max_supervision_channels sesiones de supervisión concurrentes. Es un tope APARTE de max_concurrent_channels (ADR #37) e independiente en AMBAS direcciones: un piso de marcación saturado nunca rechaza la supervisión, y una cuota de supervisión agotada nunca rechaza una marcación. La unidad es la sesión (llamada, supervisor), de modo que pasar de escuchar a intervenir en la misma llamada no consume un segundo cupo. Se puede reintentar en cuanto termine una llamada supervisada. No se envía la cabecera Retry-After.
json
{
"error": {
"code": "supervision_capacity",
"message": "tenant supervision quota is full; retry when a supervised call ends"
}
}502 — SupervisionFailed
El switch rechazó el comando de supervisión (la llamada ya terminó / el dispositivo del supervisor no está registrado).
json
{
"error": {
"code": "supervision_failed",
"message": "the switch rejected the supervision command"
}
}503 — SupervisionUnavailable
code audit_unavailable: no se pudo escribir la fila de evidencia, por lo que NO se envió ningún comando al switch (evidencia primero, fail-closed). codeesl_unavailable: el enlace de control del switch está caído. Ambos son reintentables.
audit_unavailable
json
{
"error": {
"code": "audit_unavailable",
"message": "supervision audit unavailable, retry"
}
}esl_unavailable
json
{
"error": {
"code": "esl_unavailable",
"message": "telephony control unavailable, retry"
}
}Toma de control (el deudor se transfiere al supervisor)
http
POST /v1/supervision/calls/{call_id}/takeoverTransfiere la pierna del deudor al supervisor y cuelga la pierna huérfana del agente. session_id es null: no hay pierna de escucha. Mismo contrato de auditoría de evidencia primero que los demás modos.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
call_id | path | string (uuid) | sí | El uuid de FreeSWITCH de la llamada en vivo (= call_attempts.call_uuid, también el call_id de los eventos call.* del piso). |
Cuerpo de la petición (JSON, obligatorio)
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
supervisor_ext | string | sí | Debe ser una extensión ACTIVA de la lista de ESTE tenant con rol supervisor o admin (ADR #116; 403 role_forbidden en caso contrario), y una como la que el principal puede actuar (ADR #135; un ddu_ con puesto solo su propio puesto, 403 forbidden); su dispositivo con check-in recibe la pierna de supervisión (contestar en 20 s). |
Respuestas
200
Pierna del deudor transferida (fila de auditoría durable).
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
supervision | object (SupervisionResult) | sí | |
supervision.action | listen · whisper · barge · takeover | no | |
supervision.call_id | string | no | |
supervision.supervisor_ext | string | no | |
supervision.session_id | string | null | no | uuid de la pierna del supervisor; null para takeover (sin pierna eavesdrop). |
supervision.audit_id | string (uuid) | no | La fila durable de supervision_actions. |
supervision.to_number | string | no | Últimos 4 enmascarados (***0184) — el E.164 completo nunca cruza esta superficie. |
400 — BadRequest
Petición mal formada (errores de forma/tipo, filtros no válidos, marcas de tiempo erróneas).
json
{
"error": {
"code": "bad_request",
"message": "from must be RFC-3339"
}
}401 — Unauthorized
Clave de API ausente, desconocida o revocada (o, en /v1/admin/*, un token de administración incorrecto o sin definir; en webhooks, una firma incorrecta o ausente). Una sesión del dashboard (ddu_) que un inicio de sesión más reciente de la misma persona haya cerrado responde en cambio con el código session_superseded (indicador de tenant single_session_enforced), para que la pantalla pueda explicar por qué se cerró la sesión; un cierre de sesión, un token vencido o uno desconocido siguen siendo unauthorized.
json
{
"error": {
"code": "unauthorized",
"message": "invalid or revoked API key"
}
}403 — SupervisionRoleForbidden
Quien llama no puede supervisar con ese supervisor_ext (ADR #116, core#928; ADR #135, core#1037 fase 3). code role_forbidden: la extensión resuelve a un agente activo cuyo role no es supervisor ni admin — o un inicio de sesión ddu_ sin puesto vinculado nombró la extensión de otra persona sin el rol account_admin (una vez que ddu_author_role_enforced está activado). codeforbidden: un principal ligado a UN agente — un token ddw_, o un inicio de sesión ddu_ vinculado a un puesto — nombró una extensión que no es la suya. En cualquier caso el intento QUEDA con evidencia — una fila de supervision_actions con result: refused — y se ejecutaron CERO comandos al switch. Por tenant, supervision_role_enforced = false desactiva la comprobación de rol de la extensión (la vinculación de identidad y la regla de principal se mantienen).
role_forbidden
json
{
"error": {
"code": "role_forbidden",
"message": "supervisor_ext must belong to an agent with role supervisor or admin"
}
}forbidden
json
{
"error": {
"code": "forbidden",
"message": "supervisor_ext must be the agent bound to this token"
}
}404 — NotFound
Id desconocido, mal formado (no UUID) O id de otro tenant: RLS devuelve cero filas, así que los tres son indistinguibles por diseño (sin fuga de existencia, nunca un 403 para ids ajenos).
json
{
"error": {
"code": "not_found",
"message": "resource not found for this tenant"
}
}429 — ApiKeyRateLimited
Esta clave de API ha superado su cuota de peticiones, o las claves del tenant en conjunto han superado el techo del tenant (core#2503) (code rate_limited). La petición no se procesó. Espera Retry-After segundos y reintenta; un rechazo no cuenta contra el presupuesto, así que esa espera siempre basta. Acotado por clave de API y, por encima de las claves, por tenant (api_tenant_requests_per_minute): una clave hermana no se ve afectada hasta que las claves del tenant en conjunto alcanzan ese techo. La cuota se aplica a toda operación alcanzable con una clave dd_, así que las operaciones que nombran un 429 más específico (control de llamadas, disposiciones, SMS, …) PUEDEN responder TAMBIÉN este, con sus cabeceras X-RateLimit-*.
json
{
"error": {
"code": "rate_limited",
"message": "API key request quota exceeded; retry after the interval in Retry-After"
}
}502 — SupervisionFailed
El switch rechazó el comando de supervisión (la llamada ya terminó / el dispositivo del supervisor no está registrado).
json
{
"error": {
"code": "supervision_failed",
"message": "the switch rejected the supervision command"
}
}503 — SupervisionUnavailable
code audit_unavailable: no se pudo escribir la fila de evidencia, por lo que NO se envió ningún comando al switch (evidencia primero, fail-closed). codeesl_unavailable: el enlace de control del switch está caído. Ambos son reintentables.
audit_unavailable
json
{
"error": {
"code": "audit_unavailable",
"message": "supervision audit unavailable, retry"
}
}esl_unavailable
json
{
"error": {
"code": "esl_unavailable",
"message": "telephony control unavailable, retry"
}
}