Appearance
Usuarios
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.
Cuentas de usuario del dashboard (email + contraseña; se deshabilitan, nunca se eliminan).
Endpoints
| Método | Ruta | Resumen |
|---|---|---|
GET | /v1/users | Listar los usuarios del dashboard y las invitaciones abiertas |
POST | /v1/users | Invitar a una persona al dashboard |
DELETE | /v1/users/{id} | Deshabilitar a un usuario (nunca elimina) |
POST | /v1/users/{id}/enable | Volver a habilitar a un usuario deshabilitado |
POST | /v1/users/{id}/mfa/reset-failures | Levantar el freno de segundo factor de una persona |
POST | /v1/users/{id}/mfa/remove | Quitar el segundo factor de una persona (autenticador y códigos de recuperación perdidos) |
Listar los usuarios del dashboard y las invitaciones abiertas
http
GET /v1/usersEmails, nombres, estado y marcas de tiempo de inicio de sesión — los hashes de contraseña nunca se exponen. invitations lista las invitaciones ABIERTAS (ni aceptadas ni reemplazadas) enviadas por POST /v1/users, de la más reciente a la más antigua: pending hasta que caducan, expired después. Una invitación a una dirección que ya es usuaria de otro tenant se lista, y caduca, exactamente como una que nadie abrió — esta lista no dice nada sobre a quién más pertenece la dirección. Una invitación aceptada sale de esta lista y su persona aparece en users.
Respuestas
200
Los usuarios del dashboard del tenant y sus invitaciones abiertas.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
users | arreglo de User | sí | |
users[].id | string (uuid) | no | |
users[].email | string (email) | no | Identificador de inicio de sesión global, almacenado en minúsculas. |
users[].name | string | no | |
users[].status | active · disabled | no | |
users[].role | member · account_admin | no | Privilegio dentro de la cuenta. Solo un account_admin puede crear o modificar las filas de toda la empresa que heredan todas las sedes hermanas (scope: "empresa" en carriers y proveedores de SMS); un member recibe 403. Solo lectura aquí: la promoción es un gesto del operador, nunca una petición. |
users[].password_updated_at | string (date-time) | no | |
users[].last_login_at | string (date-time) | null | no | |
users[].mfa_enabled | boolean | no | Si la persona tiene un segundo factor ACTIVO (una inscripción pendiente de confirmación es false). Se emite SOLO cuando quien llama es un inicio de sesión de dashboard account_admin, el que puede actuar sobre él con POST /v1/users/{id}/mfa/remove; para un member, una clave dd_, o cuando no se puede determinar el rol de quien llama, el campo está AUSENTE (no es false). Dondequiera que se renderice un User rige la misma regla: GET /v1/users, GET /v1/me, el usuario devuelto por DELETE /v1/users/{id} y POST /v1/users/{id}/enable, y el usuario en las respuestas de sesión (POST /v1/auth/login, POST /v1/auth/sso/exchange y las dos rutas de finalización de MFA); en ellas, para el account_admin que acaba de iniciar sesión. |
users[].created_at | string (date-time) | no | |
users[].updated_at | string (date-time) | no | |
invitations | arreglo de UserInvitation | sí | |
invitations[].id | string (uuid) | no | |
invitations[].email | string (email) | no | Almacenado en minúsculas. |
invitations[].name | string | no | |
invitations[].status | pending · expired | no | pending hasta expires_at, expired después. Reenvía invitando de nuevo. |
invitations[].expires_at | string (date-time) | no | |
invitations[].created_at | string (date-time) | no | |
invitations[].invited_by | object | no | Quién hizo la invitación (core#2449), inmutable. kind es user (un inicio de sesión de dashboard; user_id es esa persona), api_key (una clave dd_; user_id null) u operator. kind es null para una invitación anterior al registro. |
invitations[].invited_by.kind | user · api_key · operator · null | sí | |
invitations[].invited_by.user_id | string,null (uuid) | sí | |
truncated | boolean | sí | true cuando hay más filas que los 500 usuarios o 500 invitaciones abiertas (es true si cualquiera de las listas se cortó): la respuesta es un prefijo en el orden documentado, no el conjunto completo. |
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"
}
}Invitar a una persona al dashboard
http
POST /v1/usersInvita — no crea al usuario (ADR #182, un cambio incompatible de esta operación: antes tomaba una password y respondía 201 con el usuario creado). Registra una invitación y envía por correo a la dirección un enlace de un solo uso (válido 72 h) a /accept-invite; la persona se crea cuando lo canjea con la contraseña que ELLA elige, mediante POST /v1/auth/password-reset/confirm. Por tanto, una dirección solo la ocupa quien demostró que lee su correo.
La respuesta es 202 con el MISMO cuerpo — byte por byte — tanto si la dirección está libre como si ya es usuaria de OTRO tenant. En el segundo caso la invitación se registra y se lista igualmente, y la dirección recibe un aviso de que ya tiene una cuenta (sin enlace): el tenant que invita no averigua nada de otros tenants. Solo una dirección que ya es usuaria de ESTE tenant, activa o deshabilitada, da 409 — esa fila ya está en el propio GET /v1/users de este tenant.
Reglas de rol (core#2334, core#2449): una vez que el tenant tiene un account_admin activo, esto requiere un inicio de sesión account_admin (403 role_forbidden para un member Y para una clave dd_; interruptor de tenant user_management_admin_only, activado por defecto; interruptor del founder api_key_manages_people, desactivado por defecto, devuelve a la clave dd_ su alcance anterior). Un tenant sin account_admin activo mantiene la postura anterior, clave dd_ incluida (invita a la primera persona). La invitación registra quién la hizo (invited_by).
Invitar a la misma dirección de nuevo reemplaza el enlace anterior (así se reenvía una invitación). Dos frenos acotan el correo que esta ruta puede enviar: por tenant (un 429 visible) y por dirección entre todos los tenants (invisible: por encima de él la invitación se registra igualmente y la respuesta es el mismo 202, pero no sale ningún correo — un 429 ahí le diría a un tenant que otro acaba de invitar a esa dirección).
El bootstrap se hace con la clave de máquina dd_ (invita al PRIMER usuario); después cualquier sesión ddu_ puede gestionar usuarios (todos los usuarios son administradores de la consola desde el día 1). tenant_id nunca se lee del cuerpo. Una password en el cuerpo da 400: la persona invitada la elige.
Cuerpo de la petición (JSON, obligatorio)
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
email | string (email) | sí | |
name | string | no | |
locale | es · en | no | Idioma en el que el administrador que invita tiene la consola; la invitación (y el aviso "esta dirección ya tiene una cuenta") se envía en él. Ausente o cualquier otro: el idioma de la celda (DEFAULT_LOCALE). Nunca es un error. |
json
{
"email": "[email protected]",
"name": "Ops Admin",
"locale": "es"
}Respuestas
202
Invitación registrada. Idéntica para todos los resultados registrados (véase la descripción).
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
status | invited | sí | |
message | string | sí |
json
{
"status": "invited",
"message": "invitation recorded"
}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 — UserManagementForbidden
Se rechazó una escritura de gestión de usuarios (core#2334, adenda del ADR #46). code admin_target_forbidden: un inicio de sesión member intentó deshabilitar o volver a habilitar a un account_admin — siempre, sea cual sea la configuración del tenant. code role_forbidden: el tenant tiene un account_admin activo y quien llama es un inicio de sesión member o (core#2449) una clave dd_ (la ruta requiere un inicio de sesión account_admin; el interruptor del founder api_key_manages_people, desactivado por defecto, restablece la clave); el interruptor por tenant user_management_admin_only (activado por defecto) desactiva este, y a un tenant sin account_admin activo no se le pide uno. code forbidden: el tenant está suspendido o el token es un token de widget.
json
{
"error": {
"code": "role_forbidden",
"message": "managing users takes a dashboard login with the account_admin role"
}
}409
La dirección ya es usuaria de ESTE tenant (activa o deshabilitada), o una invitación concurrente a ella de este mismo tenant ganó la carrera.
json
{
"error": {
"code": "conflict",
"message": "that address is already a user of this tenant"
}
}429
El freno de invitaciones de este tenant rechazó la petición (ventana fija; se puede reintentar más tarde). code rate_limited. Se aplica solo por tenant — no dice nada sobre la dirección. Retry-After es el tiempo que queda de la ventana fija.
json
{
"error": {
"code": "rate_limited",
"message": "user invitation rate limit exceeded; retry later"
}
}Deshabilitar a un usuario (nunca elimina)
http
DELETE /v1/users/{id}Establece status: disabled Y revoca todas las sesiones vivas que el usuario tiene (su bearer muere en la siguiente petición). Idempotente. Los usuarios son evidencia de auditoría — las filas nunca se eliminan; vuelve a habilitar con POST /v1/users/{id}/enable.
Se rechaza con 409 cuando dejaría la cuenta sin acceso (core#2328): cannot_disable_self cuando quien llama es el objetivo (un inicio de sesión de dashboard; una clave dd_ no es una persona), y last_account_admin cuando el objetivo es el único account_admin activo del tenant. Un usuario ya deshabilitado sigue siendo idempotente.
Reglas de rol (core#2334): una vez que el tenant tiene un account_admin activo, esto acepta una clave dd_ o un inicio de sesión account_admin (403 role_forbidden para un member Y, desde core#2449, para una clave dd_; interruptor de tenant user_management_admin_only, activado por defecto; interruptor del founder api_key_manages_people, desactivado por defecto). Un tenant sin account_admin activo mantiene la postura anterior, clave dd_ incluida. Un member nunca puede deshabilitar a un account_admin (403 admin_target_forbidden).
Claves que la persona emitió (core#2359): la respuesta lista toda clave dd_ que su sesión emitió en issued_api_keys (las vivas tienen revoked_at: null), de modo que el administrador pueda rotar lo que dejó quien se va. Interruptor por tenant user_disable_revokes_api_keys (desactivado por defecto): cuando está activado, deshabilitar a la persona revoca primero sus claves vivas.
Asiento y credencial SIP (core#2405): interruptor por tenant user_disable_retires_seat (activado por defecto). El agente vinculado a la persona sale del FSM de agentes (armado mientras hay una llamada en curso), se expulsan su entrada agentcred y su binding usrloc y se desactiva su inicio de sesión de widget; seat_retirement informa de cada paso (null con el interruptor desactivado). POST /v1/auth/agent-login rechaza a un agente cuya persona vinculada no está activa.
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 usuario deshabilitado y las claves de API que esa persona emitió.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
user | object (User) | sí | Un usuario del dashboard; el hash de la contraseña nunca se expone. |
user.id | string (uuid) | no | |
user.email | string (email) | no | Identificador de inicio de sesión global, almacenado en minúsculas. |
user.name | string | no | |
user.status | active · disabled | no | |
user.role | member · account_admin | no | Privilegio dentro de la cuenta. Solo un account_admin puede crear o modificar las filas de toda la empresa que heredan todas las sedes hermanas (scope: "empresa" en carriers y proveedores de SMS); un member recibe 403. Solo lectura aquí: la promoción es un gesto del operador, nunca una petición. |
user.password_updated_at | string (date-time) | no | |
user.last_login_at | string (date-time) | null | no | |
user.mfa_enabled | boolean | no | Si la persona tiene un segundo factor ACTIVO (una inscripción pendiente de confirmación es false). Se emite SOLO cuando quien llama es un inicio de sesión de dashboard account_admin, el que puede actuar sobre él con POST /v1/users/{id}/mfa/remove; para un member, una clave dd_, o cuando no se puede determinar el rol de quien llama, el campo está AUSENTE (no es false). Dondequiera que se renderice un User rige la misma regla: GET /v1/users, GET /v1/me, el usuario devuelto por DELETE /v1/users/{id} y POST /v1/users/{id}/enable, y el usuario en las respuestas de sesión (POST /v1/auth/login, POST /v1/auth/sso/exchange y las dos rutas de finalización de MFA); en ellas, para el account_admin que acaba de iniciar sesión. |
user.created_at | string (date-time) | no | |
user.updated_at | string (date-time) | no | |
issued_api_keys | arreglo de ApiKey | sí | |
issued_api_keys[].id | string (uuid) | no | |
issued_api_keys[].label | string | no | |
issued_api_keys[].revoked_at | string (date-time) | null | no | |
issued_api_keys[].last_used_at | string (date-time) | null | no | Reloj de higiene de rotación: la última vez que esta clave se autenticó CON ÉXITO. Se escribe como mucho una vez por minuto por clave, de modo que una lectura reciente puede ir retrasada hasta ese tiempo. null significa que no se ha autenticado con éxito desde que la columna adquirió un escritor — no que la clave nunca se haya presentado. |
issued_api_keys[].allowed_cidrs | arreglo de string | no | Lista de permitidos de red (core#2450). [] = sin restricción. Fuera de ella, una petición se sirve y se cuenta, o se rechaza con 401, según el interruptor de tenant api_key_network_enforced (desactivado por defecto). |
issued_api_keys[].stale | boolean | no | true para una clave viva sin usar durante 90 días (una clave que nunca se autenticó cuenta desde su creación). Consejo para que la consola rote o revoque; nada caduca por sí solo. |
issued_api_keys[].created_by_user_id | string (uuid) | null | no | El usuario del dashboard cuya sesión emitió la clave (core#2359). null cuando la emitió otra clave dd_, el operador o las semillas, y en toda clave anterior al campo. |
issued_api_keys[].created_at | string (date-time) | no | |
seat_retirement | object,null | no | Qué pasó con el asiento del agente vinculado; null cuando user_disable_retires_seat está desactivado. |
seat_retirement.seat | retired · armed · none · failed | no | |
seat_retirement.sip_teardown | ok · skipped · failed | no | |
seat_retirement.widget_login | disabled · none · failed | 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 — UserManagementForbidden
Se rechazó una escritura de gestión de usuarios (core#2334, adenda del ADR #46). code admin_target_forbidden: un inicio de sesión member intentó deshabilitar o volver a habilitar a un account_admin — siempre, sea cual sea la configuración del tenant. code role_forbidden: el tenant tiene un account_admin activo y quien llama es un inicio de sesión member o (core#2449) una clave dd_ (la ruta requiere un inicio de sesión account_admin; el interruptor del founder api_key_manages_people, desactivado por defecto, restablece la clave); el interruptor por tenant user_management_admin_only (activado por defecto) desactiva este, y a un tenant sin account_admin activo no se le pide uno. code forbidden: el tenant está suspendido o el token es un token de widget.
json
{
"error": {
"code": "role_forbidden",
"message": "managing users takes a dashboard login with the account_admin role"
}
}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
Rechazado: cannot_disable_self (quien llama es el objetivo) o last_account_admin (el objetivo es el único account_admin activo).
json
{
"error": {
"code": "last_account_admin",
"message": "the last active account_admin cannot be disabled; promote another one first"
}
}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 a un usuario deshabilitado
http
POST /v1/users/{id}/enableLas sesiones revocadas al deshabilitar SIGUEN revocadas — el usuario inicia sesión desde cero.
Reglas de rol (core#2334): una vez que el tenant tiene un account_admin activo, esto acepta una clave dd_ o un inicio de sesión account_admin (403 role_forbidden para un member Y, desde core#2449, para una clave dd_; interruptor de tenant user_management_admin_only, activado por defecto; interruptor del founder api_key_manages_people, desactivado por defecto). Un tenant sin account_admin activo mantiene la postura anterior, clave dd_ incluida. Un member nunca puede volver a habilitar a un account_admin (403 admin_target_forbidden).
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 usuario vuelto a habilitar.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
user | object (User) | sí | Un usuario del dashboard; el hash de la contraseña nunca se expone. |
user.id | string (uuid) | no | |
user.email | string (email) | no | Identificador de inicio de sesión global, almacenado en minúsculas. |
user.name | string | no | |
user.status | active · disabled | no | |
user.role | member · account_admin | no | Privilegio dentro de la cuenta. Solo un account_admin puede crear o modificar las filas de toda la empresa que heredan todas las sedes hermanas (scope: "empresa" en carriers y proveedores de SMS); un member recibe 403. Solo lectura aquí: la promoción es un gesto del operador, nunca una petición. |
user.password_updated_at | string (date-time) | no | |
user.last_login_at | string (date-time) | null | no | |
user.mfa_enabled | boolean | no | Si la persona tiene un segundo factor ACTIVO (una inscripción pendiente de confirmación es false). Se emite SOLO cuando quien llama es un inicio de sesión de dashboard account_admin, el que puede actuar sobre él con POST /v1/users/{id}/mfa/remove; para un member, una clave dd_, o cuando no se puede determinar el rol de quien llama, el campo está AUSENTE (no es false). Dondequiera que se renderice un User rige la misma regla: GET /v1/users, GET /v1/me, el usuario devuelto por DELETE /v1/users/{id} y POST /v1/users/{id}/enable, y el usuario en las respuestas de sesión (POST /v1/auth/login, POST /v1/auth/sso/exchange y las dos rutas de finalización de MFA); en ellas, para el account_admin que acaba de iniciar sesión. |
user.created_at | string (date-time) | no | |
user.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 — UserManagementForbidden
Se rechazó una escritura de gestión de usuarios (core#2334, adenda del ADR #46). code admin_target_forbidden: un inicio de sesión member intentó deshabilitar o volver a habilitar a un account_admin — siempre, sea cual sea la configuración del tenant. code role_forbidden: el tenant tiene un account_admin activo y quien llama es un inicio de sesión member o (core#2449) una clave dd_ (la ruta requiere un inicio de sesión account_admin; el interruptor del founder api_key_manages_people, desactivado por defecto, restablece la clave); el interruptor por tenant user_management_admin_only (activado por defecto) desactiva este, y a un tenant sin account_admin activo no se le pide uno. code forbidden: el tenant está suspendido o el token es un token de widget.
json
{
"error": {
"code": "role_forbidden",
"message": "managing users takes a dashboard login with the account_admin role"
}
}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"
}
}Levantar el freno de segundo factor de una persona
http
POST /v1/users/{id}/mfa/reset-failuresBorra el freno acumulativo del segundo factor (core#1572) para una persona del tenant: escribe un evento failures_reset firmado por el administrador que llama, y los códigos rechazados anteriores dejan de contar. No se elimina nada del registro de auditoría. Solo inicio de sesión de account_admin en el dashboard (véase 403).
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
204
Se reinició el contador de fallos.
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"
}
}Quitar el segundo factor de una persona (autenticador y códigos de recuperación perdidos)
http
POST /v1/users/{id}/mfa/removeLa vía de recuperación para una persona que perdió TANTO el autenticador como los códigos de recuperación (core#1580): un account_admin del MISMO tenant quita el segundo factor activo de esa persona. En UNA sola transacción — si algún paso falla el factor queda intacto: el factor y sus códigos de recuperación sin usar dejan de ser válidos, se revocan TODAS las sesiones ddu_ vivas de la persona, y un evento factor_removed_by_admin (autor = el administrador que llama, objetivo = la persona, el reason escrito) se anexa al registro de auditoría del segundo factor. No se elimina nada.
No abre ninguna puerta sin un segundo factor: cuando el tenant lo exige (mfa_required_enforced) el siguiente inicio de sesión de la persona cae en el alta forzada; en caso contrario la cuenta simplemente no tiene segundo factor hasta que se dé de alta de nuevo.
Solo inicio de sesión de account_admin en el dashboard (véase 403): nunca la propia persona (no tiene factor que demostrar) y nunca una clave dd_. Un administrador no puede usarlo sobre SÍ MISMO (409): su propia vía es POST /v1/me/mfa/disable, que reautentica. Una persona deshabilitada da 404 — vuelve a habilitarla primero.
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 |
|---|---|---|---|
reason | string | sí | Por qué se quita el factor — texto libre, conservado en el registro de auditoría. Los espacios iniciales y finales se recortan antes de contar. |
json
{
"reason": "Lost phone and printed codes; identity confirmed on a video call."
}Respuestas
204
El factor se quitó, las sesiones de la persona se revocaron y el evento se escribió.
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
Nada que quitar o no es esta ruta: la persona no tiene un segundo factor ACTIVO, o quien llama es esa misma persona (usa POST /v1/me/mfa/disable).
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"
}
}