Appearance
Plantillas de email
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.
Plantillas de email por tenant (asunto estático + cuerpo con variables tipadas), versiones de solo anexar, aprobación y retirada por account_admin.
Endpoints
| Método | Ruta | Resumen |
|---|---|---|
GET | /v1/email-templates | Versiones de plantillas de email |
POST | /v1/email-templates | Crear un borrador (la siguiente versión cuando name ya existe) |
GET | /v1/email-templates/{id} | Una versión de plantilla |
PATCH | /v1/email-templates/{id} | Editar un borrador (subject / body / variables / creditor_names) |
POST | /v1/email-templates/{id}/approve | Aprobar un borrador (solo account_admin) |
POST | /v1/email-templates/{id}/retire | Retirar una versión (solo account_admin; un borrador se descarta retirándolo) |
Versiones de plantillas de email
http
GET /v1/email-templatesTodas las versiones de todas las plantillas de email del tenant, la versión más reciente primero por name.
Parámetros
| Nombre | En | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
status | query | draft · approved · retired | no | |
name | query | string | no |
Respuestas
200
Las versiones de plantilla del tenant.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
email_templates | arreglo de EmailTemplate | sí | |
email_templates[].id | string (uuid) | no | |
email_templates[].name | string | no | |
email_templates[].version | integer | no | |
email_templates[].status | draft · approved · retired | no | |
email_templates[].subject | string | no | |
email_templates[].body | string | no | |
email_templates[].variables | arreglo de EmailTemplateVariable | no | |
email_templates[].variables[].name | string | sí | |
email_templates[].variables[].type | string · number · date | sí | |
email_templates[].variables[].required | boolean | no | Una variable opcional que no se envía se renderiza vacía. |
email_templates[].creditor_names | arreglo de string | no | |
email_templates[].approved_by | string (uuid) | null | no | |
email_templates[].approved_at | string (date-time) | null | no | |
email_templates[].retired_at | string (date-time) | null | no | |
email_templates[].created_at | string (date-time) | no | |
email_templates[].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"
}
}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"
}
}Crear un borrador (la siguiente versión cuando name ya existe)
http
POST /v1/email-templatesEl body usa marcadores {{variable}}; cada marcador debe declararse en variables y cada variable declarada debe usarse. El subject es texto ESTÁTICO (sin marcadores) y debe pasar la política de asunto frente a los creditor_names declarados: no puede nombrar la deuda, un importe ni un acreedor. El cuerpo estático debe llevar ya el aviso de baja y la declaración del cobrador (las mismas reglas que aplica el envío). Un name que ya tiene versiones abre la siguiente versión como un borrador nuevo: una versión aprobada nunca se edita. tenant_id, version y status nunca son entrada del cuerpo.
Cuerpo de la petición (JSON, obligatorio)
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
name | string | sí | Familia de plantilla; un nombre existente abre su siguiente versión. |
subject | string | sí | Texto estático: sin marcadores {{}}; no puede nombrar la deuda, un importe ni un acreedor. |
body | string | sí | |
variables | arreglo de EmailTemplateVariable | no | |
variables[].name | string | sí | |
variables[].type | string · number · date | sí | |
variables[].required | boolean | no | Una variable opcional que no se envía se renderiza vacía. |
creditor_names | arreglo de string | no | Nombres de acreedores contra los que la política de asunto comprueba el asunto (recortados, sin duplicados). |
json
{
"name": "payment-reminder",
"subject": "Un mensaje importante para usted",
"body": "Hola {{first_name}}. Este mensaje proviene de una agencia de cobranza. Para dejar de recibir correos, responda BAJA.",
"variables": [
{
"name": "first_name",
"type": "string"
}
],
"creditor_names": []
}Respuestas
201
El nuevo borrador.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
email_template | object (EmailTemplate) | sí | |
email_template.id | string (uuid) | no | |
email_template.name | string | no | |
email_template.version | integer | no | |
email_template.status | draft · approved · retired | no | |
email_template.subject | string | no | |
email_template.body | string | no | |
email_template.variables | arreglo de EmailTemplateVariable | no | |
email_template.variables[].name | string | sí | |
email_template.variables[].type | string · number · date | sí | |
email_template.variables[].required | boolean | no | Una variable opcional que no se envía se renderiza vacía. |
email_template.creditor_names | arreglo de string | no | |
email_template.approved_by | string (uuid) | null | no | |
email_template.approved_at | string (date-time) | null | no | |
email_template.retired_at | string (date-time) | null | no | |
email_template.created_at | string (date-time) | no | |
email_template.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"
}
}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 versión de plantilla
http
GET /v1/email-templates/{id}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
La versión.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
email_template | object (EmailTemplate) | sí | |
email_template.id | string (uuid) | no | |
email_template.name | string | no | |
email_template.version | integer | no | |
email_template.status | draft · approved · retired | no | |
email_template.subject | string | no | |
email_template.body | string | no | |
email_template.variables | arreglo de EmailTemplateVariable | no | |
email_template.variables[].name | string | sí | |
email_template.variables[].type | string · number · date | sí | |
email_template.variables[].required | boolean | no | Una variable opcional que no se envía se renderiza vacía. |
email_template.creditor_names | arreglo de string | no | |
email_template.approved_by | string (uuid) | null | no | |
email_template.approved_at | string (date-time) | null | no | |
email_template.retired_at | string (date-time) | null | no | |
email_template.created_at | string (date-time) | no | |
email_template.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"
}
}Editar un borrador (subject / body / variables / creditor_names)
http
PATCH /v1/email-templates/{id}Solo un draft puede cambiar; una versión aprobada o retirada responde 409 (crea una versión nueva en su lugar).
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. |
Cuerpo de la petición (JSON, obligatorio)
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
subject | string | no | |
body | string | no | |
variables | arreglo de EmailTemplateVariable | no | |
variables[].name | string | sí | |
variables[].type | string · number · date | sí | |
variables[].required | boolean | no | Una variable opcional que no se envía se renderiza vacía. |
creditor_names | arreglo de string | no |
Respuestas
200
El borrador actualizado.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
email_template | object (EmailTemplate) | sí | |
email_template.id | string (uuid) | no | |
email_template.name | string | no | |
email_template.version | integer | no | |
email_template.status | draft · approved · retired | no | |
email_template.subject | string | no | |
email_template.body | string | no | |
email_template.variables | arreglo de EmailTemplateVariable | no | |
email_template.variables[].name | string | sí | |
email_template.variables[].type | string · number · date | sí | |
email_template.variables[].required | boolean | no | Una variable opcional que no se envía se renderiza vacía. |
email_template.creditor_names | arreglo de string | no | |
email_template.approved_by | string (uuid) | null | no | |
email_template.approved_at | string (date-time) | null | no | |
email_template.retired_at | string (date-time) | null | no | |
email_template.created_at | string (date-time) | no | |
email_template.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"
}
}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 — 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"
}
}Aprobar un borrador (solo account_admin)
http
POST /v1/email-templates/{id}/approveAprueba el borrador exactamente como está y registra quién y cuándo (approved_by, approved_at). Solo un login account_admin puede aprobar: un member o una clave de máquina dd_ recibe 403. La base de datos también lo hace cumplir. Una versión que no es un borrador responde 409.
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
La versión aprobada.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
email_template | object (EmailTemplate) | sí | |
email_template.id | string (uuid) | no | |
email_template.name | string | no | |
email_template.version | integer | no | |
email_template.status | draft · approved · retired | no | |
email_template.subject | string | no | |
email_template.body | string | no | |
email_template.variables | arreglo de EmailTemplateVariable | no | |
email_template.variables[].name | string | sí | |
email_template.variables[].type | string · number · date | sí | |
email_template.variables[].required | boolean | no | Una variable opcional que no se envía se renderiza vacía. |
email_template.creditor_names | arreglo de string | no | |
email_template.approved_by | string (uuid) | null | no | |
email_template.approved_at | string (date-time) | null | no | |
email_template.retired_at | string (date-time) | null | no | |
email_template.created_at | string (date-time) | no | |
email_template.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"
}
}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 — 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"
}
}Retirar una versión (solo account_admin; un borrador se descarta retirándolo)
http
POST /v1/email-templates/{id}/retireTerminal. Una versión retirada ya no se puede enviar; una ya retirada responde 409. Solo un login account_admin puede retirar (un member o una clave de máquina dd_ recibe 403): retirar saca de uso una plantilla aprobada, así que tiene la misma autoridad que aprobarla.
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
La versión retirada.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
email_template | object (EmailTemplate) | sí | |
email_template.id | string (uuid) | no | |
email_template.name | string | no | |
email_template.version | integer | no | |
email_template.status | draft · approved · retired | no | |
email_template.subject | string | no | |
email_template.body | string | no | |
email_template.variables | arreglo de EmailTemplateVariable | no | |
email_template.variables[].name | string | sí | |
email_template.variables[].type | string · number · date | sí | |
email_template.variables[].required | boolean | no | Una variable opcional que no se envía se renderiza vacía. |
email_template.creditor_names | arreglo de string | no | |
email_template.approved_by | string (uuid) | null | no | |
email_template.approved_at | string (date-time) | null | no | |
email_template.retired_at | string (date-time) | null | no | |
email_template.created_at | string (date-time) | no | |
email_template.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"
}
}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 — 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"
}
}