Skip to content

Academia ​

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

English version

Traducción en curso

Esta referencia se genera desde la especificación OpenAPI. Las cadenas que todavía no tienen traducción aparecen en inglés.

Registros de formación de la Academia dentro de la app: la constancia auditable (quién completó qué y cuándo), de solo anexar y por agente.

Endpoints ​

MétodoRutaResumen
POST/v1/academy/completionsRegistrar UN hito de la Academia para un agente
GET/v1/academy/progressEl estado DERIVADO de la Academia de un agente
GET/v1/academy/transcriptEl registro de formación auditable: quién completó qué y cuándo

Registrar UN hito de la Academia para un agente ​

http
POST /v1/academy/completions

Anexa un evento de finalización (una lección terminada, una insignia obtenida) al flujo de formación de solo anexar del tenant. La fila es el registro que audita un cliente, así que nada aquí se puede reescribir después: la tabla no tiene permiso de UPDATE ni de DELETE y un trigger rechaza ambos.

Idempotente. Completar el mismo elemento dos veces no es un segundo evento: se devuelve el PRIMER registro sin cambios, de modo que occurred_at sigue indicando cuándo llegó realmente el agente.

occurred_at NO es una entrada: lo sella el servidor. Un registro de formación cuyo instante lo elige el navegador de la persona auditada no es evidencia.

Quién puede nombrar a quién (ADR #134). Un token de agente ddw_ escribe SOLO su PROPIO registro (agent_id se toma del token; nombrar a otro agente es 403). Una clave de máquina dd_ DEBE nombrar al agente: en el carril del tenant no existe un "yo", y asumir uno por defecto atribuiría la formación a quien hubiera llamado (400). Una sesión de inicio de sesión ddu_ vinculada a un asiento de agente escribe como ESE asiento (agent_id opcional o el suyo; otro agente es 403 forbidden); un ddu_ SIN asiento vinculado DEBE nombrar al agente (400) y solo puede nombrar a otro con users.role = account_admin; un member es 403 role_forbidden, una vez que la clave de catálogo del tenant ddu_author_role_enforced está activada (nace apagada: hasta entonces mantiene el contrato de dd_).

item_id se comprueba por formato, no se enumera: la fuente de verdad del currículo es el dashboard, así que una lección nueva no debe necesitar una migración de core. Minúsculas alfanuméricas más ._-, hasta 64 caracteres.

Cuerpo de la petición (JSON, obligatorio)

CampoTipoObligatorioDescripción
agent_idstring (uuid)noObligatorio para una clave dd_ y para una sesión ddu_ sin asiento; para un token ddw_ y para una sesión ddu_ vinculada a un asiento, solo puede ser su propio agente (y puede omitirse).
kindlesson · badgesí
item_idstringsíId del elemento del currículo, p. ej. ch1.dashboard.
json
{
  "agent_id": "8ac7f2f9-1f2c-4f7a-9d3b-1f0a6c5d4e3b",
  "kind": "lesson",
  "item_id": "ch1.dashboard"
}

Respuestas

201 ​

El hito tal como se registró (el PRIMER registro, si ya existía).

CampoTipoObligatorioDescripción
idstring (uuid)sí
agent_idstring (uuid)sí
kindlesson · badgesí
item_idstringsí
occurred_atstring (date-time)síSellado por el servidor, nunca por quien llama.

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

El estado DERIVADO de la Academia de un agente ​

http
GET /v1/academy/progress

Pliega el flujo de finalizaciones del agente en el estado a partir del cual renderiza la Academia. El capítulo y el nivel NO se calculan aquí deliberadamente: qué lección pertenece a qué capítulo es el currículo del cliente, y duplicarlo del lado del servidor haría que cada capítulo nuevo fuera un despliegue de core.

Un token ddw_ lee su PROPIO progreso (agent_id opcional, y solo se acepta el suyo); lo mismo una sesión de inicio de sesión ddu_ vinculada a un asiento de agente (otro agente es 403 forbidden). Una clave dd_ DEBE pasar agent_id; lo mismo un ddu_ SIN asiento vinculado, y solo puede leer el de otro agente con users.role = account_admin; un member es 403 role_forbidden, una vez que la clave de catálogo del tenant ddu_author_role_enforced está activada (nace apagada: hasta entonces mantiene el contrato de dd_; ADR #134). Un agente de otro tenant se lee como un documento VACÍO: RLS devuelve cero filas, el handler no compara ids.

Parámetros

NombreEnTipoObligatorioDescripción
agent_idquerystring (uuid)no

Respuestas

200 ​

El documento de progreso derivado.

CampoTipoObligatorioDescripción
agent_idstring (uuid)sí
lessons_donearreglo de stringsíIds de lecciones en orden de finalización.
badgesobjectsíId de insignia -> el instante en que se obtuvo.
updated_atstring,null (date-time)síEl hito más reciente, o null cuando el agente aún no tiene ninguno.

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

El registro de formación auditable: quién completó qué y cuándo ​

http
GET /v1/academy/transcript

La constancia en sí: todos los hitos de todos los agentes del tenant, con el nombre, el email y el rol del agente, en una ventana. Este es el entregable de negocio de MT-CLI-20: el informe que pide un cliente que audita la formación de sus gestores de cobranza.

La ventana es semiabierta: from inclusive, to EXCLUSIVO, como los informes de facturación, de modo que un hito en un corte de periodo pertenece exactamente a un lado. from es por defecto la época y no una ventana reciente: la pregunta de un auditor es "todo lo que este gestor ha completado alguna vez", y el flujo está acotado por construcción (una fila por agente y elemento, nunca más).

Solo ámbito de tenant: esta es la exportación de todo el tenant, pedida por quien audita, no por el auditado. Un token de agente ddw_ se deniega antes del handler (403).

?format=csv (o Accept: text/csv) devuelve el artefacto con su propio X-Artifact-SHA256, de modo que un auditor que lo archive pueda demostrar después que es el que se le entregó.

Parámetros

NombreEnTipoObligatorioDescripción
fromquerystring (date-time)noLímite inferior RFC 3339 (campo específico del endpoint; por defecto los últimos 30 días UTC donde se indica).
toquerystring (date-time)noLímite superior RFC 3339.
agent_idquerystring (uuid)no
formatquerycsvnocsv para el artefacto descargable (equivalente: Accept: text/csv).

Respuestas

200 ​

La transcripción (JSON) o el artefacto CSV.

CampoTipoObligatorioDescripción
fromstring (date-time)sí
tostring (date-time)sí
agent_idstring,null (uuid)síEl agente por el que se filtró el informe, o null para todo el tenant.
totalintegersí
rowsarreglo de AcademyTranscriptRowsí
rows[].agent_idstring (uuid)sí
rows[].agent_namestringsí
rows[].agent_emailstringsí
rows[].agent_roleagent · supervisor · adminsíEl rol del agente HOY (una unión, no una instantánea): quien cambió de rol no ha dejado de haber completado su formación.
rows[].kindlesson · badgesí
rows[].item_idstringsí
rows[].occurred_atstring (date-time)sí

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

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