Skip to content

Llamadas ​

Generado desde DialerDigital/core commit 0fc18008b3c8 — especificación openapi/dialer-v1.yaml v0.134.0. No se edita a mano; consulta Cómo se construye esta referencia. Descargar la especificación OpenAPI.

English version

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.

Verbos de control de llamadas en vivo (hold/unhold/mute/unmute/hangup), con evidencia primero.

Endpoints ​

MétodoRutaResumen
GET/v1/callsEstado de las llamadas para la superficie CTI (paginación por keyset, ?live=true para las que están en curso)
GET/v1/calls/{call_id}Una llamada por su call_uuid
POST/v1/calls/{call_id}/holdPoner en espera una llamada en vivo
POST/v1/calls/{call_id}/unholdLiberar una llamada en espera (vuelve a comprobar GATE_MID_CALL)
POST/v1/calls/{call_id}/muteSilenciar el micrófono del agente en una llamada en vivo
POST/v1/calls/{call_id}/unmuteReactivar el micrófono del agente en una llamada en vivo
POST/v1/calls/{call_id}/hangupColgar una llamada en vivo
POST/v1/calls/{call_id}/transferTransferir a ciegas una llamada en vivo a un destino interno o externo
POST/v1/calls/{call_id}/transfer/attended/startAbrir una consulta de transferencia asistida
POST/v1/calls/{call_id}/transfer/attended/completeCompletar la transferencia asistida: entregar la llamada al destino
POST/v1/calls/{call_id}/transfer/attended/cancelCancelar la consulta: la llamada se queda con su agente
POST/v1/calls/{call_id}/conference/addIncorporar a un colega, o a un número externo registrado, a la llamada (conferencia a tres)
POST/v1/calls/{call_id}/conference/removeSacar al colega de la llamada

Estado de las llamadas para la superficie CTI (paginación por keyset, ?live=true para las que están en curso) ​

http
GET /v1/calls

La mitad de lectura de la superficie CTI (WidgetAllowlist la preautoriza para ddw_): las mismas filas CDR de solo anexado que /v1/call_attempts, indexadas por call_uuid para los verbos de control, con ?live=true para restringir a las llamadas aún en curso (ended_at nulo, solo originales).

ALCANCE: un principal de tenant (dd_/ddu_) lee todo el piso y puede filtrar por cualquier agent_id; un principal de agente (ddw_) lee SOLO sus propias llamadas: el filtro agent_id se FUERZA al agente vinculado al token, y nombrar a cualquier otro agente es 403, nunca se reescribe en silencio. Solo el principal de agente recibe además debtor_name en cada llamada (la tarjeta de llamada del widget); consulta el esquema Call.

Parámetros

NombreEnTipoObligatorioDescripción
campaign_idquerystring (uuid)no
debt_idquerystring (uuid)no
agent_idquerystring (uuid)no
dispositionquerystringnoCoincidencia exacta contra un vocabulario ABIERTO: call_attempts.disposition se escribe TEXTUALMENTE (20260725000003_create_disposition_engine.exs) y los valores del motor — answered_human, abandoned, delivered, ai_conversation, answered_machine, ai_stream_lost, busy, no_answer, canceled, rejected, failed — son un SUBCONJUNTO NOMBRADO de él, no su frontera: los resultados tipificados del agente o de la IA (promise_to_pay, wrong_number) y los marcadores de plataforma (not_placed) son igualmente válidos. Un código desconocido responde 200 con cero filas, nunca 400. Lo que SÍ es 400 es una FORMA mal formada: la cadena vacía, y el parámetro repetido o enviado en forma de arreglo.
livequerybooleannotrue → solo las llamadas aún en curso (ended_at nulo; solo originales). Booleano estricto: cualquier otro valor es 400.
fromquerystring (date-time)noLímite inferior RFC 3339 (campo específico del endpoint; por defecto los últimos 30 días UTC donde se indica).
toquerystring (date-time)noLímite superior RFC 3339.
limitqueryintegernoTamaño de página (por defecto 100, máximo 1000).
cursorquerystringnoCursor keyset opaco del next_cursor de la página anterior.

Respuestas

200 ​

Una página de llamadas.

CampoTipoObligatorioDescripción
callsarreglo de Callsí
next_cursorstring | nullsíCursor keyset opaco; null en la última página.

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 — Forbidden ​

El tenant está suspendido. Una sesión del dashboard (ddu_) de un tenant cuya política de inicio de sesión (ADR 227) está en modo enforce responde 403 con el código login_policy_denied ante una solicitud desde una dirección o en una hora que la política no permite — el mismo cuerpo en ambos casos; la sesión no se revoca y una solicitud posterior dentro de la política se procesa. Un token de widget (ddw_) de un puesto queda sujeto a la misma política en cada solicitud (core#2406, indicador widget_login_honors_policy). Un tenant sintético (demo) responde 403 con el código synthetic_tenant en toda ruta que llegaría a un tercero — marcación manual, pierna de transferencia externa o de conferencia, envío de SMS (core#2251, adenda del ADR #280). Ningún pago lo cambia.

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

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"
  }
}

Una llamada por su call_uuid ​

http
GET /v1/calls/{call_id}

La fila CDR ORIGINAL de la llamada (corrects_id nulo: la fila sobre la que operan los verbos de control). La titularidad refleja la de los verbos: un principal ddw_ solo puede leer una llamada que le pertenece (403 en caso contrario: los verbos ya revelan la titularidad, así que una lectura no gana nada enmascarándola como 404); un call_id ajeno o desconocido es 404. También incluye transfer_chain, las piernas de la llamada en orden (core#2403): [] cuando nadie la transfirió; una cadena que no se puede leer es 503, nunca [].

Parámetros

NombreEnTipoObligatorioDescripción
call_idpathstring (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).

Respuestas

200 ​

La llamada.

CampoTipoObligatorioDescripción
callanysíCall más transfer_chain (core#2403): las piernas de la llamada en orden, [] cuando nadie la transfirió.

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 — Forbidden ​

El tenant está suspendido. Una sesión del dashboard (ddu_) de un tenant cuya política de inicio de sesión (ADR 227) está en modo enforce responde 403 con el código login_policy_denied ante una solicitud desde una dirección o en una hora que la política no permite — el mismo cuerpo en ambos casos; la sesión no se revoca y una solicitud posterior dentro de la política se procesa. Un token de widget (ddw_) de un puesto queda sujeto a la misma política en cada solicitud (core#2406, indicador widget_login_honors_policy). Un tenant sintético (demo) responde 403 con el código synthetic_tenant en toda ruta que llegaría a un tercero — marcación manual, pierna de transferencia externa o de conferencia, envío de SMS (core#2251, adenda del ADR #280). Ningún pago lo cambia.

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

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"
  }
}

503 ​

No se pudo leer la evidencia; reintenta. Falla de forma cerrada — nunca una respuesta vacía.

Poner en espera una llamada en vivo ​

http
POST /v1/calls/{call_id}/hold

Pone en espera la pierna del AGENTE para que el consumidor oiga la música de espera (evidencia primero: se escribe una fila call_control_actions antes del comando ESL). 409 cuando la llamada no tiene una pierna de agente en puente.

Parámetros

NombreEnTipoObligatorioDescripción
call_idpathstring (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).

Respuestas

200 ​

En espera (fila de auditoría durable).

CampoTipoObligatorioDescripción
callobject (CallControlResult)sí
call.verbhold · unhold · mute · unmute · hangup · blind_transfer · attended_transfer_start · attended_transfer_complete · attended_transfer_cancelno
call.call_idstringno
call.audit_idstring (uuid)noLa fila durable call_control_actions.
call.to_numberstringnoÚltimos 4 enmascarados (***0184) — el E.164 completo nunca cruza esta superficie.
call.bridge_confirm_bystring,null (date-time)noSolo attended_transfer_complete. Cuando core comprueba que el consumidor está en puente con el destino; un consumidor que aún no está en puente en ese momento se cuelga con la causa NORMAL_UNSPECIFIED. null cuando no se pudo armar esa comprobación.

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"
  }
}

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"
  }
}

409 — Conflict ​

Transición de estado no válida, conflicto de unicidad, o un asiento que está ocupado/reservado.

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

429 — CallControlThrottled ​

El freno de tasa de solicitudes NR-18 rechazó esta solicitud (reintentable en la próxima ventana). code rate_limited. Se acota por el principal DURABLE MÁS ESPECÍFICO (agente > usuario > tenant), nunca por tenant cuando existe uno más estrecho, de modo que una sola página hostil no pueda limitar a los agentes hermanos. Durable significa que el presupuesto sobrevive a la reautenticación: volver a iniciar sesión emite un token nuevo pero no compra un presupuesto nuevo. Todos los verbos con freno (los cuatro de alternancia y la transferencia a ciegas) comparten UN solo presupuesto; hangup está exento y nunca responde 429, porque rechazar un corte dejaría viva una llamada que su operador pidió terminar. Se rechaza ANTES de buscar la llamada, así que esta respuesta es idéntica exista o no el call_id. Retry-After es el tiempo que queda en la ventana fija.

json
{
  "error": {
    "code": "rate_limited",
    "message": "call control rate limit exceeded; retry later"
  }
}

502 — CallControlFailed ​

El switch rechazó el comando de control (la llamada ya terminó / la pierna ya no existe). La fila de auditoría queda en failed.

json
{
  "error": {
    "code": "call_control_failed",
    "message": "the switch rejected the control command"
  }
}

503 — CallControlUnavailable ​

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 o agotó el tiempo de espera. Ambos son reintentables.

audit_unavailable

json
{
  "error": {
    "code": "audit_unavailable",
    "message": "call-control audit unavailable, retry"
  }
}

esl_unavailable

json
{
  "error": {
    "code": "esl_unavailable",
    "message": "telephony control unavailable, retry"
  }
}

Liberar una llamada en espera (vuelve a comprobar GATE_MID_CALL) ​

http
POST /v1/calls/{call_id}/unhold

Libera la espera. Vuelve a evaluar el trío de mitad de llamada: revocación del consentimiento, orden escrita de cese y desistimiento (lecturas en vivo) y horario de silencio según la(s) zona(s) horaria(s) del consumidor congeladas en la instantánea de cumplimiento de la llamada. Si se bloquea -> 422: la llamada sigue en espera y se programa un corte automático (auto_hangup_at en el cuerpo, C9) para que el consumidor nunca quede en espera indefinidamente. 409 cuando la llamada no tiene una pierna de agente en puente.

Parámetros

NombreEnTipoObligatorioDescripción
call_idpathstring (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).

Respuestas

200 ​

Liberada (fila de auditoría durable).

CampoTipoObligatorioDescripción
callobject (CallControlResult)sí
call.verbhold · unhold · mute · unmute · hangup · blind_transfer · attended_transfer_start · attended_transfer_complete · attended_transfer_cancelno
call.call_idstringno
call.audit_idstring (uuid)noLa fila durable call_control_actions.
call.to_numberstringnoÚltimos 4 enmascarados (***0184) — el E.164 completo nunca cruza esta superficie.
call.bridge_confirm_bystring,null (date-time)noSolo attended_transfer_complete. Cuando core comprueba que el consumidor está en puente con el destino; un consumidor que aún no está en puente en ese momento se cuelga con la causa NORMAL_UNSPECIFIED. null cuando no se pudo armar esa comprobación.

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"
  }
}

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"
  }
}

409 — Conflict ​

Transición de estado no válida, conflicto de unicidad, o un asiento que está ocupado/reservado.

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

422 — MidCallComplianceBlocked ​

