Appearance
Widgets
Generado desde
DialerDigital/corecommit0fc18008b3c8— especificaciónopenapi/dialer-v1.yamlv0.134.0. No se edita a mano; consulta Cómo se construye esta referencia. Descargar la especificación OpenAPI.
Traducción en curso
Esta referencia se genera desde la especificación OpenAPI. Las cadenas que todavía no tienen traducción aparecen en inglés.
Ciclo de vida del widget de agente incrustable: tokens de navegador ddw_ y lista de orígenes permitidos.
Endpoints
| Método | Ruta | Resumen |
|---|---|---|
GET | /v1/widget_tokens | Listar los tokens de widget |
POST | /v1/widget_tokens | Emitir un token de widget |
DELETE | /v1/widget_tokens/{id} | Revocar un token de widget |
POST | /v1/widget_tokens/renew | Renovar la sesión de widget de quien llama |
POST | /v1/widget_tokens/introspect | El contexto de la sesión de widget de quien llama |
POST | /v1/widget_tokens/sip_credential | Emitir la credencial SIP efímera de quien llama |
DELETE | /v1/widget_tokens/sip_credential | Devolver la credencial SIP efímera de quien llama |
GET | /v1/widget_origins | Listar los orígenes permitidos |
POST | /v1/widget_origins | Añadir un origen permitido |
DELETE | /v1/widget_origins/{id} | Deshabilitar un origen permitido |
POST | /v1/widget_origins/{id}/enable | Volver a habilitar un origen permitido |
Listar los tokens de widget
http
GET /v1/widget_tokensSolo ids, agente, etiquetas, caducidad y revocación; el hash del token nunca se expone.
Respuestas
200
Los tokens de widget del tenant.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
widget_tokens | arreglo de WidgetToken | sí | |
widget_tokens[].id | string (uuid) | no | |
widget_tokens[].agent_id | string (uuid) | no | |
widget_tokens[].label | string | no | |
widget_tokens[].allowed_origin_id | string (uuid) | null | no | Fijación opcional a una fila de widget_origins — reduce los orígenes de EMBED expuestos al frame (CSP/postMessage) a solo ese; null = todos los orígenes de embed habilitados del tenant. NO es el límite de autenticación (ese es el Origin widget-host). El inicio de sesión del agente emite SIN FIJAR. |
widget_tokens[].expires_at | string (date-time) | no | |
widget_tokens[].session_expires_at | string (date-time) | no | |
widget_tokens[].revoked_at | string (date-time) | null | no | |
widget_tokens[].last_used_at | string (date-time) | null | no | Reloj de higiene de rotación, con el mismo significado que ApiKey.last_used_at: la última vez que este token se resolvió CON ÉXITO (superadas todas las compuertas), escrito como mucho una vez por minuto por token, de modo que una lectura reciente puede ir retrasada hasta ese tiempo. null significa que no se ha resuelto con éxito desde que la columna adquirió un escritor en la ruta caliente — no que el token nunca se haya presentado. La renovación también lo marca. |
widget_tokens[].created_at | string (date-time) | no | |
widget_tokens[].updated_at | string (date-time) | no | Fecha la FILA, no la emisión: el reloj de uso anterior y las escrituras del ciclo de vida (renovación, baja) lo mueven todos. |
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"
}
}Emitir un token de widget
http
POST /v1/widget_tokensEmite un token de navegador ddw_ ligado a un agente. El texto plano se devuelve UNA sola vez; solo se almacena su sha256. Los TTL los fija el servidor (nunca vienen de la entrada del cliente). Tiene límite de uso por tenant.
PARA QUIÉN se emite el token depende del principal (ADR #133, ADR #134). Una clave de máquina dd_ nombra a cualquier agente de su tenant y para ella agent_id es obligatorio (400 si falta). Una sesión de login ddu_ cuya persona está vinculada a un puesto de agente emite para ESE puesto: agent_id puede omitirse (se rellena con el puesto) o repetirlo; nombrar a otro agente da 403 forbidden y no se emite ningún token: una persona no puede acuñar la credencial de otro agente. Una ddu_ sin puesto vinculado puede emitir para otro agente solo con users.role = account_admin (un member recibe 403 role_forbidden), una vez que la llave de catálogo del tenant ddu_author_role_enforced está activada (nace apagada: hasta entonces la sesión sin puesto conserva el contrato de dd_, con agent_id obligatorio).
Cuerpo de la petición (JSON, obligatorio)
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
agent_id | string (uuid) | no | El agente en cuyo nombre actúa este token. OBLIGATORIO para una clave dd_; opcional (y, si se indica, debe ser el puesto propio de quien llama) para una sesión ddu_ vinculada a un puesto. |
label | string | no | Etiqueta de formato libre (por defecto ""). |
allowed_origin_id | string (uuid) | no | Opcional: lo fija a una sola fila de widget_origins (acota los orígenes de INCRUSTACIÓN que se muestran al marco; NO es el límite de autenticación, que es el Origin del anfitrión del widget). El inicio de sesión del agente emite SIN fijar. |
json
{
"agent_id": "7a3f0f7e-52a1-4f3d-9f9d-27e5a1b9c001",
"label": "crm-embed"
}Respuestas
201
Token emitido; token es la única vez que se ve el texto plano.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
widget_token | object (WidgetToken) | sí | Un token de widget de navegador ddw_ — el texto plano y el hash nunca se exponen aquí. |
widget_token.id | string (uuid) | no | |
widget_token.agent_id | string (uuid) | no | |
widget_token.label | string | no | |
widget_token.allowed_origin_id | string (uuid) | null | no | Fijación opcional a una fila de widget_origins — reduce los orígenes de EMBED expuestos al frame (CSP/postMessage) a solo ese; null = todos los orígenes de embed habilitados del tenant. NO es el límite de autenticación (ese es el Origin widget-host). El inicio de sesión del agente emite SIN FIJAR. |
widget_token.expires_at | string (date-time) | no | |
widget_token.session_expires_at | string (date-time) | no | |
widget_token.revoked_at | string (date-time) | null | no | |
widget_token.last_used_at | string (date-time) | null | no | Reloj de higiene de rotación, con el mismo significado que ApiKey.last_used_at: la última vez que este token se resolvió CON ÉXITO (superadas todas las compuertas), escrito como mucho una vez por minuto por token, de modo que una lectura reciente puede ir retrasada hasta ese tiempo. null significa que no se ha resuelto con éxito desde que la columna adquirió un escritor en la ruta caliente — no que el token nunca se haya presentado. La renovación también lo marca. |
widget_token.created_at | string (date-time) | no | |
widget_token.updated_at | string (date-time) | no | Fecha la FILA, no la emisión: el reloj de uso anterior y las escrituras del ciclo de vida (renovación, baja) lo mueven todos. |
token | string | sí | Token ddw_ en texto plano, mostrado exactamente una vez. |
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"
}
}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 — WidgetRateLimited
El freno de escritura de tokens de widget rechazó esta petición (reintentable más tarde). code rate_limited. La emisión tiene límite por tenant; la renovación, por token. Retry-After es el tiempo que queda en la ventana fija.
json
{
"error": {
"code": "rate_limited",
"message": "widget token mint rate limit exceeded; retry later"
}
}Revocar un token de widget
http
DELETE /v1/widget_tokens/{id}Fija revoked_at; los tokens nunca se borran. Idempotente.
TAMBIÉN desmonta el endpoint SIP del agente (NR-02): borra la credencial efímera agentcred y el registro usrloc vivo. Sin esto, un token revocado dejaba al softphone en condiciones de hacer REGISTER y cursar llamadas hasta la caducidad automática de la credencial a las 24 h. La revocación en la base de datos es duradera y ocurre en cualquier caso; sip_teardown informa de si la parte SIP tuvo éxito, de modo que un 200 nunca implica una expulsión que no ocurrió.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí | UUID del recurso. Los ids mal formados o de otro tenant se leen como 404. |
Respuestas
200
El token revocado, más el resultado del desmontaje SIP.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
widget_token | object (WidgetToken) | sí | Un token de widget de navegador ddw_ — el texto plano y el hash nunca se exponen aquí. |
widget_token.id | string (uuid) | no | |
widget_token.agent_id | string (uuid) | no | |
widget_token.label | string | no | |
widget_token.allowed_origin_id | string (uuid) | null | no | Fijación opcional a una fila de widget_origins — reduce los orígenes de EMBED expuestos al frame (CSP/postMessage) a solo ese; null = todos los orígenes de embed habilitados del tenant. NO es el límite de autenticación (ese es el Origin widget-host). El inicio de sesión del agente emite SIN FIJAR. |
widget_token.expires_at | string (date-time) | no | |
widget_token.session_expires_at | string (date-time) | no | |
widget_token.revoked_at | string (date-time) | null | no | |
widget_token.last_used_at | string (date-time) | null | no | Reloj de higiene de rotación, con el mismo significado que ApiKey.last_used_at: la última vez que este token se resolvió CON ÉXITO (superadas todas las compuertas), escrito como mucho una vez por minuto por token, de modo que una lectura reciente puede ir retrasada hasta ese tiempo. null significa que no se ha resuelto con éxito desde que la columna adquirió un escritor en la ruta caliente — no que el token nunca se haya presentado. La renovación también lo marca. |
widget_token.created_at | string (date-time) | no | |
widget_token.updated_at | string (date-time) | no | Fecha la FILA, no la emisión: el reloj de uso anterior y las escrituras del ciclo de vida (renovación, baja) lo mueven todos. |
sip_teardown | ok · skipped · failed | sí | Resultado del desmontaje SIP que acompaña a una revocación (NR-02): el borrado de la credencial efímera agentcred del agente y de su registro usrloc vivo en Kamailio. * ok: credencial y registro eliminados; el softphone ya no puede registrarse. * skipped: no había nada que eliminar: el agente no tiene extensión SIP, el aprovisionamiento del SBC no está configurado en este entorno, o el agente aún conserva una sesión VIGENTE (véase abajo), por lo que esta revocación no dejó ningún acceso abierto. * failed: la revocación en la base de datos se mantiene, pero la credencial SIP SIGUE ACTIVA y lo seguirá hasta su caducidad automática a las 24 h. Trátalo como una vía de acceso abierta: reintenta o expulsa al agente por otros medios. Es un campo y no un código de estado a propósito: la revocación en sí es duradera y sí ocurrió, así que un 5xx mentiría en el otro sentido. Lo que nunca debe pasar es un 200 silencioso que implique una expulsión que no ocurrió. El desmontaje sigue a la TRANSICIÓN, no al agente. Revocar un id de token que ya estaba revocado (un id que un cliente puede conservar legítimamente, ya que GET /v1/widget_tokens lista las filas revocadas, y ya que emitir un token sustituye al anterior) NO debe expulsar, porque se cortaría la sesión SUCESORA del agente. Por tanto, el desmontaje solo se ejecuta cuando el agente se queda sin ningún token vigente; en caso contrario informa skipped. Esto es lo que mantiene útil el consejo de reintento de failed: un token ya revocado y sin sucesor vivo sí expulsa en un DELETE reintentado, de modo que reintentar es un remedio real y no una operación vacía. |
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"
}
}Renovar la sesión de widget de quien llama
http
POST /v1/widget_tokens/renewAdelanta la caducidad del token ddw_ AUTENTICADO (nunca más allá del tope de la sesión). Se autentica con el propio ddw_; opera SOLO sobre el token de quien llama (no hay id en la ruta ni en el cuerpo). Tiene límite de uso por token.
Respuestas
200
El token renovado.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
widget_token | object (WidgetToken) | sí | Un token de widget de navegador ddw_ — el texto plano y el hash nunca se exponen aquí. |
widget_token.id | string (uuid) | no | |
widget_token.agent_id | string (uuid) | no | |
widget_token.label | string | no | |
widget_token.allowed_origin_id | string (uuid) | null | no | Fijación opcional a una fila de widget_origins — reduce los orígenes de EMBED expuestos al frame (CSP/postMessage) a solo ese; null = todos los orígenes de embed habilitados del tenant. NO es el límite de autenticación (ese es el Origin widget-host). El inicio de sesión del agente emite SIN FIJAR. |
widget_token.expires_at | string (date-time) | no | |
widget_token.session_expires_at | string (date-time) | no | |
widget_token.revoked_at | string (date-time) | null | no | |
widget_token.last_used_at | string (date-time) | null | no | Reloj de higiene de rotación, con el mismo significado que ApiKey.last_used_at: la última vez que este token se resolvió CON ÉXITO (superadas todas las compuertas), escrito como mucho una vez por minuto por token, de modo que una lectura reciente puede ir retrasada hasta ese tiempo. null significa que no se ha resuelto con éxito desde que la columna adquirió un escritor en la ruta caliente — no que el token nunca se haya presentado. La renovación también lo marca. |
widget_token.created_at | string (date-time) | no | |
widget_token.updated_at | string (date-time) | no | Fecha la FILA, no la emisión: el reloj de uso anterior y las escrituras del ciclo de vida (renovación, baja) lo mueven todos. |
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"
}
}429 — WidgetRateLimited
El freno de escritura de tokens de widget rechazó esta petición (reintentable más tarde). code rate_limited. La emisión tiene límite por tenant; la renovación, por token. Retry-After es el tiempo que queda en la ventana fija.
json
{
"error": {
"code": "rate_limited",
"message": "widget token mint rate limit exceeded; retry later"
}
}El contexto de la sesión de widget de quien llama
http
POST /v1/widget_tokens/introspectDevuelve el tenant y el agente de la sesión ddw_ autenticada, sus orígenes permitidos (para la CSP del marco) y sus relojes de sesión. Se autentica con el propio ddw_; acotado al tenant, sin enumeración.
Respuestas
200
El contexto vivo de la sesión de quien llama.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
widget_session | object (WidgetSession) | sí | La vista de introspección con la que arranca un marco (su propia sesión viva). |
widget_session.tenant_id | string (uuid) | sí | |
widget_session.agent_id | string (uuid) | sí | |
widget_session.origins | arreglo de string | sí | Los orígenes de INCRUSTACIÓN habilitados de la sesión (widget_origins) para la CSP / postMessage del marco; NO es el límite de autenticación (el Origin del anfitrión del widget). |
widget_session.expires_at | string (date-time) | sí | |
widget_session.session_expires_at | string (date-time) | sí |
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"
}
}Emitir la credencial SIP efímera de quien llama
http
POST /v1/widget_tokens/sip_credentialAprovisiona la credencial SIP EFÍMERA (agentcred_w) de la sesión ddw_ AUTENTICADA y la devuelve una sola vez, en memoria: el arranque del marco para registrarse por WSS (MT-CTI-07 fase 2).
Se autentica con el propio ddw_ y opera SOLO sobre la sesión de quien llama: el id del token sale del bearer, nunca de un valor de la ruta o del cuerpo, de modo que una sesión no puede emitir ni leer la de otra. La credencial es por TOKEN (w-<token_id>@t-<tenant>.<base>), nunca por extensión del agente, y vive en su propia htable y en su propio AOR de usrloc, por lo que revocarla no puede alcanzar la credencial del softphone del agente, ni al revés.
FAIL-CLOSED: si no se puede emitir la credencial, NO se devuelve NADA. No hay respaldo a agentcred, la credencial de 24 h del softphone del agente; un marco sin audio es el resultado previsto.
Idempotente por sesión: una nueva emisión SOBRESCRIBE la clave, así que la contraseña ANTERIOR de esa misma sesión deja de funcionar. Tiene límite de uso por token.
La password se devuelve EXACTAMENTE UNA VEZ y no se almacena en ningún lugar del lado del servidor: ni en Postgres, ni en una línea de log, ni en una fila de auditoría. El rastro de auditoría registra QUE se emitió una credencial, nunca CUÁL.
Respuestas
200
El arranque, o sip: null cuando el carril SIP del widget no está armado en este entorno (WIDGET_SIP_ENABLED=false, o sin SBC configurado). null es un estado de DESPLIEGUE, no un fallo de quien llama: no se inventa ninguna credencial y el marco simplemente no tiene audio. Ramifica sobre ello en lugar de reintentar.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
sip | WidgetSipCredential | null | sí |
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"
}
}429 — WidgetRateLimited
El freno de escritura de tokens de widget rechazó esta petición (reintentable más tarde). code rate_limited. La emisión tiene límite por tenant; la renovación, por token. Retry-After es el tiempo que queda en la ventana fija.
json
{
"error": {
"code": "rate_limited",
"message": "widget token mint rate limit exceeded; retry later"
}
}503 — WidgetSipUnavailable
No se pudo aprovisionar la credencial SIP (code sbc_unavailable), así que no se devolvió NADA. FAIL-CLOSED y reintentable: no hay respaldo a la agentcred de larga duración del agente, porque entregar al marco una credencial que el servidor no pretendía conceder es peor que un marco sin audio.
json
{
"error": {
"code": "sbc_unavailable",
"message": "widget sip provisioning unavailable, retry"
}
}Devolver la credencial SIP efímera de quien llama
http
DELETE /v1/widget_tokens/sip_credentialBorra la credencial agentcred_w de la sesión ddw_ AUTENTICADA y su registro usrloc, SIN terminar la sesión: el token sigue vivo y puede volver a emitir. Es lo que el marco llama al descargarse, al cerrar sesión o cuando el agente pasa a un teléfono de escritorio.
Su razón de ser es el residuo: sin él, el único desmontaje para una sesión que deja de usar audio es la caducidad automática de la htable o revocar el token entero, hasta 12 h de una credencial viva que nadie va a usar.
Idempotente, y llamarlo nunca es un error para una sesión que jamás encendió SIP. Acotado a la sesión de quien llama (el id del token sale del bearer), así que nunca puede alcanzar la credencial de una sesión hermana ni la agentcred del agente.
Respuestas
200
El resultado del desmontaje. failed se informa en un 200 A PROPÓSITO (ADR #56 D3: un fallo del SBC se dice, no se traga): la sesión del marco no depende de que el desmontaje haya tenido éxito, y lo que quede se resuelve de todos modos con la caducidad automática de la htable o el barrido del tope de sesión. No reintentes en bucle ante él.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
sip_teardown | ok · skipped · failed | sí | Resultado de desmontar la credencial efímera de una sesión de WIDGET: el carril agentcred_w. Distinto de SipTeardown, que informa sobre la agentcred del agente: los dos carriles tienen htables y AOR separados precisamente para que uno nunca pueda alcanzar al otro, y informarlos con un solo esquema es como empiezan a leerse como uno. * ok: credencial y registro usrloc eliminados; este marco ya no puede registrarse. * skipped: no había nada que eliminar: el carril SIP del widget no está armado en este entorno, así que nunca se emitió ninguna credencial. * failed: falló el RPC al SBC y la credencial sigue viva hasta la caducidad automática de agentcred_w. Se registra y se emite como telemetría en lugar de tragarse. Se informa dentro de un 200 a propósito; no reintentes en bucle. |
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"
}
}Listar los orígenes permitidos
http
GET /v1/widget_originsRespuestas
200
Los orígenes permitidos del tenant (habilitados y deshabilitados).
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
widget_origins | arreglo de WidgetOrigin | sí | |
widget_origins[].id | string (uuid) | no | |
widget_origins[].origin | string | no | Origen https canónico (host en minúsculas, sin el :443 por defecto). |
widget_origins[].label | string | no | |
widget_origins[].disabled_at | string (date-time) | null | no | No nulo = deshabilitado (fuera de la lista de incrustación permitida: sin frame-ancestors/postMessage, nunca se muestra a un marco). |
widget_origins[].created_at | string (date-time) | no | |
widget_origins[].updated_at | string (date-time) | no |
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"
}
}Añadir un origen permitido
http
POST /v1/widget_originsEl origen en bruto se normaliza a la forma https canónica; un valor mal formado da 400.
Cuerpo de la petición (JSON, obligatorio)
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
origin | string | sí | Un origen web, p. ej. https://crm.example.com. |
label | string | no |
json
{
"origin": "https://crm.example.com"
}Respuestas
201
El origen añadido (forma canónica).
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
widget_origin | object (WidgetOrigin) | sí | Un origen web de la lista de INCRUSTACIÓN permitida por tenant (forma https canónica): gobierna quién puede enmarcar el widget (CSP frame-ancestors / postMessage); NO es el límite de autenticación (el Origin del anfitrión del widget). |
widget_origin.id | string (uuid) | no | |
widget_origin.origin | string | no | Origen https canónico (host en minúsculas, sin el :443 por defecto). |
widget_origin.label | string | no | |
widget_origin.disabled_at | string (date-time) | null | no | No nulo = deshabilitado (fuera de la lista de incrustación permitida: sin frame-ancestors/postMessage, nunca se muestra a un marco). |
widget_origin.created_at | string (date-time) | no | |
widget_origin.updated_at | string (date-time) | no |
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"
}
}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 — Unprocessable
La forma es correcta, la semántica no (regla de dominio incumplida).
json
{
"error": {
"code": "unprocessable",
"message": "scheduled_at is closer than the minimum notice for a callback (10 minutes unless the tenant's callback_min_notice_seconds says otherwise)"
}
}429 — ApiKeyRateLimited
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"
}
}Deshabilitar un origen permitido
http
DELETE /v1/widget_origins/{id}Deshabilitación suave (fuera de la lista de incrustación permitida: deja de enmarcar este CRM mediante frame-ancestors/postMessage; NO bloquea el inicio de sesión del agente, que se controla con el Origin del anfitrión del widget). Los orígenes nunca se borran.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí | UUID del recurso. Los ids mal formados o de otro tenant se leen como 404. |
Respuestas
200
El origen deshabilitado.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
widget_origin | object (WidgetOrigin) | sí | Un origen web de la lista de INCRUSTACIÓN permitida por tenant (forma https canónica): gobierna quién puede enmarcar el widget (CSP frame-ancestors / postMessage); NO es el límite de autenticación (el Origin del anfitrión del widget). |
widget_origin.id | string (uuid) | no | |
widget_origin.origin | string | no | Origen https canónico (host en minúsculas, sin el :443 por defecto). |
widget_origin.label | string | no | |
widget_origin.disabled_at | string (date-time) | null | no | No nulo = deshabilitado (fuera de la lista de incrustación permitida: sin frame-ancestors/postMessage, nunca se muestra a un marco). |
widget_origin.created_at | string (date-time) | no | |
widget_origin.updated_at | string (date-time) | no |
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"
}
}Volver a habilitar un origen permitido
http
POST /v1/widget_origins/{id}/enableParámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
id | path | string (uuid) | sí | UUID del recurso. Los ids mal formados o de otro tenant se leen como 404. |
Respuestas
200
El origen vuelto a habilitar.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
widget_origin | object (WidgetOrigin) | sí | Un origen web de la lista de INCRUSTACIÓN permitida por tenant (forma https canónica): gobierna quién puede enmarcar el widget (CSP frame-ancestors / postMessage); NO es el límite de autenticación (el Origin del anfitrión del widget). |
widget_origin.id | string (uuid) | no | |
widget_origin.origin | string | no | Origen https canónico (host en minúsculas, sin el :443 por defecto). |
widget_origin.label | string | no | |
widget_origin.disabled_at | string (date-time) | null | no | No nulo = deshabilitado (fuera de la lista de incrustación permitida: sin frame-ancestors/postMessage, nunca se muestra a un marco). |
widget_origin.created_at | string (date-time) | no | |
widget_origin.updated_at | string (date-time) | no |
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"
}
}