Skip to content

Gestión de calidad (QM) ​

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.

Formularios de puntuación de gestión de calidad (ADR #217), versionados de sólo anexado por tenant. Las escrituras requieren el indicador qm_enabled.

Endpoints ​

MétodoRutaResumen
GET/v1/me/evaluationsLas evaluaciones de QM PROPIAS de quien llama, de la más reciente a la más antigua
GET/v1/me/evaluations/{id}Una de las evaluaciones de QM PROPIAS de quien llama, con sus criterios y su hilo de disputa
POST/v1/me/evaluations/{id}/disputeAbrir la disputa de una de las evaluaciones de QM PROPIAS de quien llama
GET/v1/qm/formsLos formularios de puntuación de QM del tenant, cada uno con su versión vigente
POST/v1/qm/formsCrear un formulario de QM (versión 1)
GET/v1/qm/forms/{id}Un formulario de QM, en su versión vigente
PATCH/v1/qm/forms/{id}Editar un formulario de QM para crear una versión NUEVA
DELETE/v1/qm/forms/{id}Archivar un formulario de QM
GET/v1/qm/forms/{id}/versionsTodas las versiones de un formulario de QM, de la más antigua a la más reciente
GET/v1/qm/forms/{id}/versions/{version}Una versión de un formulario de QM
GET/v1/recordings/{id}/evaluationsLas evaluaciones de QM de una grabación, de la más reciente a la más antigua
POST/v1/recordings/{id}/evaluationsEvaluar una grabación con una versión de formulario de QM
GET/v1/recordings/{id}/evaluations/{evaluation_id}Una evaluación de QM de una grabación
POST/v1/qm/evaluations/{id}/dispute/resolutionResolver la disputa del agente sobre una evaluación
GET/v1/qm/reports/agentsCifras de QM por agente y formulario en una ventana
GET/v1/qm/reports/campaignsCifras de QM por campaña y formulario en una ventana

Las evaluaciones de QM PROPIAS de quien llama, de la más reciente a la más antigua ​

http
GET /v1/me/evaluations

Las evaluaciones del puesto que identifica el BEARER, correcciones incluidas, con tope de 200. Ningún parámetro puede nombrar a un agente: agent_id, seat_id, user_id y sip_extension se rechazan por su nombre con 400, nunca se ignoran, de modo que un cliente nunca pueda creer que leyó las evaluaciones de un compañero. La comprobación va DESPUÉS del 403, así que quien llama sin puesto no averigua qué parámetros se leen.

Quién obtiene un puesto: un login de panel ddu_ vinculado a un puesto activo (403 seat_not_linked en caso contrario). Una clave de máquina dd_ no tiene ninguna persona detrás y recibe 403. Un token de widget ddw_ recibe 403 antes del handler: esta ruta no está en la lista de permitidos del widget.

Cada fila lleva las respuestas a los criterios, la puntuación, la versión del formulario, el comment escrito para el agente, si es la current, el estado de la disputa (dispute, nulo cuando no hay ninguna) y dispute_until, el fin de la ventana qm_dispute_window_days mientras la disputa aún puede abrirse (nulo en otro caso: evaluación sustituida, disputa ya abierta o resuelta, fruto de una disputa resuelta, ventana cerrada). La fila NO dice quién evaluó y nunca lleva el id propio del agente. Las lecturas funcionan con qm_enabled activado o no.

Respuestas

200 ​

Las evaluaciones del llamante.

CampoTipoObligatorioDescripción
evaluationsarreglo de QmAgentEvaluationsí
evaluations[].idstring (uuid)sí
evaluations[].recording_idstring (uuid)sí
evaluations[].call_attempt_idstring (uuid)sí
evaluations[].campaign_idstring,null (uuid)no
evaluations[].form_idstring (uuid)sí
evaluations[].form_versionintegersí
evaluations[].answersobjectsí
evaluations[].score_bpintegersíPuntos básicos: 8750 es 87,5 %.
evaluations[].auto_failedbooleansíUn criterio crítico se respondió que no; la puntuación es 0.
evaluations[].passedbooleansí
evaluations[].commentstring,nullsíEl texto libre del evaluador; el agente evaluado puede leerlo.
evaluations[].supersedes_idstring,null (uuid)no
evaluations[].currentbooleansíNinguna otra evaluación reemplaza a esta.
evaluations[].disputeQmAgentDispute | nullsí
evaluations[].dispute_untilstring,null (date-time)síEl fin de la ventana de disputa mientras la disputa aún puede abrirse; null en otro caso.
evaluations[].created_atstring (date-time)sí

400 ​

Un parámetro que nombra a un agente (agent_id, seat_id, user_id, sip_extension), rechazado por su nombre.

json
{
  "error": {
    "code": "bad_request",
    "message": "agent_id not accepted here: these evaluations are always the caller's own, derived from the token"
  }
}

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

Una de las evaluaciones de QM PROPIAS de quien llama, con sus criterios y su hilo de disputa ​

http
GET /v1/me/evaluations/{id}

Mismo contrato de identidad que GET /v1/me/evaluations: el puesto sale del token y los parámetros que nombran a un agente son 400. Añade los criteria y el pass_threshold de la versión del formulario con la que se puntuó la evaluación, y el hilo dispute_events (kind, reason, note, hora; sin ids de actor). Una evaluación de otro agente, de otro tenant o que no existe da el mismo 404.

Parámetros

NombreEnTipoObligatorioDescripción
idpathstring (uuid)síUUID del recurso. Los ids mal formados o de otro tenant se leen como 404.

Respuestas

200 ​

La evaluación.

CampoTipoObligatorioDescripción
evaluationanysíUna QmAgentEvaluation más los criterios con los que se puntuó y su hilo de disputa.

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

Abrir la disputa de una de las evaluaciones de QM PROPIAS de quien llama ​

http
POST /v1/me/evaluations/{id}/dispute

El agente evaluado impugna la evaluación: UNA sola disputa por evaluación, abierta dentro de la ventana qm_dispute_window_days (de 1 a 90 días, 7 por defecto) contada desde que se escribió la evaluación. Sólo el login ddu_ del agente al que se refiere la evaluación puede abrirla, con un puesto ACTIVO. Una clave dd_ es un servicio, no una persona: 403 role_forbidden. Un token de widget ddw_ recibe 403 antes del handler: esta ruta no está en la lista permitida del widget.

Las comprobaciones se ejecutan en este orden y la primera que falla no escribe nada: alcance del tenant, qm_enabled (403 qm_not_enabled: las lecturas siguen con el indicador apagado, las escrituras no), la persona (403 role_forbidden), 404 si el id no es un UUID, 400 (el cuerpo: reason es uno de wrong_call, criterion_misjudged, other, note es texto opcional, los campos desconocidos se rechazan), 404 (la evaluación no es del propio llamante, pertenece a otro tenant o no existe: una sola respuesta para los tres casos), y después 409 cuando la evaluación fue reemplazada por una más nueva (disputa la vigente), ya tiene su disputa o es ella misma el resultado de una disputa resuelta (una disputa resuelta no se reabre), o la ventana se ha cerrado.

Responde con la evaluación tal como la muestra GET /v1/me/evaluations/{id}, ahora con su dispute y el evento opened en dispute_events. Mientras la disputa está abierta la evaluación sigue contando: nada la oculta ni la excluye.

Parámetros

NombreEnTipoObligatorioDescripción
idpathstring (uuid)síUUID del recurso. Los ids mal formados o de otro tenant se leen como 404.

Cuerpo de la petición (JSON, obligatorio)

CampoTipoObligatorioDescripción
reasonwrong_call · criterion_misjudged · othersí
notestringnoTexto libre opcional; en blanco se lee como ausente.
json
{
  "reason": "criterion_misjudged",
  "note": "Dije el aviso de grabacion en el minuto 1:10 y el criterio lo marca como omitido."
}

Respuestas

201 ​

La evaluación con su disputa abierta.

CampoTipoObligatorioDescripción
evaluationanysíUna QmAgentEvaluation más los criterios con los que se puntuó y su hilo de disputa.

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 ​

code qm_not_enabled: el indicador qm_enabled del tenant está apagado. coderole_forbidden: el llamante es una clave dd_ o un login sin puesto de agente activo. code forbidden: el tenant está suspendido o el token es un token de widget.

json
{
  "error": {
    "code": "qm_not_enabled",
    "message": "QM is not enabled for this tenant"
  }
}

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

Los formularios de puntuación de QM del tenant, cada uno con su versión vigente ​

http
GET /v1/qm/forms

Por nombre, los vigentes; ?include_archived=true añade los archivados. Cada formulario viene con su versión VIGENTE. Tope de 1 000. Las lecturas funcionan con qm_enabled activado o no.

Parámetros

NombreEnTipoObligatorioDescripción
include_archivedquerybooleanno

Respuestas

200 ​

Los formularios.

CampoTipoObligatorioDescripción
formsarreglo de QmFormsí
forms[].idstring (uuid)sí
forms[].tenant_idstring (uuid)no
forms[].namestringsí
forms[].archivedbooleansí
forms[].versionintegersíLa versión vigente.
forms[].criteriaarreglo de QmCriterionsíLista ORDENADA de criterios de puntuación. key es única dentro del formulario; la puntuación de una evaluación se calcula a partir de ellos, en puntos básicos.
forms[].criteria[].keystringsí
forms[].criteria[].labelstringsíSin espacios en los extremos, no en blanco.
forms[].criteria[].kindyes_no · scalesí
forms[].criteria[].weightintegersí
forms[].criteria[].maxintegernoObligatorio para scale, rechazado para yes_no.
forms[].criteria[].criticalbooleannoSólo yes_no: un criterio crítico fallido hace fallar toda la evaluación.
forms[].criteria[].na_allowedbooleannoEl evaluador puede marcar el criterio como no aplicable.
forms[].pass_thresholdintegersí
forms[].version_created_atstring (date-time)no
forms[].created_atstring (date-time)no
forms[].updated_atstring (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"
  }
}