La nueva comprobación de GATE_MID_CALL rechazó la liberación: se revocó el consentimiento del consumidor, hay una orden escrita de cese y desistimiento registrada, o la(s) zona(s) horaria(s) congeladas del consumidor están fuera de la ventana de horario de silencio. La llamada SIGUE en espera y se programa un corte automático (auto_hangup_at, C9): un consumidor nunca queda en espera indefinidamente tras un bloqueo de cumplimiento. Sin decision_id: es una comprobación barata de mitad de llamada, no una decisión del motor; la fila durable call_control_actions es la evidencia.

json
{
  "error": {
    "code": "compliance_blocked",
    "message": "the mid-call compliance re-check refused this unhold (quiet_hours)",
    "gate": "mid_call",
    "reason_code": "quiet_hours",
    "rule_id": "fdcpa.quiet_hours.v1",
    "consumer_timezone": "America/Chicago",
    "consumer_local_time": "2026-07-06T21:12:09-05:00",
    "auto_hangup_at": "2026-07-07T02:17:09Z"
  }
}

429 — CallControlThrottled ​

El freno de tasa de solicitudes NR-18 rechazó esta solicitud (reintentable en la próxima ventana). code rate_limited. Se acota por el principal DURABLE MÁS ESPECÍFICO (agente > usuario > tenant), nunca por tenant cuando existe uno más estrecho, de modo que una sola página hostil no pueda limitar a los agentes hermanos. Durable significa que el presupuesto sobrevive a la reautenticación: volver a iniciar sesión emite un token nuevo pero no compra un presupuesto nuevo. Todos los verbos con freno (los cuatro de alternancia y la transferencia a ciegas) comparten UN solo presupuesto; hangup está exento y nunca responde 429, porque rechazar un corte dejaría viva una llamada que su operador pidió terminar. Se rechaza ANTES de buscar la llamada, así que esta respuesta es idéntica exista o no el call_id. Retry-After es el tiempo que queda en la ventana fija.

json
{
  "error": {
    "code": "rate_limited",
    "message": "call control rate limit exceeded; retry later"
  }
}

502 — CallControlFailed ​

El switch rechazó el comando de control (la llamada ya terminó / la pierna ya no existe). La fila de auditoría queda en failed.

json
{
  "error": {
    "code": "call_control_failed",
    "message": "the switch rejected the control command"
  }
}

503 — CallControlUnavailable ​

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 o agotó el tiempo de espera. Ambos son reintentables.

audit_unavailable

json
{
  "error": {
    "code": "audit_unavailable",
    "message": "call-control audit unavailable, retry"
  }
}

esl_unavailable

json
{
  "error": {
    "code": "esl_unavailable",
    "message": "telephony control unavailable, retry"
  }
}

Silenciar el micrófono del agente en una llamada en vivo ​

http
POST /v1/calls/{call_id}/mute

Silencia el audio que el agente envía al puente (su micrófono), con evidencia primero. 409 cuando la llamada no tiene una pierna de agente en puente.

Parámetros

NombreEnTipoObligatorioDescripción
call_idpathstring (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).

Respuestas

200 ​

Silenciada (fila de auditoría durable).

CampoTipoObligatorioDescripción
callobject (CallControlResult)sí
call.verbhold · unhold · mute · unmute · hangup · blind_transfer · attended_transfer_start · attended_transfer_complete · attended_transfer_cancelno
call.call_idstringno
call.audit_idstring (uuid)noLa fila durable call_control_actions.
call.to_numberstringnoÚltimos 4 enmascarados (***0184) — el E.164 completo nunca cruza esta superficie.
call.bridge_confirm_bystring,null (date-time)noSolo attended_transfer_complete. Cuando core comprueba que el consumidor está en puente con el destino; un consumidor que aún no está en puente en ese momento se cuelga con la causa NORMAL_UNSPECIFIED. null cuando no se pudo armar esa comprobación.

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"
  }
}

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"
  }
}

409 — Conflict ​

Transición de estado no válida, conflicto de unicidad, o un asiento que está ocupado/reservado.

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

429 — CallControlThrottled ​

El freno de tasa de solicitudes NR-18 rechazó esta solicitud (reintentable en la próxima ventana). code rate_limited. Se acota por el principal DURABLE MÁS ESPECÍFICO (agente > usuario > tenant), nunca por tenant cuando existe uno más estrecho, de modo que una sola página hostil no pueda limitar a los agentes hermanos. Durable significa que el presupuesto sobrevive a la reautenticación: volver a iniciar sesión emite un token nuevo pero no compra un presupuesto nuevo. Todos los verbos con freno (los cuatro de alternancia y la transferencia a ciegas) comparten UN solo presupuesto; hangup está exento y nunca responde 429, porque rechazar un corte dejaría viva una llamada que su operador pidió terminar. Se rechaza ANTES de buscar la llamada, así que esta respuesta es idéntica exista o no el call_id. Retry-After es el tiempo que queda en la ventana fija.

json
{
  "error": {
    "code": "rate_limited",
    "message": "call control rate limit exceeded; retry later"
  }
}

502 — CallControlFailed ​

El switch rechazó el comando de control (la llamada ya terminó / la pierna ya no existe). La fila de auditoría queda en failed.

json
{
  "error": {
    "code": "call_control_failed",
    "message": "the switch rejected the control command"
  }
}

503 — CallControlUnavailable ​

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 o agotó el tiempo de espera. Ambos son reintentables.

audit_unavailable

json
{
  "error": {
    "code": "audit_unavailable",
    "message": "call-control audit unavailable, retry"
  }
}

esl_unavailable

json
{
  "error": {
    "code": "esl_unavailable",
    "message": "telephony control unavailable, retry"
  }
}

Reactivar el micrófono del agente en una llamada en vivo ​

http
POST /v1/calls/{call_id}/unmute

Restablece el audio del micrófono del agente, con evidencia primero.

Parámetros

NombreEnTipoObligatorioDescripción
call_idpathstring (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).

Respuestas

200 ​

Silencio retirado (fila de auditoría durable).

CampoTipoObligatorioDescripción
callobject (CallControlResult)sí
call.verbhold · unhold · mute · unmute · hangup · blind_transfer · attended_transfer_start · attended_transfer_complete · attended_transfer_cancelno
call.call_idstringno
call.audit_idstring (uuid)noLa fila durable call_control_actions.
call.to_numberstringnoÚltimos 4 enmascarados (***0184) — el E.164 completo nunca cruza esta superficie.
call.bridge_confirm_bystring,null (date-time)noSolo attended_transfer_complete. Cuando core comprueba que el consumidor está en puente con el destino; un consumidor que aún no está en puente en ese momento se cuelga con la causa NORMAL_UNSPECIFIED. null cuando no se pudo armar esa comprobación.

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"
  }
}

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"
  }
}

409 — Conflict ​

Transición de estado no válida, conflicto de unicidad, o un asiento que está ocupado/reservado.

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

429 — CallControlThrottled ​

El freno de tasa de solicitudes NR-18 rechazó esta solicitud (reintentable en la próxima ventana). code rate_limited. Se acota por el principal DURABLE MÁS ESPECÍFICO (agente > usuario > tenant), nunca por tenant cuando existe uno más estrecho, de modo que una sola página hostil no pueda limitar a los agentes hermanos. Durable significa que el presupuesto sobrevive a la reautenticación: volver a iniciar sesión emite un token nuevo pero no compra un presupuesto nuevo. Todos los verbos con freno (los cuatro de alternancia y la transferencia a ciegas) comparten UN solo presupuesto; hangup está exento y nunca responde 429, porque rechazar un corte dejaría viva una llamada que su operador pidió terminar. Se rechaza ANTES de buscar la llamada, así que esta respuesta es idéntica exista o no el call_id. Retry-After es el tiempo que queda en la ventana fija.

json
{
  "error": {
    "code": "rate_limited",
    "message": "call control rate limit exceeded; retry later"
  }
}

502 — CallControlFailed ​

El switch rechazó el comando de control (la llamada ya terminó / la pierna ya no existe). La fila de auditoría queda en failed.

json
{
  "error": {
    "code": "call_control_failed",
    "message": "the switch rejected the control command"
  }
}

503 — CallControlUnavailable ​

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 o agotó el tiempo de espera. Ambos son reintentables.

audit_unavailable

json
{
  "error": {
    "code": "audit_unavailable",
    "message": "call-control audit unavailable, retry"
  }
}

esl_unavailable

json
{
  "error": {
    "code": "esl_unavailable",
    "message": "telephony control unavailable, retry"
  }
}

Colgar una llamada en vivo ​

http
POST /v1/calls/{call_id}/hangup

Termina la llamada (cierra la pierna del consumidor), con evidencia primero. El pipeline de CDR emite call.ended cuando la pierna muere.

Parámetros

NombreEnTipoObligatorioDescripción
call_idpathstring (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).

Respuestas

200 ​

Corte emitido (fila de auditoría durable).

CampoTipoObligatorioDescripción
callobject (CallControlResult)sí
call.verbhold · unhold · mute · unmute · hangup · blind_transfer · attended_transfer_start · attended_transfer_complete · attended_transfer_cancelno
call.call_idstringno
call.audit_idstring (uuid)noLa fila durable call_control_actions.
call.to_numberstringnoÚltimos 4 enmascarados (***0184) — el E.164 completo nunca cruza esta superficie.
call.bridge_confirm_bystring,null (date-time)noSolo attended_transfer_complete. Cuando core comprueba que el consumidor está en puente con el destino; un consumidor que aún no está en puente en ese momento se cuelga con la causa NORMAL_UNSPECIFIED. null cuando no se pudo armar esa comprobación.

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"
  }
}

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"
  }
}

502 — CallControlFailed ​

El switch rechazó el comando de control (la llamada ya terminó / la pierna ya no existe). La fila de auditoría queda en failed.

json
{
  "error": {
    "code": "call_control_failed",
    "message": "the switch rejected the control command"
  }
}

503 — CallControlUnavailable ​

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 o agotó el tiempo de espera. Ambos son reintentables.

audit_unavailable

json
{
  "error": {
    "code": "audit_unavailable",
    "message": "call-control audit unavailable, retry"
  }
}

esl_unavailable

json
{
  "error": {
    "code": "esl_unavailable",
    "message": "telephony control unavailable, retry"
  }
}

Transferir a ciegas una llamada en vivo a un destino interno o externo ​

http
POST /v1/calls/{call_id}/transfer

Mueve la pierna del CONSUMIDOR a otro destino (uuid_transfer), con evidencia primero; la pierna del agente de origen muere con el puente roto. La llamada se entrega de inmediato: no hay pierna de consulta ni vuelta atrás. Cuando el agente necesita hablar primero con el destino, es la transferencia asistida de más abajo.

destination es una de TRES clases, cada una sujeta a sus propias condiciones:

  • un sip_extension del directorio o un id de agente (UUID) de un agente ACTIVO del tenant del solicitante cuyo puesto esté LIBRE en este momento;
  • una extensión del directorio sin ningún agente detrás;
  • un número PSTN EXTERNO en E.164 estricto (+<country><number>), o el id de uno de los destinos externos registrados VIGENTES del tenant: core lo resuelve a su E.164 y se somete a las mismas compuertas que ese número (GET /v1/transfer/targets los lista SIN el número, que es lo que envía un selector de widget).

El directorio se consulta PRIMERO, de modo que un tenant cuyas extensiones tengan 10 dígitos sigue transfiriendo internamente. Una cadena con forma de número que no sea E.164 se rechaza con 422 destination_not_supported: la jurisdicción que decide si se puede colocar la nueva pierna se resuelve A PARTIR del número de destino, y una cadena nacional sin país no puede responderlo.