Crear un formulario de QM (versión 1) ​

http
POST /v1/qm/forms

Un formulario es una lista ORDENADA de criterios más el umbral de aprobación (de 0 a 100). name va sin espacios en los extremos, no en blanco, con un máximo de 200 caracteres y único entre los formularios VIGENTES del tenant (409). Un tenant tiene como máximo 200 formularios vigentes (422). El cuerpo se comprueba en su conjunto: el primer criterio que no encaja se nombra por su posición en el mensaje 400. Los campos desconocidos se rechazan.

Las escrituras requieren el indicador qm_enabled (403 qm_not_enabled mientras esté apagado) y una PERSONA: un login del dashboard con el rol account_admin. Una clave de API dd_, un login member o un token de widget recibe 403 role_forbidden.

Cuerpo de la petición (JSON, obligatorio)

CampoTipoObligatorioDescripción
namestringsí
criteriaarreglo de QmCriterionsíLista ORDENADA de criterios de puntuación. key es única dentro del formulario; la puntuación de una evaluación se calcula a partir de ellos, en puntos básicos.
criteria[].keystringsí
criteria[].labelstringsíSin espacios en los extremos, no en blanco.
criteria[].kindyes_no · scalesí
criteria[].weightintegersí
criteria[].maxintegernoObligatorio para scale, rechazado para yes_no.
criteria[].criticalbooleannoSólo yes_no: un criterio crítico fallido hace fallar toda la evaluación.
criteria[].na_allowedbooleannoEl evaluador puede marcar el criterio como no aplicable.
pass_thresholdintegersí
json
{
  "name": "Cobranza — llamada saliente",
  "pass_threshold": 80,
  "criteria": [
    {
      "key": "identificacion",
      "label": "Identifica a la empresa y al agente",
      "kind": "yes_no",
      "weight": 2
    },
    {
      "key": "mini_miranda",
      "label": "Lee el aviso legal completo",
      "kind": "yes_no",
      "weight": 5,
      "critical": true
    },
    {
      "key": "empatia",
      "label": "Empatía con el deudor",
      "kind": "scale",
      "max": 5,
      "weight": 3,
      "na_allowed": true
    }
  ]
}

Respuestas

201 ​

El formulario, en la versión 1.

CampoTipoObligatorioDescripción
formobject (QmForm)síUn formulario: su cabecera y su versión VIGENTE.
form.idstring (uuid)sí
form.tenant_idstring (uuid)no
form.namestringsí
form.archivedbooleansí
form.versionintegersíLa versión vigente.
form.criteriaarreglo de QmCriterionsíLista ORDENADA de criterios de puntuación. key es única dentro del formulario; la puntuación de una evaluación se calcula a partir de ellos, en puntos básicos.
form.criteria[].keystringsí
form.criteria[].labelstringsíSin espacios en los extremos, no en blanco.
form.criteria[].kindyes_no · scalesí
form.criteria[].weightintegersí
form.criteria[].maxintegernoObligatorio para scale, rechazado para yes_no.
form.criteria[].criticalbooleannoSólo yes_no: un criterio crítico fallido hace fallar toda la evaluación.
form.criteria[].na_allowedbooleannoEl evaluador puede marcar el criterio como no aplicable.
form.pass_thresholdintegersí
form.version_created_atstring (date-time)no
form.created_atstring (date-time)no
form.updated_atstring (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 — QmWriteForbidden ​

Se rechazó una escritura de gestión de calidad (QM). code qm_not_enabled: el indicador qm_enabled del tenant está apagado (viene apagado por defecto; un indicador que no se puede leer cuenta como apagado). code role_forbidden: el llamante no es un login del dashboard con el rol account_admin (una clave dd_, un member). code forbidden: el tenant está suspendido o el token es un token de widget.

json
{
  "error": {
    "code": "qm_not_enabled",
    "message": "QM is not enabled for this tenant"
  }
}

409 — Conflict ​

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

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

422 — 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)"
  }
}

Un formulario de QM, en su versión vigente ​

http
GET /v1/qm/forms/{id}

Parámetros

NombreEnTipoObligatorioDescripción
idpathstring (uuid)síUUID del recurso. Los ids mal formados o de otro tenant se leen como 404.

Respuestas

200 ​

El formulario (también los archivados, marcados con archived).

CampoTipoObligatorioDescripción
formobject (QmForm)síUn formulario: su cabecera y su versión VIGENTE.
form.idstring (uuid)sí
form.tenant_idstring (uuid)no
form.namestringsí
form.archivedbooleansí
form.versionintegersíLa versión vigente.
form.criteriaarreglo de QmCriterionsíLista ORDENADA de criterios de puntuación. key es única dentro del formulario; la puntuación de una evaluación se calcula a partir de ellos, en puntos básicos.
form.criteria[].keystringsí
form.criteria[].labelstringsíSin espacios en los extremos, no en blanco.
form.criteria[].kindyes_no · scalesí
form.criteria[].weightintegersí
form.criteria[].maxintegernoObligatorio para scale, rechazado para yes_no.
form.criteria[].criticalbooleannoSólo yes_no: un criterio crítico fallido hace fallar toda la evaluación.
form.criteria[].na_allowedbooleannoEl evaluador puede marcar el criterio como no aplicable.
form.pass_thresholdintegersí
form.version_created_atstring (date-time)no
form.created_atstring (date-time)no
form.updated_atstring (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"
  }
}

Editar un formulario de QM para crear una versión NUEVA ​

http
PATCH /v1/qm/forms/{id}

Envía al menos uno de criteria, pass_threshold; el que se omita se hereda de la versión vigente. Esto añade la versión n+1 y deja la versión n exactamente como estaba: una evaluación puede haberla citado. Una edición que no cambia nada no escribe ninguna versión y devuelve la vigente. base_version es opcional y, si se envía, debe ser la versión vigente; si no, 409 y no se escribe nada, de modo que dos personas que editan el mismo formulario no se sobrescriben sin enterarse. Un formulario archivado no se puede editar (409); un formulario tiene como máximo 1 000 versiones (422). Requiere qm_enabled y un login account_admin.

Parámetros