Un destino externo debe estar REGISTRADO primero (POST /v1/transfer-destinations). Cualquier otro E.164 se rechaza con 422compliance_blocked, gate: pre_dial, rule_idtransfer.destination_unregistered.v1, antes de que corra la cadena de abajo y sin decision_id (el motor nunca corrió). Un registro que no se puede leer también bloquea (transfer.destination_registry_unavailable.v1). Un destino registrado aun así pasa toda la cadena de abajo.

Una transferencia externa ORIGINA UNA NUEVA PIERNA, por lo que pasa la misma cadena GATE_PRE_DIAL que una marcación (consentimiento, DNC, horario de silencio, Reg F, matriz estatal, divulgación). Se evalúa como lo que es: una llamada al DESTINO: DNC lee el estado de supresión del destino y el horario de silencio se resuelve con el NPA propio del destino. Un bloqueo responde 422 compliance_blocked con gate: pre_dial y el decision_id del motor; no se marca nada. Un E.164 que no sea NANP bloquea: una celda USA no tiene ventana de horario de silencio para él.

Qué pregunta cada compuerta de esa cadena sobre el destino y qué lo deja pasar:

  • Consentimiento (tcpa.consent.v1). Una revocación de consentimiento registrada para el número bloquea (consent_revoked). De lo contrario se exige consentimiento expreso previo, como para un móvil, salvo que se cumpla una de tres condiciones: hay consentimiento registrado para el número; el line_type que el tenant DECLARÓ para el destino registrado es landline; o está activa la postura de iniciativa humana del tenant (human_initiated_enabled, DESACTIVADA por defecto, solo admin). unknown (el valor por defecto de un registro), mobile y voip lo exigen (tcpa_no_consent).
  • DNC (dnc.lists.v1 y la Reassigned Numbers Database). El destino no debe estar en ninguna lista de supresión, y la RND debe responder que no fue reasignado desde el instante del registro. El line_type declarado no cambia nada aquí.
  • Horario de silencio: la ventana propia del destino, según su NPA.
  • Reg F y la matriz estatal leen el historial de intentos del consumidor y la deuda de la solicitud, que esta pierna deja VACÍO: la parte del otro extremo no es el deudor.
  • Divulgación y voz artificial: en una transferencia no se reproduce nada pregrabado ni sintético, así que no tienen nada que exigir.

El caller-ID de una pierna externa es el DID que esta llamada ya presenta: nunca se elige en el momento de la transferencia, porque el caller-ID rota por turnos sobre el pool que configuró el operador. Una llamada sin DID del tenant que presentar se rechaza con 422 caller_id_unavailable en lugar de marcarse con el número por defecto del gateway del carrier.

La pierna externa es su propio intento de llamada, facturado solo si establece puente. Antes de tocar el switch, la pierna obtiene su propia fila call_attempts (sin deudor: nunca cuenta contra los intentos Reg F del deudor) y su propio listener. Lo que se cobra son outbound_minutes desde el CHANNEL_BRIDGE de la pierna hasta su corte, tarificados en Decimal como cualquier marcación; nunca desde el acuse de uuid_transfer, que llega antes de que suene el otro extremo. Una pierna que nunca estableció puente se cierra sin answered_at y no cuesta nada.

Una pierna house sale por un carrier que eligió el LCR, medida contra la tasa de llamadas contratada de ese carrier. La misma selección de ruta que usa una marcación elige el carrier de la pierna; la ruta se registra con el intento de la pierna y viaja al borde como el carrier a usar. Una pierna house sin ruta (enrutamiento desactivado, ningún carrier candidato) se rechaza con 503 no_route, y un carrier que ya está en sus llamadas por segundo contratadas la rechaza con 429carrier_cps. Ambos ocurren antes de escribir o marcar nada, de modo que el consumidor se queda con su agente. La pierna de un tenant BYOC sale por su propio troncal, sin ruta ni medición de carrier.

Sujeta a compuerta como unhold también del lado del CONSUMIDOR: la llamada vuelve a audio en vivo, así que el trío GATE_MID_CALL (revocación de consentimiento, cese y desistimiento, horario de silencio) se vuelve a comprobar ANTES de tocar el switch y rechaza con 422 compliance_blocked, gate: mid_call. Y como esta fase NO mueve el puesto del agente, un destino INTERNO cuyo puesto está ocupado se rechaza con 422destination_unavailable en lugar de duplicar la reserva.

Si tiene éxito, se estampa una fila control_handoff: nombra al agente DESTINO en una transferencia interna (desde entonces la compuerta de titularidad autoriza a ese agente y rechaza al de origen), y no lleva agente en una externa: el control salió de la población de agentes, de modo que ningún principal con alcance de agente puede manejar la llamada después. El agent_id de la llamada nunca se toca; sigue diciendo dónde empezó la llamada.

Parámetros

NombreEnTipoObligatorioDescripción
call_idpathstring (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)

CampoTipoObligatorioDescripción
destinationstringsísip_extension / id de agente interno, o un destino externo en E.164 estricto (+<country><number>, de 8 a 15 dígitos) o por su id de registro. El servidor RECORTA el valor antes de validarlo y exige que no esté en blanco y que tenga como máximo 64 BYTES una vez recortado; minLength/ maxLength aquí cuentan CARACTERES sobre el valor sin procesar, de modo que una cadena solo de espacios los satisface y aun así recibe un 400. Un valor con forma de número que NO sea E.164 (dígitos nacionales sueltos, una cadena + mal formada) se rechaza con 422 destination_not_supported.

Respuestas

200 ​

Transferencia emitida (fila de auditoría durable, traspaso estampado).

CampoTipoObligatorioDescripción
callobject (CallControlResult)sí
call.verbhold · unhold · mute · unmute · hangup · blind_transfer · attended_transfer_start · attended_transfer_complete · attended_transfer_cancelno
call.call_idstringno
call.audit_idstring (uuid)noLa fila durable call_control_actions.
call.to_numberstringnoÚltimos 4 enmascarados (***0184) — el E.164 completo nunca cruza esta superficie.
call.bridge_confirm_bystring,null (date-time)noSolo attended_transfer_complete. Cuando core comprueba que el consumidor está en puente con el destino; un consumidor que aún no está en puente en ese momento se cuelga con la causa NORMAL_UNSPECIFIED. null cuando no se pudo armar esa comprobación.

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 ​

El plan del tenant no está activo (o no se pudo leer: fail-closed). Una transferencia EXTERNA compra minutos de carrier igual que una marcación, así que pasa la misma compuerta de tráfico del plan que una marcación (ADR #39). Una transferencia INTERNA nunca la recibe: mover una llamada entre dos agentes del mismo tenant no compra nada a un carrier.

json
{
  "error": {
    "code": "plan_inactive",
    "message": "tenant plan is not active; traffic is gated"
  }
}

403 — Forbidden ​

El tenant está suspendido. Una sesión del dashboard (ddu_) de un tenant cuya política de inicio de sesión (ADR 227) está en modo enforce responde 403 con el código login_policy_denied ante una solicitud desde una dirección o en una hora que la política no permite — el mismo cuerpo en ambos casos; la sesión no se revoca y una solicitud posterior dentro de la política se procesa. Un token de widget (ddw_) de un puesto queda sujeto a la misma política en cada solicitud (core#2406, indicador widget_login_honors_policy). Un tenant sintético (demo) responde 403 con el código synthetic_tenant en toda ruta que llegaría a un tercero — marcación manual, pierna de transferencia externa o de conferencia, envío de SMS (core#2251, adenda del ADR #280). Ningún pago lo cambia.

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

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"
  }
}

422 — TransferRefused ​

La transferencia a ciegas nunca llegó al switch. Tres familias de rechazo comparten este estado, y gate (cuando está presente) indica qué punto de control la rechazó.

La nueva comprobación de GATE_MID_CALL la rechazó: code compliance_blocked, gate mid_call, con el mismo envelope que devuelve unhold (reason_code, rule_id, auto_hangup_at): consentimiento revocado, una orden escrita de cese y desistimiento registrada, o la(s) zona(s) horaria(s) congeladas del consumidor fuera de la ventana de horario de silencio. Una transferencia devuelve al consumidor a audio en vivo igual que un unhold, por lo que se somete a la misma compuerta; de lo contrario un unhold bloqueado podría eludirse transfiriendo la misma llamada. Se arma el corte automático C9.