NombreEnTipoObligatorioDescripción
idpathstring (uuid)síUUID del recurso. Los ids mal formados o de otro tenant se leen como 404.

Cuerpo de la petición (JSON, obligatorio)

CampoTipoObligatorioDescripción
criteriaarreglo de QmCriterionnoLista ORDENADA de criterios de puntuación. key es única dentro del formulario; la puntuación de una evaluación se calcula a partir de ellos, en puntos básicos.
criteria[].keystringsí
criteria[].labelstringsíSin espacios en los extremos, no en blanco.
criteria[].kindyes_no · scalesí
criteria[].weightintegersí
criteria[].maxintegernoObligatorio para scale, rechazado para yes_no.
criteria[].criticalbooleannoSólo yes_no: un criterio crítico fallido hace fallar toda la evaluación.
criteria[].na_allowedbooleannoEl evaluador puede marcar el criterio como no aplicable.
pass_thresholdintegerno
base_versionintegerno
json
{
  "base_version": 1,
  "pass_threshold": 85
}

Respuestas

200 ​

El formulario, en su versión vigente tras la edición.

CampoTipoObligatorioDescripción
formobject (QmForm)síUn formulario: su cabecera y su versión VIGENTE.
form.idstring (uuid)sí
form.tenant_idstring (uuid)no
form.namestringsí
form.archivedbooleansí
form.versionintegersíLa versión vigente.
form.criteriaarreglo de QmCriterionsíLista ORDENADA de criterios de puntuación. key es única dentro del formulario; la puntuación de una evaluación se calcula a partir de ellos, en puntos básicos.
form.criteria[].keystringsí
form.criteria[].labelstringsíSin espacios en los extremos, no en blanco.
form.criteria[].kindyes_no · scalesí
form.criteria[].weightintegersí
form.criteria[].maxintegernoObligatorio para scale, rechazado para yes_no.
form.criteria[].criticalbooleannoSólo yes_no: un criterio crítico fallido hace fallar toda la evaluación.
form.criteria[].na_allowedbooleannoEl evaluador puede marcar el criterio como no aplicable.
form.pass_thresholdintegersí
form.version_created_atstring (date-time)no
form.created_atstring (date-time)no
form.updated_atstring (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 — QmWriteForbidden ​

Se rechazó una escritura de gestión de calidad (QM). code qm_not_enabled: el indicador qm_enabled del tenant está apagado (viene apagado por defecto; un indicador que no se puede leer cuenta como apagado). code role_forbidden: el llamante no es un login del dashboard con el rol account_admin (una clave dd_, un member). code forbidden: el tenant está suspendido o el token es un token de widget.

json
{
  "error": {
    "code": "qm_not_enabled",
    "message": "QM is not enabled for this tenant"
  }
}

404 — NotFound ​

Id desconocido, mal formado (no UUID) O id de otro tenant: RLS devuelve cero filas, así que los tres son indistinguibles por diseño (sin fuga de existencia, nunca un 403 para ids ajenos).

json
{
  "error": {
    "code": "not_found",
    "message": "resource not found for this tenant"
  }
}

409 — Conflict ​

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

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

422 — 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)"
  }
}

Archivar un formulario de QM ​

http
DELETE /v1/qm/forms/{id}

Los formularios nunca se borran: una evaluación puede haber citado una de sus versiones. Archivar libera el nombre para un formulario nuevo y saca el formulario de la lista por defecto; ya no se puede editar. Idempotente. Requiere qm_enabled y un login account_admin, como las demás escrituras.

Parámetros

NombreEnTipoObligatorioDescripción
idpathstring (uuid)síUUID del recurso. Los ids mal formados o de otro tenant se leen como 404.

Respuestas

204 ​

El formulario está archivado.

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

Se rechazó una escritura de gestión de calidad (QM). code qm_not_enabled: el indicador qm_enabled del tenant está apagado (viene apagado por defecto; un indicador que no se puede leer cuenta como apagado). code role_forbidden: el llamante no es un login del dashboard con el rol account_admin (una clave dd_, un member). code forbidden: el tenant está suspendido o el token es un token de widget.

json
{
  "error": {
    "code": "qm_not_enabled",
    "message": "QM is not enabled for this tenant"
  }
}

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

Todas las versiones de un formulario de QM, de la más antigua a la más reciente ​

http
GET /v1/qm/forms/{id}/versions

Parámetros

NombreEnTipoObligatorioDescripción
idpathstring (uuid)síUUID del recurso. Los ids mal formados o de otro tenant se leen como 404.

Respuestas

200 ​

Las versiones (con tope de 1 000).

CampoTipoObligatorioDescripción
versionsarreglo de QmFormVersionsí
versions[].form_idstring (uuid)sí
versions[].versionintegersí
versions[].criteriaarreglo de QmCriterionsíLista ORDENADA de criterios de puntuación. key es única dentro del formulario; la puntuación de una evaluación se calcula a partir de ellos, en puntos básicos.
versions[].criteria[].keystringsí
versions[].criteria[].labelstringsíSin espacios en los extremos, no en blanco.
versions[].criteria[].kindyes_no · scalesí
versions[].criteria[].weightintegersí
versions[].criteria[].maxintegernoObligatorio para scale, rechazado para yes_no.
versions[].criteria[].criticalbooleannoSólo yes_no: un criterio crítico fallido hace fallar toda la evaluación.
versions[].criteria[].na_allowedbooleannoEl evaluador puede marcar el criterio como no aplicable.
versions[].pass_thresholdintegersí
versions[].created_atstring (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"
  }
}

Una versión de un formulario de QM ​

http
GET /v1/qm/forms/{id}/versions/{version}

Parámetros

NombreEnTipoObligatorioDescripción
idpathstring (uuid)síUUID del recurso. Los ids mal formados o de otro tenant se leen como 404.
versionpathintegersíEl número de versión (>= 1). Una desconocida, mal formada o de otro tenant se lee como 404.

Respuestas

200 ​

La versión, exactamente como se escribió.

CampoTipoObligatorioDescripción
versionobject (QmFormVersion)síUna versión inmutable de un formulario.
version.form_idstring (uuid)sí
version.versionintegersí
version.criteriaarreglo de QmCriterionsíLista ORDENADA de criterios de puntuación. key es única dentro del formulario; la puntuación de una evaluación se calcula a partir de ellos, en puntos básicos.
version.criteria[].keystringsí
version.criteria[].labelstringsíSin espacios en los extremos, no en blanco.
version.criteria[].kindyes_no · scalesí
version.criteria[].weightintegersí
version.criteria[].maxintegernoObligatorio para scale, rechazado para yes_no.
version.criteria[].criticalbooleannoSólo yes_no: un criterio crítico fallido hace fallar toda la evaluación.
version.criteria[].na_allowedbooleannoEl evaluador puede marcar el criterio como no aplicable.
version.pass_thresholdintegersí
version.created_atstring (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"
  }
}

Las evaluaciones de QM de una grabación, de la más reciente a la más antigua ​

http
GET /v1/recordings/{id}/evaluations

Todas las evaluaciones escritas para la grabación, correcciones incluidas: cada fila indica si es la current (ninguna otra fila la reemplaza) y a qué fila reemplaza con supersedes_id. Tope de 200. Las lecturas funcionan con qm_enabled activado o no. Un login del dashboard que no puede evaluar (un puesto de agente, un member) recibe 403 role_forbidden: las filas indican quién evaluó. Una clave dd_ lee. El comment sólo está presente para un evaluador elegible (un puesto de supervisor o admin, o un login account_admin sin puesto); para cualquier otro la clave está ausente.

Parámetros

NombreEnTipoObligatorioDescripción
idpathstring (uuid)síUUID del recurso. Los ids mal formados o de otro tenant se leen como 404.

Respuestas

200 ​

Las evaluaciones.

CampoTipoObligatorioDescripción
evaluationsarreglo de QmEvaluationsí
evaluations[].idstring (uuid)sí
evaluations[].recording_idstring (uuid)sí
evaluations[].call_attempt_idstring (uuid)sí
evaluations[].agent_idstring (uuid)sí
evaluations[].campaign_idstring,null (uuid)no
evaluations[].form_idstring (uuid)sí
evaluations[].form_versionintegersí
evaluations[].evaluator_user_idstring,null (uuid)síEl usuario firmante; null cuando evaluator_kind es automatic.
evaluations[].evaluator_kindhuman · automaticsí
evaluations[].answersobjectsí
evaluations[].score_bpintegersíPuntos básicos: 8750 es 87,5 %.
evaluations[].auto_failedbooleansíUn criterio crítico se respondió que no; la puntuación es 0.
evaluations[].passedbooleansí
evaluations[].supersedes_idstring,null (uuid)no
evaluations[].currentbooleansíNinguna otra evaluación reemplaza a esta.
evaluations[].commentstring,nullnoPresente sólo para un evaluador elegible.
evaluations[].created_atstring (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"
  }
}

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

Evaluar una grabación con una versión de formulario de QM ​

http
POST /v1/recordings/{id}/evaluations

Un supervisor puntúa UNA grabación available contra una versión de un formulario vigente y la fila queda congelada: nunca se edita. Para corregirla, envía el mismo cuerpo con supersedes_id apuntando a la evaluación VIGENTE de esa grabación y formulario; eso añade una fila nueva y deja la anterior como estaba. Sin supersedes_id una grabación admite una evaluación por formulario (409 en cuanto hay una).

La puntuación se calcula aquí, en puntos básicos (8750 es 87,5 %), a partir de la versión que citas y de tus answers: yes_no admite true o false, scale un entero de 0 a max, y "na" donde el criterio lo permite. Se exige una respuesta para cada criterio. agent_id, call_attempt_id y campaign_id salen de la grabación, nunca del cuerpo. Los campos desconocidos se rechazan.

Las comprobaciones se ejecutan en este orden y la primera que falla no escribe nada: qm_enabled (403 qm_not_enabled), la persona (403 role_forbidden), 400 (forma del cuerpo), 404 (grabación), 403 self_evaluation_forbidden (la grabación es del propio evaluador), 409 (grabación no available), 422 (sin agente, pierna de IA, formulario o versión desconocidos, respuestas que no encajan), 409 (formulario archivado, o la cadena). Una clave de API dd_ es un servicio, no una persona: 403 role_forbidden.

Se rechaza una corrección mientras la evaluación que corrige tenga una disputa ABIERTA (el agente la abrió y nadie la resolvió): 409 con error.codeevaluation_under_dispute, no se escribe nada, y la evaluación sigue contando en los informes de gestión de calidad (QM) con su disputa abierta. Esa evaluación sólo se corrige resolviendo la disputa como adjusted. Una vez que la disputa se resuelve como upheld, se vuelve a aceptar una corrección.

Parámetros