La cadena GATE_PRE_DIAL rechazó la NUEVA PIERNA: codecompliance_blocked, gate pre_dial, con el decision_id y el rule_id del motor. Solo un destino EXTERNO puede recibirlo: la pierna que crearía es una originación y pasa la misma cadena que una marcación, evaluada contra el número de DESTINO (su estado DNC, la ventana de horario de silencio de su NPA). NO se marcó NADA, NO se armó NADA y la propia llamada del consumidor no se toca: sigue hablando con su agente. reason_code engine_unavailable es la respuesta fail-closed cuando la compuerta no pudo evaluarse en absoluto: una compuerta que no puede decidir bloquea. reason_code destination_unregistered (rule_idtransfer.destination_unregistered.v1) es el rechazo de un E.164 que el tenant nunca registró en /v1/transfer-destinations, y destination_registry_unavailable la respuesta fail-closed cuando ese registro no pudo leerse; ambos van antes de la cadena, sin decision_id. reason_code destination_not_allowed (rule_idegress.destination_not_allowed.v1) es el rechazo de un E.164 fuera de la lista de destinos permitidos de un troncal BYOC de la sede (core#1281), y destination_allowlist_unavailable (egress.destination_allowlist_unavailable.v1) la respuesta fail-closed cuando esa lista no pudo leerse; ambos van antes del registro, con decision_id cuando se escribió su fila gate_blocks.

O el propio destino fue rechazado: envelope ErrorEnvelope. code destination_not_supported: el destino tiene forma de número pero no es E.164 estricto (dígitos nacionales sueltos, una cadena + mal formada). Los destinos externos se marcan solo desde E.164, porque la jurisdicción se resuelve a partir de ese número. code destination_not_found: cualquier otra cosa que no se resuelva a un agente activo del directorio de ESTE tenant. La división se decide por la FORMA de lo enviado, nunca por una segunda búsqueda, por lo que ninguna de las dos respuestas dice si el destino existe en otro tenant. code destination_unavailable: el destino ES un agente activo de este tenant, pero su puesto no está en :available en este momento (sonando, en una llamada, en cierre de la llamada, en pausa o sin registrarse). Esta fase no mueve el puesto, así que transferir a un agente ocupado lo duplicaría; esta respuesta solo nombra a un agente del directorio PROPIO del solicitante, por lo que tampoco es un oráculo entre tenants. codecaller_id_unavailable: una transferencia EXTERNA en una llamada que no tiene DID del tenant que presentar: se rechaza en lugar de marcarse con el ANI por defecto del gateway del carrier, que el tenant puede no poseer. code did_unverified (core#2493): el DID que presentaría la pierna externa (en una llamada entrante, el número que marcó el consumidor) es un DID de tipo customer cuya titularidad nunca se verificó, y la clave de tenant did_ownership_proof es enforce. Con observe la pierna sale y dialer_dids_unverified_use_total{surface="voice_transfer"} la cuenta; con off nada cambia. Aplica a una transferencia a ciegas externa y a una adición externa a conferencia.

En todos los casos la fila call_control_actions queda en failed con el destino solicitado registrado; se ejecutaron CERO comandos ESL y la llamada no se toca.

O la consulta nunca se atendió (solo transferencia asistida): code consultation_unanswered: el destino no está registrado, está ocupado o no contestó la pierna de consulta. Es un 422 y no un 502 porque el switch funcionó y una persona no contestó. LA ESPERA YA SE HA LIBERADO: el consumidor vuelve con su agente antes de que se escriba esta respuesta, y no queda ninguna consulta abierta.

O la pierna de conferencia nunca se atendió (solo agregar a conferencia): codeconference_unanswered: el colega no está registrado, está ocupado o no contestó. Un 422 y no un 502 por la misma razón; la llamada continúa exactamente como estaba y no queda ninguna conferencia abierta.

destination_not_found

json
{
  "error": {
    "code": "destination_not_found",
    "message": "no active agent with that destination in this tenant"
  }
}

destination_not_supported

json
{
  "error": {
    "code": "destination_not_supported",
    "message": "an external transfer destination must be E.164 (+<country><number>)"
  }
}

destination_unavailable

json
{
  "error": {
    "code": "destination_unavailable",
    "message": "that agent is not available to take a transfer right now"
  }
}

caller_id_unavailable

json
{
  "error": {
    "code": "caller_id_unavailable",
    "message": "this call has no tenant caller-ID to present on a transferred leg"
  }
}

did_unverified

json
{
  "error": {
    "code": "did_unverified",
    "message": "the caller-ID this transferred leg would present is not a verified number of the tenant"
  }
}

compliance_blocked_mid_call

json
{
  "error": {
    "code": "compliance_blocked",
    "message": "the mid-call compliance re-check refused this blind_transfer (consent_revoked)",
    "gate": "mid_call",
    "reason_code": "consent_revoked",
    "rule_id": "regf.revocation.v1"
  }
}

compliance_blocked_pre_dial

json
{
  "error": {
    "code": "compliance_blocked",
    "message": "the origination gate refused the leg this blind_transfer would create (dnc_listed)",
    "gate": "pre_dial",
    "reason_code": "dnc_listed",
    "rule_id": "dnc.lists.v1",
    "decision_id": "018f3f2a-0000-7000-8000-000000000000"
  }
}

429 — TransferThrottled ​

code rate_limited: el freno de tasa de solicitudes NR-18, exactamente como lo describe CallControlThrottled (rechazado antes de buscar la llamada). code carrier_cps: una transferencia EXTERNA cuya pierna saldría por un carrier que ya está en sus llamadas por segundo contratadas en este segundo. No se escribió ni marcó nada y el consumidor sigue con su agente. Reintentable en menos de un segundo. rate_limited lleva Retry-After (tiempo que queda en la ventana fija); carrier_cps no. code tenant_channels / tenant_cps (solo agregar a conferencia un número EXTERNO): el tercero es un canal más del tenant, que está en su tope de canales o en su ventana de tasa de llamadas; no se marcó nada y la llamada sigue con las personas que ya están en ella.

rate_limited

json
{
  "error": {
    "code": "rate_limited",
    "message": "call control rate limit exceeded; retry later"
  }
}

carrier_cps

json
{
  "error": {
    "code": "carrier_cps",
    "message": "the carrier for the transferred leg is at its contracted call rate; retry"
  }
}

tenant_channels

json
{
  "error": {
    "code": "tenant_channels",
    "message": "the tenant is at its channel or call-rate ceiling; the third party was not dialled"
  }
}

502 — CallControlFailed ​

El switch rechazó el comando de control (la llamada ya terminó / la pierna ya no existe). La fila de auditoría queda en failed.

json
{
  "error": {
    "code": "call_control_failed",
    "message": "the switch rejected the control command"
  }
}

503 — TransferUnavailable ​

Los cuatro códigos 503 de una transferencia a ciegas. audit_unavailable y esl_unavailable son los que describe CallControlUnavailable. Otros dos aplican solo a un destino EXTERNO. no_route: la pierna house no tiene una ruta de carrier dirigida (enrutamiento desactivado, ningún carrier candidato), por lo que no se coloca, porque el tráfico house siempre es dirigido. capacity_unavailable: la compuerta de capacidad no pudo admitir el carrier de la pierna, y falla en modo cerrado. En ambos casos no se escribió ni marcó nada.

audit_unavailable

json
{
  "error": {
    "code": "audit_unavailable",
    "message": "call-control audit unavailable, retry"
  }
}

esl_unavailable

json
{
  "error": {
    "code": "esl_unavailable",
    "message": "telephony control unavailable, retry"
  }
}

no_route

json
{
  "error": {
    "code": "no_route",
    "message": "no directed carrier route for the transferred leg; nothing was dialled"
  }
}

capacity_unavailable

json
{
  "error": {
    "code": "capacity_unavailable",
    "message": "the capacity gate could not admit the transferred leg, retry"
  }
}

Abrir una consulta de transferencia asistida ​

http
POST /v1/calls/{call_id}/transfer/attended/start

Pone al CONSUMIDOR en MÚSICA DE ESPERA y abre una pierna de consulta privada al destino para que el agente pueda hablar con él ANTES de entregarle la llamada. Todavía no se transfiere nada y no se rompe ningún puente: el consumidor sigue en puente con su agente durante toda la consulta, lo que hace que .../cancel sea una restauración y no una reparación.

QUÉ OYE CADA PARTE, dicho explícitamente. El consumidor oye música de espera (la misma MOH que transmite el verbo hold, no silencio). El destino se oye SOLO con el AGENTE (la pierna de consulta es la pierna de susurro de supervisión), así que nada de lo dicho durante la consulta llega al consumidor. El destino, al estar en una pierna que oye la llamada, puede oír a un consumidor que siga hablando: es la consulta funcionando como se diseñó, y se indica aquí para que no se descubra por sorpresa.

destination se valida exactamente como el de la transferencia a ciegas: un agente ACTIVO de ESTE tenant, por extensión del directorio o id de agente, cuyo puesto esté libre en este momento. Los destinos externos/con forma PSTN se rechazan con 422destination_not_supported (esta fase es solo interna).

NO sujeta a GATE_MID_CALL, deliberadamente: este verbo solo quita el audio del consumidor, igual que hold. La compuerta corre en .../complete y .../cancel, que son los verbos que lo devuelven a audio en vivo.

UNA CONSULTA POR LLAMADA: un segundo start mientras hay una abierta es 409consultation_in_progress. Si el destino no atiende la pierna de consulta, la espera se LIBERA antes de devolver el 422consultation_unanswered: el consumidor vuelve con su agente antes de que quien llama lea el error.

Parámetros

NombreEnTipoObligatorioDescripción
call_idpathstring (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)

CampoTipoObligatorioDescripción
destinationstringsísip_extension / id de agente interno, o un destino externo en E.164 estricto (+<country><number>, de 8 a 15 dígitos) o por su id de registro. El servidor RECORTA el valor antes de validarlo y exige que no esté en blanco y que tenga como máximo 64 BYTES una vez recortado; minLength/ maxLength aquí cuentan CARACTERES sobre el valor sin procesar, de modo que una cadena solo de espacios los satisface y aun así recibe un 400. Un valor con forma de número que NO sea E.164 (dígitos nacionales sueltos, una cadena + mal formada) se rechaza con 422 destination_not_supported.

Respuestas

200 ​

Consulta abierta (fila de auditoría durable, pierna de consulta establecida).

CampoTipoObligatorioDescripción
callobject (CallControlResult)sí
call.verbhold · unhold · mute · unmute · hangup · blind_transfer · attended_transfer_start · attended_transfer_complete · attended_transfer_cancelno
call.call_idstringno
call.audit_idstring (uuid)noLa fila durable call_control_actions.
call.to_numberstringnoÚltimos 4 enmascarados (***0184) — el E.164 completo nunca cruza esta superficie.
call.bridge_confirm_bystring,null (date-time)noSolo attended_transfer_complete. Cuando core comprueba que el consumidor está en puente con el destino; un consumidor que aún no está en puente en ese momento se cuelga con la causa NORMAL_UNSPECIFIED. null cuando no se pudo armar esa comprobación.

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 — Forbidden ​

El tenant está suspendido. Una sesión del dashboard (ddu_) de un tenant cuya política de inicio de sesión (ADR 227) está en modo enforce responde 403 con el código login_policy_denied ante una solicitud desde una dirección o en una hora que la política no permite — el mismo cuerpo en ambos casos; la sesión no se revoca y una solicitud posterior dentro de la política se procesa. Un token de widget (ddw_) de un puesto queda sujeto a la misma política en cada solicitud (core#2406, indicador widget_login_honors_policy). Un tenant sintético (demo) responde 403 con el código synthetic_tenant en toda ruta que llegaría a un tercero — marcación manual, pierna de transferencia externa o de conferencia, envío de SMS (core#2251, adenda del ADR #280). Ningún pago lo cambia.

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

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"
  }
}

409 — Conflict ​

Transición de estado no válida, conflicto de unicidad, o un asiento que está ocupado/reservado.

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

422 — TransferRefused ​

La transferencia a ciegas nunca llegó al switch. Tres familias de rechazo comparten este estado, y gate (cuando está presente) indica qué punto de control la rechazó.

La nueva comprobación de GATE_MID_CALL la rechazó: code compliance_blocked, gate mid_call, con el mismo envelope que devuelve unhold (reason_code, rule_id, auto_hangup_at): consentimiento revocado, una orden escrita de cese y desistimiento registrada, o la(s) zona(s) horaria(s) congeladas del consumidor fuera de la ventana de horario de silencio. Una transferencia devuelve al consumidor a audio en vivo igual que un unhold, por lo que se somete a la misma compuerta; de lo contrario un unhold bloqueado podría eludirse transfiriendo la misma llamada. Se arma el corte automático C9.

La cadena GATE_PRE_DIAL rechazó la NUEVA PIERNA: codecompliance_blocked, gate pre_dial, con el decision_id y el rule_id del motor. Solo un destino EXTERNO puede recibirlo: la pierna que crearía es una originación y pasa la misma cadena que una marcación, evaluada contra el número de DESTINO (su estado DNC, la ventana de horario de silencio de su NPA). NO se marcó NADA, NO se armó NADA y la propia llamada del consumidor no se toca: sigue hablando con su agente. reason_code engine_unavailable es la respuesta fail-closed cuando la compuerta no pudo evaluarse en absoluto: una compuerta que no puede decidir bloquea. reason_code destination_unregistered (rule_idtransfer.destination_unregistered.v1) es el rechazo de un E.164 que el tenant nunca registró en /v1/transfer-destinations, y destination_registry_unavailable la respuesta fail-closed cuando ese registro no pudo leerse; ambos van antes de la cadena, sin decision_id. reason_code destination_not_allowed (rule_idegress.destination_not_allowed.v1) es el rechazo de un E.164 fuera de la lista de destinos permitidos de un troncal BYOC de la sede (core#1281), y destination_allowlist_unavailable (egress.destination_allowlist_unavailable.v1) la respuesta fail-closed cuando esa lista no pudo leerse; ambos van antes del registro, con decision_id cuando se escribió su fila gate_blocks.

O el propio destino fue rechazado: envelope ErrorEnvelope. code destination_not_supported: el destino tiene forma de número pero no es E.164 estricto (dígitos nacionales sueltos, una cadena + mal formada). Los destinos externos se marcan solo desde E.164, porque la jurisdicción se resuelve a partir de ese número. code destination_not_found: cualquier otra cosa que no se resuelva a un agente activo del directorio de ESTE tenant. La división se decide por la FORMA de lo enviado, nunca por una segunda búsqueda, por lo que ninguna de las dos respuestas dice si el destino existe en otro tenant. code destination_unavailable: el destino ES un agente activo de este tenant, pero su puesto no está en :available en este momento (sonando, en una llamada, en cierre de la llamada, en pausa o sin registrarse). Esta fase no mueve el puesto, así que transferir a un agente ocupado lo duplicaría; esta respuesta solo nombra a un agente del directorio PROPIO del solicitante, por lo que tampoco es un oráculo entre tenants. codecaller_id_unavailable: una transferencia EXTERNA en una llamada que no tiene DID del tenant que presentar: se rechaza en lugar de marcarse con el ANI por defecto del gateway del carrier, que el tenant puede no poseer. code did_unverified (core#2493): el DID que presentaría la pierna externa (en una llamada entrante, el número que marcó el consumidor) es un DID de tipo customer cuya titularidad nunca se verificó, y la clave de tenant did_ownership_proof es enforce. Con observe la pierna sale y dialer_dids_unverified_use_total{surface="voice_transfer"} la cuenta; con off nada cambia. Aplica a una transferencia a ciegas externa y a una adición externa a conferencia.

En todos los casos la fila call_control_actions queda en failed con el destino solicitado registrado; se ejecutaron CERO comandos ESL y la llamada no se toca.

O la consulta nunca se atendió (solo transferencia asistida): code consultation_unanswered: el destino no está registrado, está ocupado o no contestó la pierna de consulta. Es un 422 y no un 502 porque el switch funcionó y una persona no contestó. LA ESPERA YA SE HA LIBERADO: el consumidor vuelve con su agente antes de que se escriba esta respuesta, y no queda ninguna consulta abierta.

O la pierna de conferencia nunca se atendió (solo agregar a conferencia): codeconference_unanswered: el colega no está registrado, está ocupado o no contestó. Un 422 y no un 502 por la misma razón; la llamada continúa exactamente como estaba y no queda ninguna conferencia abierta.

destination_not_found

json
{
  "error": {
    "code": "destination_not_found",
    "message": "no active agent with that destination in this tenant"
  }
}

destination_not_supported

json
{
  "error": {
    "code": "destination_not_supported",
    "message": "an external transfer destination must be E.164 (+<country><number>)"
  }
}

destination_unavailable

json
{
  "error": {
    "code": "destination_unavailable",
    "message": "that agent is not available to take a transfer right now"
  }
}

caller_id_unavailable

json
{
  "error": {
    "code": "caller_id_unavailable",
    "message": "this call has no tenant caller-ID to present on a transferred leg"
  }
}

did_unverified

json
{
  "error": {
    "code": "did_unverified",
    "message": "the caller-ID this transferred leg would present is not a verified number of the tenant"
  }
}

compliance_blocked_mid_call

json
{
  "error": {
    "code": "compliance_blocked",
    "message": "the mid-call compliance re-check refused this blind_transfer (consent_revoked)",
    "gate": "mid_call",
    "reason_code": "consent_revoked",
    "rule_id": "regf.revocation.v1"
  }
}

compliance_blocked_pre_dial

json
{
  "error": {
    "code": "compliance_blocked",
    "message": "the origination gate refused the leg this blind_transfer would create (dnc_listed)",
    "gate": "pre_dial",
    "reason_code": "dnc_listed",
    "rule_id": "dnc.lists.v1",
    "decision_id": "018f3f2a-0000-7000-8000-000000000000"
  }
}

429 — CallControlThrottled ​

El freno de tasa de solicitudes NR-18 rechazó esta solicitud (reintentable en la próxima ventana). code rate_limited. Se acota por el principal DURABLE MÁS ESPECÍFICO (agente > usuario > tenant), nunca por tenant cuando existe uno más estrecho, de modo que una sola página hostil no pueda limitar a los agentes hermanos. Durable significa que el presupuesto sobrevive a la reautenticación: volver a iniciar sesión emite un token nuevo pero no compra un presupuesto nuevo. Todos los verbos con freno (los cuatro de alternancia y la transferencia a ciegas) comparten UN solo presupuesto; hangup está exento y nunca responde 429, porque rechazar un corte dejaría viva una llamada que su operador pidió terminar. Se rechaza ANTES de buscar la llamada, así que esta respuesta es idéntica exista o no el call_id. Retry-After es el tiempo que queda en la ventana fija.

json
{
  "error": {
    "code": "rate_limited",
    "message": "call control rate limit exceeded; retry later"
  }
}

502 — CallControlFailed ​

El switch rechazó el comando de control (la llamada ya terminó / la pierna ya no existe). La fila de auditoría queda en failed.

json
{
  "error": {
    "code": "call_control_failed",
    "message": "the switch rejected the control command"
  }
}

503 — CallControlUnavailable ​

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 o agotó el tiempo de espera. Ambos son reintentables.

audit_unavailable

json
{
  "error": {
    "code": "audit_unavailable",
    "message": "call-control audit unavailable, retry"
  }
}

esl_unavailable

json
{
  "error": {
    "code": "esl_unavailable",
    "message": "telephony control unavailable, retry"
  }
}

Completar la transferencia asistida: entregar la llamada al destino ​

http
POST /v1/calls/{call_id}/transfer/attended/complete

Cuelga la pierna de consulta y mueve la pierna del CONSUMIDOR al destino, con el mismo uuid_transfer que ejecuta la transferencia a ciegas. Se estampa un control_handoff que nombra al agente DESTINO: desde esa fila la compuerta de titularidad lo autoriza a él y rechaza al agente de origen, sin tocar el agent_id de la llamada.

SIN CUERPO. El destino sale de la consulta ABIERTA, nunca de la solicitud, de modo que quien llama no puede consultar con un agente y completar hacia otro. SÍ se vuelve a resolver: un destino desactivado desde start se rechaza con 422 en lugar de recibir la llamada.

Sujeto a compuerta como la transferencia a ciegas (el consumidor cae en audio en vivo con una nueva parte), por lo que el trío GATE_MID_CALL corre ANTES de tocar el switch y rechaza con 422 compliance_blocked dejando la consulta abierta. .../cancel corre la MISMA compuerta, así que también se rechaza mientras el bloqueo dure: el consumidor sigue en espera con el corte automático C9 armado, igual que lo deja un unhold bloqueado.

SI LA PROPIA TRANSFERENCIA FALLA, la espera se libera y el consumidor vuelve al agente que ya lo estaba atendiendo (nunca a nadie), y no se estampa ningún traspaso por una transferencia que no ocurrió.

200 SIGNIFICA QUE EL SWITCH ACEPTÓ LA TRANSFERENCIA, NO QUE EL DESTINO CONTESTÓ. Para entonces la pierna del agente de origen ya no existe, por lo que la respuesta incluye call.bridge_confirm_by: el instante en que el consumidor queda en puente con el destino, o ha colgado, o core lo cuelga con la causa NORMAL_UNSPECIFIED (en el CDR y el webhook call.ended, donde la llamada aún se cierra como contestada) y una fila de auditoría hangup / attended_transfer_unbridged. Nunca se le deja solo en la línea. null significa que core no pudo armar esa comprobación; la fila de auditoría de este complete dirá entonces bridge_net_unarmed.

409 no_consultation cuando no hay una consulta abierta en esta llamada.

Parámetros

NombreEnTipoObligatorioDescripción
call_idpathstring (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).

Respuestas

200 ​

Transferencia emitida (traspaso estampado, consulta cerrada, comprobación de puente armada).

CampoTipoObligatorioDescripción
callobject (CallControlResult)sí
call.verbhold · unhold · mute · unmute · hangup · blind_transfer · attended_transfer_start · attended_transfer_complete · attended_transfer_cancelno
call.call_idstringno
call.audit_idstring (uuid)noLa fila durable call_control_actions.
call.to_numberstringnoÚltimos 4 enmascarados (***0184) — el E.164 completo nunca cruza esta superficie.
call.bridge_confirm_bystring,null (date-time)noSolo attended_transfer_complete. Cuando core comprueba que el consumidor está en puente con el destino; un consumidor que aún no está en puente en ese momento se cuelga con la causa NORMAL_UNSPECIFIED. null cuando no se pudo armar esa comprobación.

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 — Forbidden ​

El tenant está suspendido. Una sesión del dashboard (ddu_) de un tenant cuya política de inicio de sesión (ADR 227) está en modo enforce responde 403 con el código login_policy_denied ante una solicitud desde una dirección o en una hora que la política no permite — el mismo cuerpo en ambos casos; la sesión no se revoca y una solicitud posterior dentro de la política se procesa. Un token de widget (ddw_) de un puesto queda sujeto a la misma política en cada solicitud (core#2406, indicador widget_login_honors_policy). Un tenant sintético (demo) responde 403 con el código synthetic_tenant en toda ruta que llegaría a un tercero — marcación manual, pierna de transferencia externa o de conferencia, envío de SMS (core#2251, adenda del ADR #280). Ningún pago lo cambia.

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

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"
  }
}

409 — Conflict ​

Transición de estado no válida, conflicto de unicidad, o un asiento que está ocupado/reservado.

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

422 — TransferRefused ​

La transferencia a ciegas nunca llegó al switch. Tres familias de rechazo comparten este estado, y gate (cuando está presente) indica qué punto de control la rechazó.

La nueva comprobación de GATE_MID_CALL la rechazó: code compliance_blocked, gate mid_call, con el mismo envelope que devuelve unhold (reason_code, rule_id, auto_hangup_at): consentimiento revocado, una orden escrita de cese y desistimiento registrada, o la(s) zona(s) horaria(s) congeladas del consumidor fuera de la ventana de horario de silencio. Una transferencia devuelve al consumidor a audio en vivo igual que un unhold, por lo que se somete a la misma compuerta; de lo contrario un unhold bloqueado podría eludirse transfiriendo la misma llamada. Se arma el corte automático C9.

La cadena GATE_PRE_DIAL rechazó la NUEVA PIERNA: codecompliance_blocked, gate pre_dial, con el decision_id y el rule_id del motor. Solo un destino EXTERNO puede recibirlo: la pierna que crearía es una originación y pasa la misma cadena que una marcación, evaluada contra el número de DESTINO (su estado DNC, la ventana de horario de silencio de su NPA). NO se marcó NADA, NO se armó NADA y la propia llamada del consumidor no se toca: sigue hablando con su agente. reason_code engine_unavailable es la respuesta fail-closed cuando la compuerta no pudo evaluarse en absoluto: una compuerta que no puede decidir bloquea. reason_code destination_unregistered (rule_idtransfer.destination_unregistered.v1) es el rechazo de un E.164 que el tenant nunca registró en /v1/transfer-destinations, y destination_registry_unavailable la respuesta fail-closed cuando ese registro no pudo leerse; ambos van antes de la cadena, sin decision_id. reason_code destination_not_allowed (rule_idegress.destination_not_allowed.v1) es el rechazo de un E.164 fuera de la lista de destinos permitidos de un troncal BYOC de la sede (core#1281), y destination_allowlist_unavailable (egress.destination_allowlist_unavailable.v1) la respuesta fail-closed cuando esa lista no pudo leerse; ambos van antes del registro, con decision_id cuando se escribió su fila gate_blocks.

O el propio destino fue rechazado: envelope ErrorEnvelope. code destination_not_supported: el destino tiene forma de número pero no es E.164 estricto (dígitos nacionales sueltos, una cadena + mal formada). Los destinos externos se marcan solo desde E.164, porque la jurisdicción se resuelve a partir de ese número. code destination_not_found: cualquier otra cosa que no se resuelva a un agente activo del directorio de ESTE tenant. La división se decide por la FORMA de lo enviado, nunca por una segunda búsqueda, por lo que ninguna de las dos respuestas dice si el destino existe en otro tenant. code destination_unavailable: el destino ES un agente activo de este tenant, pero su puesto no está en :available en este momento (sonando, en una llamada, en cierre de la llamada, en pausa o sin registrarse). Esta fase no mueve el puesto, así que transferir a un agente ocupado lo duplicaría; esta respuesta solo nombra a un agente del directorio PROPIO del solicitante, por lo que tampoco es un oráculo entre tenants. codecaller_id_unavailable: una transferencia EXTERNA en una llamada que no tiene DID del tenant que presentar: se rechaza en lugar de marcarse con el ANI por defecto del gateway del carrier, que el tenant puede no poseer. code did_unverified (core#2493): el DID que presentaría la pierna externa (en una llamada entrante, el número que marcó el consumidor) es un DID de tipo customer cuya titularidad nunca se verificó, y la clave de tenant did_ownership_proof es enforce. Con observe la pierna sale y dialer_dids_unverified_use_total{surface="voice_transfer"} la cuenta; con off nada cambia. Aplica a una transferencia a ciegas externa y a una adición externa a conferencia.

En todos los casos la fila call_control_actions queda en failed con el destino solicitado registrado; se ejecutaron CERO comandos ESL y la llamada no se toca.

O la consulta nunca se atendió (solo transferencia asistida): code consultation_unanswered: el destino no está registrado, está ocupado o no contestó la pierna de consulta. Es un 422 y no un 502 porque el switch funcionó y una persona no contestó. LA ESPERA YA SE HA LIBERADO: el consumidor vuelve con su agente antes de que se escriba esta respuesta, y no queda ninguna consulta abierta.

O la pierna de conferencia nunca se atendió (solo agregar a conferencia): codeconference_unanswered: el colega no está registrado, está ocupado o no contestó. Un 422 y no un 502 por la misma razón; la llamada continúa exactamente como estaba y no queda ninguna conferencia abierta.

destination_not_found

json
{
  "error": {
    "code": "destination_not_found",
    "message": "no active agent with that destination in this tenant"
  }
}

destination_not_supported

json
{
  "error": {
    "code": "destination_not_supported",
    "message": "an external transfer destination must be E.164 (+<country><number>)"
  }
}

destination_unavailable

json
{
  "error": {
    "code": "destination_unavailable",
    "message": "that agent is not available to take a transfer right now"
  }
}

caller_id_unavailable

json
{
  "error": {
    "code": "caller_id_unavailable",
    "message": "this call has no tenant caller-ID to present on a transferred leg"
  }
}

did_unverified

json
{
  "error": {
    "code": "did_unverified",
    "message": "the caller-ID this transferred leg would present is not a verified number of the tenant"
  }
}

compliance_blocked_mid_call

json
{
  "error": {
    "code": "compliance_blocked",
    "message": "the mid-call compliance re-check refused this blind_transfer (consent_revoked)",
    "gate": "mid_call",
    "reason_code": "consent_revoked",
    "rule_id": "regf.revocation.v1"
  }
}

compliance_blocked_pre_dial

json
{
  "error": {
    "code": "compliance_blocked",
    "message": "the origination gate refused the leg this blind_transfer would create (dnc_listed)",
    "gate": "pre_dial",
    "reason_code": "dnc_listed",
    "rule_id": "dnc.lists.v1",
    "decision_id": "018f3f2a-0000-7000-8000-000000000000"
  }
}

429 — CallControlThrottled ​

El freno de tasa de solicitudes NR-18 rechazó esta solicitud (reintentable en la próxima ventana). code rate_limited. Se acota por el principal DURABLE MÁS ESPECÍFICO (agente > usuario > tenant), nunca por tenant cuando existe uno más estrecho, de modo que una sola página hostil no pueda limitar a los agentes hermanos. Durable significa que el presupuesto sobrevive a la reautenticación: volver a iniciar sesión emite un token nuevo pero no compra un presupuesto nuevo. Todos los verbos con freno (los cuatro de alternancia y la transferencia a ciegas) comparten UN solo presupuesto; hangup está exento y nunca responde 429, porque rechazar un corte dejaría viva una llamada que su operador pidió terminar. Se rechaza ANTES de buscar la llamada, así que esta respuesta es idéntica exista o no el call_id. Retry-After es el tiempo que queda en la ventana fija.

json
{
  "error": {
    "code": "rate_limited",
    "message": "call control rate limit exceeded; retry later"
  }
}

502 — CallControlFailed ​

El switch rechazó el comando de control (la llamada ya terminó / la pierna ya no existe). La fila de auditoría queda en failed.

json
{
  "error": {
    "code": "call_control_failed",
    "message": "the switch rejected the control command"
  }
}

503 — CallControlUnavailable ​

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 o agotó el tiempo de espera. Ambos son reintentables.

audit_unavailable

json
{
  "error": {
    "code": "audit_unavailable",
    "message": "call-control audit unavailable, retry"
  }
}

esl_unavailable

json
{
  "error": {
    "code": "esl_unavailable",
    "message": "telephony control unavailable, retry"
  }
}

Cancelar la consulta: la llamada se queda con su agente ​

http
POST /v1/calls/{call_id}/transfer/attended/cancel

Cuelga la pierna de consulta y saca al consumidor de la espera. LA LLAMADA QUEDA EXACTAMENTE COMO ESTABA: el consumidor nunca salió del puente, así que esto es una restauración por construcción, no una reconstrucción: la música se detiene y vuelve con el agente que ya lo estaba atendiendo.

NO SE ESTAMPA NINGÚN TRASPASO, y eso es el punto y no una omisión: el control nunca SE MOVIÓ durante una consulta (.../start deliberadamente no estampa), así que el agente de origen conservó la llamada todo el tiempo y no hay nada que devolver. La fila de auditoría attended_transfer_cancel es la evidencia durable de que la consulta terminó.

SIN CUERPO. Sujeto a compuerta como unhold (el consumidor vuelve a audio en vivo), por lo que un 422 compliance_blocked lo deja en espera con el corte automático C9 armado, igual que lo hace un unhold bloqueado.

Una pierna de consulta que ya no existe (el destino colgó) NO hace fallar este verbo: derribarla es de mejor esfuerzo, porque el trabajo real del verbo es devolverle su agente al consumidor. Si el AGENTE DE ORIGEN colgó durante la consulta, no hay pierna que sacar de la espera ni agente al que devolver, por lo que responde 409 not_bridged: completar la transferencia es entonces la salida segura.

409 no_consultation cuando no hay una consulta abierta en esta llamada.

Parámetros

NombreEnTipoObligatorioDescripción
call_idpathstring (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).

Respuestas

200 ​

Consulta cancelada; la llamada continúa con su agente.

CampoTipoObligatorioDescripción
callobject (CallControlResult)sí
call.verbhold · unhold · mute · unmute · hangup · blind_transfer · attended_transfer_start · attended_transfer_complete · attended_transfer_cancelno
call.call_idstringno
call.audit_idstring (uuid)noLa fila durable call_control_actions.
call.to_numberstringnoÚltimos 4 enmascarados (***0184) — el E.164 completo nunca cruza esta superficie.
call.bridge_confirm_bystring,null (date-time)noSolo attended_transfer_complete. Cuando core comprueba que el consumidor está en puente con el destino; un consumidor que aún no está en puente en ese momento se cuelga con la causa NORMAL_UNSPECIFIED. null cuando no se pudo armar esa comprobación.

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 — Forbidden ​

El tenant está suspendido. Una sesión del dashboard (ddu_) de un tenant cuya política de inicio de sesión (ADR 227) está en modo enforce responde 403 con el código login_policy_denied ante una solicitud desde una dirección o en una hora que la política no permite — el mismo cuerpo en ambos casos; la sesión no se revoca y una solicitud posterior dentro de la política se procesa. Un token de widget (ddw_) de un puesto queda sujeto a la misma política en cada solicitud (core#2406, indicador widget_login_honors_policy). Un tenant sintético (demo) responde 403 con el código synthetic_tenant en toda ruta que llegaría a un tercero — marcación manual, pierna de transferencia externa o de conferencia, envío de SMS (core#2251, adenda del ADR #280). Ningún pago lo cambia.

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

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"
  }
}

409 — Conflict ​

Transición de estado no válida, conflicto de unicidad, o un asiento que está ocupado/reservado.

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

422 — TransferRefused ​

La transferencia a ciegas nunca llegó al switch. Tres familias de rechazo comparten este estado, y gate (cuando está presente) indica qué punto de control la rechazó.

La nueva comprobación de GATE_MID_CALL la rechazó: code compliance_blocked, gate mid_call, con el mismo envelope que devuelve unhold (reason_code, rule_id, auto_hangup_at): consentimiento revocado, una orden escrita de cese y desistimiento registrada, o la(s) zona(s) horaria(s) congeladas del consumidor fuera de la ventana de horario de silencio. Una transferencia devuelve al consumidor a audio en vivo igual que un unhold, por lo que se somete a la misma compuerta; de lo contrario un unhold bloqueado podría eludirse transfiriendo la misma llamada. Se arma el corte automático C9.

La cadena GATE_PRE_DIAL rechazó la NUEVA PIERNA: codecompliance_blocked, gate pre_dial, con el decision_id y el rule_id del motor. Solo un destino EXTERNO puede recibirlo: la pierna que crearía es una originación y pasa la misma cadena que una marcación, evaluada contra el número de DESTINO (su estado DNC, la ventana de horario de silencio de su NPA). NO se marcó NADA, NO se armó NADA y la propia llamada del consumidor no se toca: sigue hablando con su agente. reason_code engine_unavailable es la respuesta fail-closed cuando la compuerta no pudo evaluarse en absoluto: una compuerta que no puede decidir bloquea. reason_code destination_unregistered (rule_idtransfer.destination_unregistered.v1) es el rechazo de un E.164 que el tenant nunca registró en /v1/transfer-destinations, y destination_registry_unavailable la respuesta fail-closed cuando ese registro no pudo leerse; ambos van antes de la cadena, sin decision_id. reason_code destination_not_allowed (rule_idegress.destination_not_allowed.v1) es el rechazo de un E.164 fuera de la lista de destinos permitidos de un troncal BYOC de la sede (core#1281), y destination_allowlist_unavailable (egress.destination_allowlist_unavailable.v1) la respuesta fail-closed cuando esa lista no pudo leerse; ambos van antes del registro, con decision_id cuando se escribió su fila gate_blocks.

O el propio destino fue rechazado: envelope ErrorEnvelope. code destination_not_supported: el destino tiene forma de número pero no es E.164 estricto (dígitos nacionales sueltos, una cadena + mal formada). Los destinos externos se marcan solo desde E.164, porque la jurisdicción se resuelve a partir de ese número. code destination_not_found: cualquier otra cosa que no se resuelva a un agente activo del directorio de ESTE tenant. La división se decide por la FORMA de lo enviado, nunca por una segunda búsqueda, por lo que ninguna de las dos respuestas dice si el destino existe en otro tenant. code destination_unavailable: el destino ES un agente activo de este tenant, pero su puesto no está en :available en este momento (sonando, en una llamada, en cierre de la llamada, en pausa o sin registrarse). Esta fase no mueve el puesto, así que transferir a un agente ocupado lo duplicaría; esta respuesta solo nombra a un agente del directorio PROPIO del solicitante, por lo que tampoco es un oráculo entre tenants. codecaller_id_unavailable: una transferencia EXTERNA en una llamada que no tiene DID del tenant que presentar: se rechaza en lugar de marcarse con el ANI por defecto del gateway del carrier, que el tenant puede no poseer. code did_unverified (core#2493): el DID que presentaría la pierna externa (en una llamada entrante, el número que marcó el consumidor) es un DID de tipo customer cuya titularidad nunca se verificó, y la clave de tenant did_ownership_proof es enforce. Con observe la pierna sale y dialer_dids_unverified_use_total{surface="voice_transfer"} la cuenta; con off nada cambia. Aplica a una transferencia a ciegas externa y a una adición externa a conferencia.

En todos los casos la fila call_control_actions queda en failed con el destino solicitado registrado; se ejecutaron CERO comandos ESL y la llamada no se toca.

O la consulta nunca se atendió (solo transferencia asistida): code consultation_unanswered: el destino no está registrado, está ocupado o no contestó la pierna de consulta. Es un 422 y no un 502 porque el switch funcionó y una persona no contestó. LA ESPERA YA SE HA LIBERADO: el consumidor vuelve con su agente antes de que se escriba esta respuesta, y no queda ninguna consulta abierta.

O la pierna de conferencia nunca se atendió (solo agregar a conferencia): codeconference_unanswered: el colega no está registrado, está ocupado o no contestó. Un 422 y no un 502 por la misma razón; la llamada continúa exactamente como estaba y no queda ninguna conferencia abierta.

destination_not_found

json
{
  "error": {
    "code": "destination_not_found",
    "message": "no active agent with that destination in this tenant"
  }
}

destination_not_supported

json
{
  "error": {
    "code": "destination_not_supported",
    "message": "an external transfer destination must be E.164 (+<country><number>)"
  }
}

destination_unavailable

json
{
  "error": {
    "code": "destination_unavailable",
    "message": "that agent is not available to take a transfer right now"
  }
}

caller_id_unavailable

json
{
  "error": {
    "code": "caller_id_unavailable",
    "message": "this call has no tenant caller-ID to present on a transferred leg"
  }
}

did_unverified

json
{
  "error": {
    "code": "did_unverified",
    "message": "the caller-ID this transferred leg would present is not a verified number of the tenant"
  }
}

compliance_blocked_mid_call

json
{
  "error": {
    "code": "compliance_blocked",
    "message": "the mid-call compliance re-check refused this blind_transfer (consent_revoked)",
    "gate": "mid_call",
    "reason_code": "consent_revoked",
    "rule_id": "regf.revocation.v1"
  }
}

compliance_blocked_pre_dial

json
{
  "error": {
    "code": "compliance_blocked",
    "message": "the origination gate refused the leg this blind_transfer would create (dnc_listed)",
    "gate": "pre_dial",
    "reason_code": "dnc_listed",
    "rule_id": "dnc.lists.v1",
    "decision_id": "018f3f2a-0000-7000-8000-000000000000"
  }
}

429 — CallControlThrottled ​

El freno de tasa de solicitudes NR-18 rechazó esta solicitud (reintentable en la próxima ventana). code rate_limited. Se acota por el principal DURABLE MÁS ESPECÍFICO (agente > usuario > tenant), nunca por tenant cuando existe uno más estrecho, de modo que una sola página hostil no pueda limitar a los agentes hermanos. Durable significa que el presupuesto sobrevive a la reautenticación: volver a iniciar sesión emite un token nuevo pero no compra un presupuesto nuevo. Todos los verbos con freno (los cuatro de alternancia y la transferencia a ciegas) comparten UN solo presupuesto; hangup está exento y nunca responde 429, porque rechazar un corte dejaría viva una llamada que su operador pidió terminar. Se rechaza ANTES de buscar la llamada, así que esta respuesta es idéntica exista o no el call_id. Retry-After es el tiempo que queda en la ventana fija.

json
{
  "error": {
    "code": "rate_limited",
    "message": "call control rate limit exceeded; retry later"
  }
}

502 — CallControlFailed ​

El switch rechazó el comando de control (la llamada ya terminó / la pierna ya no existe). La fila de auditoría queda en failed.

json
{
  "error": {
    "code": "call_control_failed",
    "message": "the switch rejected the control command"
  }
}

503 — CallControlUnavailable ​

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 o agotó el tiempo de espera. Ambos son reintentables.

audit_unavailable

json
{
  "error": {
    "code": "audit_unavailable",
    "message": "call-control audit unavailable, retry"
  }
}

esl_unavailable

json
{
  "error": {
    "code": "esl_unavailable",
    "message": "telephony control unavailable, retry"
  }
}

Incorporar a un colega, o a un número externo registrado, a la llamada (conferencia a tres) ​

http
POST /v1/calls/{call_id}/conference/add

Hace sonar a un colega del directorio de ESTE tenant y lo pone en el audio de la llamada, de modo que el agente, el consumidor y el colega hablen juntos. Un destino externo/PSTN es 422 destination_not_supported salvo que el tenant tenga la bandera conference_external_enabled ACTIVA (por defecto DESACTIVADA, y requiere conference_enabled).

TERCERO EXTERNO (core#1700, ADR #223 D6/D8). Con esa bandera ACTIVA, un E.164 pasa por la MISMA cadena que una transferencia a ciegas externa: compuerta del plan, lista de egreso permitida, el caller-ID del tenant, el registro de /v1/transfer-destinations (reason_code destination_unregistered, sin decision_id) y la cadena GATE_PRE_DIAL sobre el DESTINO (DNC, horario de silencio; 422 compliance_blocked con un decision_id consultable), más la atestación del consumidor: el cuerpo debe llevar consumer_agreed: true, o la respuesta es 422consumer_agreement_required ANTES de evaluar o marcar nada. La atestación se registra en la fila de auditoría de control de llamada y en el propio intento del tercero. Un número externo se rechaza con cero comandos al switch siempre que cualquiera de esos pasos lo rechace.

LA PIERNA EXTERNA es la pierna de carrier que tiene una transferencia externa: sale con el DID del tenant por el carrier que eligió el LCR para un tenant house (o el propio troncal del tenant para BYOC), medida contra la tasa de llamadas contratada de ese carrier (429 carrier_cps, 503 no_route, 503 capacity_unavailable, como en una transferencia). A diferencia de una transferencia no reemplaza a nadie, por lo que es UN CANAL MÁS del tenant: un tenant en su tope de canales o ventana de tasa de llamadas se rechaza con 429tenant_channels / tenant_cps sin escribir ni marcar nada. Se factura desde SU PROPIA respuesta, nunca desde el acuse del comando.

DETRÁS DE LA BANDERA conference_enabled, por tenant. Con la bandera desactivada esta ruta responde 404 not_found, la misma respuesta que una ruta que no existe, antes de leer el cuerpo, gastar el presupuesto de tasa o buscar la llamada, y nada más de la superficie de llamadas cambia.

QUÉ OYE CADA PARTE, dicho explícitamente. El colega oye el canal del CONSUMIDOR y se une a él como participante, por lo que el consumidor y el agente pueden oírlo. QUÉ SE GRABA: la voz del colega se mezcla en la grabación del consumidor (el mismo canal), no es una pista separada y no puede separarse después. Si el consumidor debe ser informado, y qué consentimiento aplica a una grabación que ahora contiene una tercera voz, es una cuestión de cumplimiento abierta que se sigue en core#1648; esta fase no añade ninguna divulgación.

UNA CONFERENCIA POR LLAMADA, y nunca sobre una consulta: un segundo add es 409 conference_in_progress, y también lo es add mientras hay una consulta de transferencia asistida abierta (409 consultation_in_progress). Una transferencia a ciegas o un start de transferencia asistida solicitados mientras una conferencia está abierta son también 409 conference_in_progress.

CON COMPUERTA como una transferencia: el trío GATE_MID_CALL (horario de silencio, revocación de consentimiento, cese y desistimiento) se vuelve a comprobar, y un tenant cuyo plan no se puede leer se rechaza (402 plan_inactive, fail-closed). La pierna del tercero es su propia fila call_attempts (leg = conference, conference_kind internal o external), que no pertenece a ningún deudor ni agente. La pierna de un colega interno no tiene carrier y no se factura; una pierna externa lleva su carrier y se factura desde su propia respuesta.

NO ALCANZABLE CON UN TOKEN DE WIDGET (ddw_) en esta fase: la lista de permitidos del widget es de denegación por defecto y no incluye estas rutas, por lo que ese token se rechaza con 403. Abrirlas al widget es una decisión aparte y explícita.

EL AGENTE CONSERVA LA LLAMADA. La titularidad es la misma compuerta del ADR #66 que la de todos los demás verbos: un agente que ya no controla la llamada se rechaza con 403.

Parámetros

NombreEnTipoObligatorioDescripción
call_idpathstring (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)

CampoTipoObligatorioDescripción
destinationstringsísip_extension / id de agente interno, o (conferencia externa habilitada) un número E.164 registrado en /v1/transfer-destinations. Se recorta y se acota igual que BlindTransferRequest.destination.
consumer_agreedbooleannoEl consumidor aceptó al tercero externo. Sin un true literal, un destino externo es 422 consumer_agreement_required.

Respuestas

200 ​

Conferencia abierta (fila de auditoría durable, pierna del colega establecida).

CampoTipoObligatorioDescripción
callobject (CallControlResult)sí
call.verbhold · unhold · mute · unmute · hangup · blind_transfer · attended_transfer_start · attended_transfer_complete · attended_transfer_cancelno
call.call_idstringno
call.audit_idstring (uuid)noLa fila durable call_control_actions.
call.to_numberstringnoÚltimos 4 enmascarados (***0184) — el E.164 completo nunca cruza esta superficie.
call.bridge_confirm_bystring,null (date-time)noSolo attended_transfer_complete. Cuando core comprueba que el consumidor está en puente con el destino; un consumidor que aún no está en puente en ese momento se cuelga con la causa NORMAL_UNSPECIFIED. null cuando no se pudo armar esa comprobación.

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 — Forbidden ​

El tenant está suspendido. Una sesión del dashboard (ddu_) de un tenant cuya política de inicio de sesión (ADR 227) está en modo enforce responde 403 con el código login_policy_denied ante una solicitud desde una dirección o en una hora que la política no permite — el mismo cuerpo en ambos casos; la sesión no se revoca y una solicitud posterior dentro de la política se procesa. Un token de widget (ddw_) de un puesto queda sujeto a la misma política en cada solicitud (core#2406, indicador widget_login_honors_policy). Un tenant sintético (demo) responde 403 con el código synthetic_tenant en toda ruta que llegaría a un tercero — marcación manual, pierna de transferencia externa o de conferencia, envío de SMS (core#2251, adenda del ADR #280). Ningún pago lo cambia.

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

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"
  }
}

409 — Conflict ​

Transición de estado no válida, conflicto de unicidad, o un asiento que está ocupado/reservado.

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

422 — TransferRefused ​

La transferencia a ciegas nunca llegó al switch. Tres familias de rechazo comparten este estado, y gate (cuando está presente) indica qué punto de control la rechazó.

La nueva comprobación de GATE_MID_CALL la rechazó: code compliance_blocked, gate mid_call, con el mismo envelope que devuelve unhold (reason_code, rule_id, auto_hangup_at): consentimiento revocado, una orden escrita de cese y desistimiento registrada, o la(s) zona(s) horaria(s) congeladas del consumidor fuera de la ventana de horario de silencio. Una transferencia devuelve al consumidor a audio en vivo igual que un unhold, por lo que se somete a la misma compuerta; de lo contrario un unhold bloqueado podría eludirse transfiriendo la misma llamada. Se arma el corte automático C9.

La cadena GATE_PRE_DIAL rechazó la NUEVA PIERNA: codecompliance_blocked, gate pre_dial, con el decision_id y el rule_id del motor. Solo un destino EXTERNO puede recibirlo: la pierna que crearía es una originación y pasa la misma cadena que una marcación, evaluada contra el número de DESTINO (su estado DNC, la ventana de horario de silencio de su NPA). NO se marcó NADA, NO se armó NADA y la propia llamada del consumidor no se toca: sigue hablando con su agente. reason_code engine_unavailable es la respuesta fail-closed cuando la compuerta no pudo evaluarse en absoluto: una compuerta que no puede decidir bloquea. reason_code destination_unregistered (rule_idtransfer.destination_unregistered.v1) es el rechazo de un E.164 que el tenant nunca registró en /v1/transfer-destinations, y destination_registry_unavailable la respuesta fail-closed cuando ese registro no pudo leerse; ambos van antes de la cadena, sin decision_id. reason_code destination_not_allowed (rule_idegress.destination_not_allowed.v1) es el rechazo de un E.164 fuera de la lista de destinos permitidos de un troncal BYOC de la sede (core#1281), y destination_allowlist_unavailable (egress.destination_allowlist_unavailable.v1) la respuesta fail-closed cuando esa lista no pudo leerse; ambos van antes del registro, con decision_id cuando se escribió su fila gate_blocks.

O el propio destino fue rechazado: envelope ErrorEnvelope. code destination_not_supported: el destino tiene forma de número pero no es E.164 estricto (dígitos nacionales sueltos, una cadena + mal formada). Los destinos externos se marcan solo desde E.164, porque la jurisdicción se resuelve a partir de ese número. code destination_not_found: cualquier otra cosa que no se resuelva a un agente activo del directorio de ESTE tenant. La división se decide por la FORMA de lo enviado, nunca por una segunda búsqueda, por lo que ninguna de las dos respuestas dice si el destino existe en otro tenant. code destination_unavailable: el destino ES un agente activo de este tenant, pero su puesto no está en :available en este momento (sonando, en una llamada, en cierre de la llamada, en pausa o sin registrarse). Esta fase no mueve el puesto, así que transferir a un agente ocupado lo duplicaría; esta respuesta solo nombra a un agente del directorio PROPIO del solicitante, por lo que tampoco es un oráculo entre tenants. codecaller_id_unavailable: una transferencia EXTERNA en una llamada que no tiene DID del tenant que presentar: se rechaza en lugar de marcarse con el ANI por defecto del gateway del carrier, que el tenant puede no poseer. code did_unverified (core#2493): el DID que presentaría la pierna externa (en una llamada entrante, el número que marcó el consumidor) es un DID de tipo customer cuya titularidad nunca se verificó, y la clave de tenant did_ownership_proof es enforce. Con observe la pierna sale y dialer_dids_unverified_use_total{surface="voice_transfer"} la cuenta; con off nada cambia. Aplica a una transferencia a ciegas externa y a una adición externa a conferencia.

En todos los casos la fila call_control_actions queda en failed con el destino solicitado registrado; se ejecutaron CERO comandos ESL y la llamada no se toca.

O la consulta nunca se atendió (solo transferencia asistida): code consultation_unanswered: el destino no está registrado, está ocupado o no contestó la pierna de consulta. Es un 422 y no un 502 porque el switch funcionó y una persona no contestó. LA ESPERA YA SE HA LIBERADO: el consumidor vuelve con su agente antes de que se escriba esta respuesta, y no queda ninguna consulta abierta.

O la pierna de conferencia nunca se atendió (solo agregar a conferencia): codeconference_unanswered: el colega no está registrado, está ocupado o no contestó. Un 422 y no un 502 por la misma razón; la llamada continúa exactamente como estaba y no queda ninguna conferencia abierta.

destination_not_found

json
{
  "error": {
    "code": "destination_not_found",
    "message": "no active agent with that destination in this tenant"
  }
}

destination_not_supported

json
{
  "error": {
    "code": "destination_not_supported",
    "message": "an external transfer destination must be E.164 (+<country><number>)"
  }
}

destination_unavailable

json
{
  "error": {
    "code": "destination_unavailable",
    "message": "that agent is not available to take a transfer right now"
  }
}

caller_id_unavailable

json
{
  "error": {
    "code": "caller_id_unavailable",
    "message": "this call has no tenant caller-ID to present on a transferred leg"
  }
}

did_unverified

json
{
  "error": {
    "code": "did_unverified",
    "message": "the caller-ID this transferred leg would present is not a verified number of the tenant"
  }
}

compliance_blocked_mid_call

json
{
  "error": {
    "code": "compliance_blocked",
    "message": "the mid-call compliance re-check refused this blind_transfer (consent_revoked)",
    "gate": "mid_call",
    "reason_code": "consent_revoked",
    "rule_id": "regf.revocation.v1"
  }
}

compliance_blocked_pre_dial

json
{
  "error": {
    "code": "compliance_blocked",
    "message": "the origination gate refused the leg this blind_transfer would create (dnc_listed)",
    "gate": "pre_dial",
    "reason_code": "dnc_listed",
    "rule_id": "dnc.lists.v1",
    "decision_id": "018f3f2a-0000-7000-8000-000000000000"
  }
}

429 — TransferThrottled ​

code rate_limited: el freno de tasa de solicitudes NR-18, exactamente como lo describe CallControlThrottled (rechazado antes de buscar la llamada). code carrier_cps: una transferencia EXTERNA cuya pierna saldría por un carrier que ya está en sus llamadas por segundo contratadas en este segundo. No se escribió ni marcó nada y el consumidor sigue con su agente. Reintentable en menos de un segundo. rate_limited lleva Retry-After (tiempo que queda en la ventana fija); carrier_cps no. code tenant_channels / tenant_cps (solo agregar a conferencia un número EXTERNO): el tercero es un canal más del tenant, que está en su tope de canales o en su ventana de tasa de llamadas; no se marcó nada y la llamada sigue con las personas que ya están en ella.

rate_limited

json
{
  "error": {
    "code": "rate_limited",
    "message": "call control rate limit exceeded; retry later"
  }
}

carrier_cps

json
{
  "error": {
    "code": "carrier_cps",
    "message": "the carrier for the transferred leg is at its contracted call rate; retry"
  }
}

tenant_channels

json
{
  "error": {
    "code": "tenant_channels",
    "message": "the tenant is at its channel or call-rate ceiling; the third party was not dialled"
  }
}

502 — CallControlFailed ​

El switch rechazó el comando de control (la llamada ya terminó / la pierna ya no existe). La fila de auditoría queda en failed.

json
{
  "error": {
    "code": "call_control_failed",
    "message": "the switch rejected the control command"
  }
}

503 — TransferUnavailable ​

Los cuatro códigos 503 de una transferencia a ciegas. audit_unavailable y esl_unavailable son los que describe CallControlUnavailable. Otros dos aplican solo a un destino EXTERNO. no_route: la pierna house no tiene una ruta de carrier dirigida (enrutamiento desactivado, ningún carrier candidato), por lo que no se coloca, porque el tráfico house siempre es dirigido. capacity_unavailable: la compuerta de capacidad no pudo admitir el carrier de la pierna, y falla en modo cerrado. En ambos casos no se escribió ni marcó nada.

audit_unavailable

json
{
  "error": {
    "code": "audit_unavailable",
    "message": "call-control audit unavailable, retry"
  }
}

esl_unavailable

json
{
  "error": {
    "code": "esl_unavailable",
    "message": "telephony control unavailable, retry"
  }
}

no_route

json
{
  "error": {
    "code": "no_route",
    "message": "no directed carrier route for the transferred leg; nothing was dialled"
  }
}

capacity_unavailable

json
{
  "error": {
    "code": "capacity_unavailable",
    "message": "the capacity gate could not admit the transferred leg, retry"
  }
}

Sacar al colega de la llamada ​

http
POST /v1/calls/{call_id}/conference/remove

Cuelga la pierna propia del colega. El consumidor y el agente quedan exactamente como estaban: este verbo solo quita una voz, por lo que nunca está sujeto a compuerta de cumplimiento ni del plan.

SIN CUERPO. La pierna que se cuelga sale de la conferencia ABIERTA, nunca de la solicitud. Una pierna que el switch ya no conoce (el colega ya colgó) es el estado que se pidió alcanzar a este verbo, así que igualmente responde 200. 409 no_conference cuando esta llamada no tiene ninguna conferencia abierta.

DETRÁS DE LA BANDERA conference_enabled: con ella desactivada esta ruta responde 404not_found como una ruta que no existe.

Parámetros

NombreEnTipoObligatorioDescripción
call_idpathstring (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).

Respuestas

200 ​

Conferencia cerrada; la llamada continúa con su agente.

CampoTipoObligatorioDescripción
callobject (CallControlResult)sí
call.verbhold · unhold · mute · unmute · hangup · blind_transfer · attended_transfer_start · attended_transfer_complete · attended_transfer_cancelno
call.call_idstringno
call.audit_idstring (uuid)noLa fila durable call_control_actions.
call.to_numberstringnoÚltimos 4 enmascarados (***0184) — el E.164 completo nunca cruza esta superficie.
call.bridge_confirm_bystring,null (date-time)noSolo attended_transfer_complete. Cuando core comprueba que el consumidor está en puente con el destino; un consumidor que aún no está en puente en ese momento se cuelga con la causa NORMAL_UNSPECIFIED. null cuando no se pudo armar esa comprobación.

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 — Forbidden ​

El tenant está suspendido. Una sesión del dashboard (ddu_) de un tenant cuya política de inicio de sesión (ADR 227) está en modo enforce responde 403 con el código login_policy_denied ante una solicitud desde una dirección o en una hora que la política no permite — el mismo cuerpo en ambos casos; la sesión no se revoca y una solicitud posterior dentro de la política se procesa. Un token de widget (ddw_) de un puesto queda sujeto a la misma política en cada solicitud (core#2406, indicador widget_login_honors_policy). Un tenant sintético (demo) responde 403 con el código synthetic_tenant en toda ruta que llegaría a un tercero — marcación manual, pierna de transferencia externa o de conferencia, envío de SMS (core#2251, adenda del ADR #280). Ningún pago lo cambia.

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

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"
  }
}

409 — Conflict ​

Transición de estado no válida, conflicto de unicidad, o un asiento que está ocupado/reservado.

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

429 — CallControlThrottled ​

El freno de tasa de solicitudes NR-18 rechazó esta solicitud (reintentable en la próxima ventana). code rate_limited. Se acota por el principal DURABLE MÁS ESPECÍFICO (agente > usuario > tenant), nunca por tenant cuando existe uno más estrecho, de modo que una sola página hostil no pueda limitar a los agentes hermanos. Durable significa que el presupuesto sobrevive a la reautenticación: volver a iniciar sesión emite un token nuevo pero no compra un presupuesto nuevo. Todos los verbos con freno (los cuatro de alternancia y la transferencia a ciegas) comparten UN solo presupuesto; hangup está exento y nunca responde 429, porque rechazar un corte dejaría viva una llamada que su operador pidió terminar. Se rechaza ANTES de buscar la llamada, así que esta respuesta es idéntica exista o no el call_id. Retry-After es el tiempo que queda en la ventana fija.

json
{
  "error": {
    "code": "rate_limited",
    "message": "call control rate limit exceeded; retry later"
  }
}

502 — CallControlFailed ​

El switch rechazó el comando de control (la llamada ya terminó / la pierna ya no existe). La fila de auditoría queda en failed.

json
{
  "error": {
    "code": "call_control_failed",
    "message": "the switch rejected the control command"
  }
}

503 — CallControlUnavailable ​

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 o agotó el tiempo de espera. Ambos son reintentables.

audit_unavailable

json
{
  "error": {
    "code": "audit_unavailable",
    "message": "call-control audit unavailable, retry"
  }
}

esl_unavailable

json
{
  "error": {
    "code": "esl_unavailable",
    "message": "telephony control unavailable, retry"
  }
}

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