NombreEnTipoObligatorioDescripción
idpathstring (uuid)síUUID del recurso. Los ids mal formados o de otro tenant se leen como 404.

Cuerpo de la petición (JSON, obligatorio)

CampoTipoObligatorioDescripción
form_idstring (uuid)síUn formulario vigente del tenant.
form_versionintegersíLa versión contra la que se puntúan las respuestas.
answersobjectsícriterion key -> answer. true/false para yes_no, un entero de 0 a max para scale, la cadena na donde na_allowed. Una entrada por criterio.
commentstringnoTexto libre opcional; en blanco se lee como ausente.
supersedes_idstring (uuid)noLa evaluación VIGENTE de esta grabación y formulario, para corregirla.
json
{
  "form_id": "5d3b0c8e-4f3a-4a0e-9d1c-0a5f9a9b7e11",
  "form_version": 1,
  "answers": {
    "identificacion": true,
    "mini_miranda": true,
    "empatia": 4
  },
  "comment": "Buena apertura; falto cerrar con el aviso de grabacion."
}

Respuestas

201 ​

La evaluación, con su puntuación y como la vigente.

CampoTipoObligatorioDescripción
evaluationobject (QmEvaluation)síUna evaluación de gestión de calidad (QM) congelada. Las correcciones son otras filas que apuntan aquí mediante supersedes_id. evaluator_kind es human (una persona la firmó, evaluator_user_id es ese usuario) o automatic (la pasada de IA posterior a la llamada sobre los criterios del formulario: nadie la firmó y evaluator_user_id es null). La puntuación la calcula core en ambos casos, nunca el modelo. Una evaluación humana de la misma grabación y formulario reemplaza a una automática mediante la misma cadena supersedes_id.
evaluation.idstring (uuid)sí
evaluation.recording_idstring (uuid)sí
evaluation.call_attempt_idstring (uuid)sí
evaluation.agent_idstring (uuid)sí
evaluation.campaign_idstring,null (uuid)no
evaluation.form_idstring (uuid)sí
evaluation.form_versionintegersí
evaluation.evaluator_user_idstring,null (uuid)síEl usuario firmante; null cuando evaluator_kind es automatic.
evaluation.evaluator_kindhuman · automaticsí
evaluation.answersobjectsí
evaluation.score_bpintegersíPuntos básicos: 8750 es 87,5 %.
evaluation.auto_failedbooleansíUn criterio crítico se respondió que no; la puntuación es 0.
evaluation.passedbooleansí
evaluation.supersedes_idstring,null (uuid)no
evaluation.currentbooleansíNinguna otra evaluación reemplaza a esta.
evaluation.commentstring,nullnoPresente sólo para un evaluador elegible.
evaluation.created_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 — QmEvaluateForbidden ​

Se rechazó evaluar una grabación. code qm_not_enabled: el indicador qm_enabled del tenant está apagado. code role_forbidden: el llamante no es un evaluador elegible (una clave dd_, un member, un puesto que no es de supervisor o admin, un puesto inactivo). code self_evaluation_forbidden: la grabación es del propio llamante. code forbidden: el tenant está suspendido o el token es un token de widget.

json
{
  "error": {
    "code": "role_forbidden",
    "message": "evaluating a recording takes a supervisor or admin seat, or an account_admin login"
  }
}

404 — NotFound ​

Id desconocido, mal formado (no UUID) O id de otro tenant: RLS devuelve cero filas, así que los tres son indistinguibles por diseño (sin fuga de existencia, nunca un 403 para ids ajenos).

json
{
  "error": {
    "code": "not_found",
    "message": "resource not found for this tenant"
  }
}

409 — Conflict ​

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

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

422 — 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)"
  }
}

Una evaluación de QM de una grabación ​

http
GET /v1/recordings/{id}/evaluations/{evaluation_id}

La fila exactamente como se escribió, más si sigue siendo la current. Un id que pertenece a otra grabación u otro tenant se lee como 404. El comment y el 403 para un login que no puede evaluar siguen la misma regla que en el listado.

Parámetros

NombreEnTipoObligatorioDescripción
idpathstring (uuid)síUUID del recurso. Los ids mal formados o de otro tenant se leen como 404.
evaluation_idpathstring (uuid)síEl UUID de la evaluación. Mal formado, desconocido o de otro tenant se lee como 404.

Respuestas

200 ​

La evaluación.

CampoTipoObligatorioDescripción
evaluationobject (QmEvaluation)síUna evaluación de gestión de calidad (QM) congelada. Las correcciones son otras filas que apuntan aquí mediante supersedes_id. evaluator_kind es human (una persona la firmó, evaluator_user_id es ese usuario) o automatic (la pasada de IA posterior a la llamada sobre los criterios del formulario: nadie la firmó y evaluator_user_id es null). La puntuación la calcula core en ambos casos, nunca el modelo. Una evaluación humana de la misma grabación y formulario reemplaza a una automática mediante la misma cadena supersedes_id.
evaluation.idstring (uuid)sí
evaluation.recording_idstring (uuid)sí
evaluation.call_attempt_idstring (uuid)sí
evaluation.agent_idstring (uuid)sí
evaluation.campaign_idstring,null (uuid)no
evaluation.form_idstring (uuid)sí
evaluation.form_versionintegersí
evaluation.evaluator_user_idstring,null (uuid)síEl usuario firmante; null cuando evaluator_kind es automatic.
evaluation.evaluator_kindhuman · automaticsí
evaluation.answersobjectsí
evaluation.score_bpintegersíPuntos básicos: 8750 es 87,5 %.
evaluation.auto_failedbooleansíUn criterio crítico se respondió que no; la puntuación es 0.
evaluation.passedbooleansí
evaluation.supersedes_idstring,null (uuid)no
evaluation.currentbooleansíNinguna otra evaluación reemplaza a esta.
evaluation.commentstring,nullnoPresente sólo para un evaluador elegible.
evaluation.created_atstring (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"
  }
}

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

Resolver la disputa del agente sobre una evaluación ​

http
POST /v1/qm/evaluations/{id}/dispute/resolution

Un evaluador elegible (un puesto de supervisor o admin, o un login account_admin sin puesto) cierra la disputa que abrió el agente evaluado. El {id} es la evaluación DISPUTADA. decision es upheld (la evaluación se mantiene) o adjusted (se reemplaza). El evaluador no puede ser el agente de la evaluación. Una clave dd_ es un servicio, no una persona: 403 role_forbidden.

adjusted admite answers (obligatorio, con la misma forma que al evaluar) y un comment opcional para la nueva evaluación, que repite el formulario y la versión de la disputada y se puntúa aquí a partir de tus respuestas. La nueva evaluación y el evento que la cita (adjusted_evaluation_id) se escriben en UNA sola transacción: o existen las dos filas o ninguna. upheld no admite ni answers ni comment. La nueva evaluación se lee con GET /v1/recordings/{id}/evaluations/{evaluation_id}.

Las comprobaciones se ejecutan en este orden y la primera que falla no escribe nada: qm_enabled (403 qm_not_enabled), la persona (403 role_forbidden), 404 (un id que no es un UUID), 400 (la forma del cuerpo), 404 (evaluación), 403 self_evaluation_forbidden, 409 (la evaluación no tiene disputa, o ya está resuelta), 422 (respuestas que no encajan con la versión del formulario), 409 (la evaluación ya no es la vigente).

Parámetros

NombreEnTipoObligatorioDescripción
idpathstring (uuid)síUUID del recurso. Los ids mal formados o de otro tenant se leen como 404.

Cuerpo de la petición (JSON, obligatorio)

CampoTipoObligatorioDescripción
decisionupheld · adjustedsí
notestringnoTexto libre opcional; en blanco se lee como ausente.
answersobjectnoUna respuesta por criterio de la versión del formulario de la evaluación disputada: un booleano para yes_no, un entero de 0 a max para scale, la cadena na donde el criterio lo permite.
commentstringnoTexto libre opcional de la nueva evaluación.
json
{
  "decision": "adjusted",
  "note": "Tiene razon: el aviso se dijo en el minuto 1:10.",
  "answers": {
    "identificacion": true,
    "mini_miranda": true,
    "empatia": 4
  }
}

Respuestas

201 ​

El evento que la resolución añadió al hilo de la disputa.

CampoTipoObligatorioDescripción
dispute_eventobject (QmDisputeResolution)síEl evento que una resolución añadió al hilo de la disputa.
dispute_event.idstring (uuid)sí
dispute_event.evaluation_idstring (uuid)síLa evaluación disputada.
dispute_event.kindupheld · adjustedsí
dispute_event.notestring,nullsí
dispute_event.adjusted_evaluation_idstring,null (uuid)síLa evaluación que reemplaza a la disputada; null cuando se mantiene (upheld).
dispute_event.created_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 — QmEvaluateForbidden ​

Se rechazó evaluar una grabación. code qm_not_enabled: el indicador qm_enabled del tenant está apagado. code role_forbidden: el llamante no es un evaluador elegible (una clave dd_, un member, un puesto que no es de supervisor o admin, un puesto inactivo). code self_evaluation_forbidden: la grabación es del propio llamante. code forbidden: el tenant está suspendido o el token es un token de widget.

json
{
  "error": {
    "code": "role_forbidden",
    "message": "evaluating a recording takes a supervisor or admin seat, or an account_admin login"
  }
}

404 — NotFound ​

Id desconocido, mal formado (no UUID) O id de otro tenant: RLS devuelve cero filas, así que los tres son indistinguibles por diseño (sin fuga de existencia, nunca un 403 para ids ajenos).

json
{
  "error": {
    "code": "not_found",
    "message": "resource not found for this tenant"
  }
}

409 — Conflict ​

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

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

422 — 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)"
  }
}

Cifras de QM por agente y formulario en una ventana ​

http
GET /v1/qm/reports/agents

Cifras derivadas en cada llamada a partir de las evaluaciones VIGENTES (una corrección reemplaza la fila que sustituye; la antigua deja de contar) cuya grabación empezó en [from, to). Una fila por agente, formulario Y evaluator_kind: dos formularios son dos escalas, y la puntuación de una persona y la pasada automática nunca se promedian juntas. Por fila: evaluations, avg_score_bp (puntuación media en puntos básicos, redondeada; null cuando no hay nada que promediar, nunca 0), pass_rate_bp (passed sobre evaluations en puntos básicos, null igualmente), passed y auto_failed (anuladas por un criterio crítico). Nunca se devuelve comentario, número de teléfono ni otro texto libre.

from y to son obligatorios, from debe ser anterior a to y la ventana no puede superar 31 días (400 en caso contrario). Sin agent_id sólo aparecen los agentes con datos; con uno existente que no tiene evaluaciones en la ventana la respuesta es UNA fila con evaluations: 0 y los promedios null; uno desconocido, o de otro tenant, da 404. Las lecturas funcionan con qm_enabled activado o no. Un login del dashboard que no puede evaluar (un puesto de agente, un member) recibe 403 role_forbidden; una clave dd_ lee.

Parámetros

NombreEnTipoObligatorioDescripción
fromquerystring (date-time)síCota inferior RFC 3339 del inicio de la grabación (inclusiva).
toquerystring (date-time)síCota superior RFC 3339 del inicio de la grabación (exclusiva); como máximo 31 días después de from.
agent_idquerystring (uuid)noSólo este agente.
form_idquerystring (uuid)noSólo este formulario.
evaluator_kindqueryhuman · automaticnoSólo evaluaciones humanas, o sólo automáticas. Sin él aparecen ambas, en filas separadas.

Respuestas

200 ​

Las filas, ordenadas por agente, formulario y luego tipo de evaluador.

CampoTipoObligatorioDescripción
fromstring (date-time)sí
tostring (date-time)sí
rowsarreglo de QmAgentReportRowsí
rows[].agent_idstring (uuid)sí
rows[].form_idstring,null (uuid)sí
rows[].evaluator_kindhuman · automatic · nullsíLas evaluaciones humanas y las automáticas nunca se promedian juntas: cada una tiene su propia fila. Null sólo en la fila vacía de una entidad solicitada sin filtro evaluator_kind.
rows[].evaluationsintegersíLas evaluaciones vigentes contabilizadas.
rows[].avg_score_bpinteger,nullsíPuntuación media en puntos básicos, redondeada; null cuando no hay evaluaciones.
rows[].pass_rate_bpinteger,nullsíAprobadas sobre evaluaciones en puntos básicos; null cuando no hay evaluaciones.
rows[].passedintegersí
rows[].auto_failedintegersíAnuladas por un criterio crítico.
rows[].adjustedintegersíEvaluaciones vigentes que reemplazaron a una disputada (la disputa se resolvió como adjusted).
rows[].open_disputesintegersíEvaluaciones vigentes con una disputa abierta y aún no resuelta. Siguen contando en todas las demás cifras.

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

Cifras de QM por campaña y formulario en una ventana ​

http
GET /v1/qm/reports/campaigns

Cifras derivadas en cada llamada a partir de las evaluaciones VIGENTES (una corrección reemplaza la fila que sustituye; la antigua deja de contar) cuya grabación empezó en [from, to). Una fila por campaña, formulario Y evaluator_kind: dos formularios son dos escalas, y la puntuación de una persona y la pasada automática nunca se promedian juntas. Por fila: evaluations, avg_score_bp (puntuación media en puntos básicos, redondeada; null cuando no hay nada que promediar, nunca 0), pass_rate_bp (passed sobre evaluations en puntos básicos, null igualmente), passed y auto_failed (anuladas por un criterio crítico). Nunca se devuelve comentario, número de teléfono ni otro texto libre.

from y to son obligatorios, from debe ser anterior a to y la ventana no puede superar 31 días (400 en caso contrario). Sin campaign_id sólo aparecen las campañas con datos; con una existente que no tiene evaluaciones en la ventana la respuesta es UNA fila con evaluations: 0 y los promedios null; una desconocida, o de otro tenant, da 404. Las lecturas funcionan con qm_enabled activado o no. Un login del dashboard que no puede evaluar (un puesto de agente, un member) recibe 403 role_forbidden; una clave dd_ lee.

Parámetros

NombreEnTipoObligatorioDescripción
fromquerystring (date-time)síCota inferior RFC 3339 del inicio de la grabación (inclusiva).
toquerystring (date-time)síCota superior RFC 3339 del inicio de la grabación (exclusiva); como máximo 31 días después de from.
campaign_idquerystring (uuid)noSólo esta campaña.
form_idquerystring (uuid)noSólo este formulario.
evaluator_kindqueryhuman · automaticnoSólo evaluaciones humanas, o sólo automáticas. Sin él aparecen ambas, en filas separadas.

Respuestas

200 ​

Las filas, ordenadas por campaña, formulario y luego tipo de evaluador.

CampoTipoObligatorioDescripción
fromstring (date-time)sí
tostring (date-time)sí
rowsarreglo de QmCampaignReportRowsí
rows[].campaign_idstring,null (uuid)sínull para las grabaciones sin campaña.
rows[].form_idstring,null (uuid)sí
rows[].evaluator_kindhuman · automatic · nullsíLas evaluaciones humanas y las automáticas nunca se promedian juntas: cada una tiene su propia fila. Null sólo en la fila vacía de una entidad solicitada sin filtro evaluator_kind.
rows[].evaluationsintegersíLas evaluaciones vigentes contabilizadas.
rows[].avg_score_bpinteger,nullsíPuntuación media en puntos básicos, redondeada; null cuando no hay evaluaciones.
rows[].pass_rate_bpinteger,nullsíAprobadas sobre evaluaciones en puntos básicos; null cuando no hay evaluaciones.
rows[].passedintegersí
rows[].auto_failedintegersíAnuladas por un criterio crítico.
rows[].adjustedintegersíEvaluaciones vigentes que reemplazaron a una disputada (la disputa se resolvió como adjusted).
rows[].open_disputesintegersíEvaluaciones vigentes con una disputa abierta y aún no resuelta. Siguen contando en todas las demás cifras.

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

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