Skip to content

Transcripciones de grabaciones, redacción de audio y aviso de monitoreo de pantalla ​

English version: Recording transcripts, redaction, screen recording.

Esta guía cubre dos cosas que la plataforma hace con una llamada grabada y las rutas que las exponen: la transcripción posterior a la llamada y la redacción de datos personales en el audio. Otras secciones dan el contrato de las rutas del aviso de monitoreo de pantalla, de la grabación de pantalla y de las sesiones de monitoreo de pantalla en vivo. Los nombres de campo, los enums y los códigos de estado están copiados del documento OpenAPI vendorizado (core v0.105.0); la Referencia de la API generada a partir de él es la autoridad sobre las formas.

Disponibilidad ​

CapacidadDisponibilidad
GET /v1/recordings/{id}/transcriptPublicado en core v0.103.0 (core#1971, core#2064)
GET / POST /v1/recordings/{id}/redaction, POST /v1/recordings/{id}/original-urlPublicado en core v0.103.0 (core#2016)
GET /v1/screen-monitor/notice, POST / GET /v1/screen-monitor/acksPublicado en core v0.103.0 (core#1989)
PUT /v1/screen-recordings/{id}/chunks/{n}, POST /v1/screen-recordings/gapsPrimero en core v0.104.0 (core#2036); presente en la spec de v0.105.0
PUT /v1/screen-monitor/armed, POST /v1/screen-monitor/sessions, POST .../sessions/{id}/signal, POST .../sessions/{id}/endPrimero en core v0.104.0 (core#1990); presente en la spec de v0.105.0
GET /v1/screen-monitor/sessionsPrimero en core v0.105.0 (core#1990)

Toda ruta de screen-monitor y screen-recordings responde 404 not_found mientras la bandera screen_monitor_enabled del tenant esté apagada, salvo las lecturas del libro (GET /v1/screen-monitor/acks, GET /v1/screen-monitor/sessions) y POST .../sessions/{id}/end, que según la spec no la consultan.

Que una grabación dada tenga transcripción depende de la elegibilidad (ver abajo) y de que la celda tenga configurado un motor de transcripción. Una grabación sin transcripción responde 404, no un documento vacío.

Transcripción ​

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

El cuerpo 200 es { "transcript": { ... } } con los campos del esquema RecordingTranscript:

CampoTipoSignificado
recording_iduuidLa grabación.
providerstringProveedor de voz a texto que la produjo.
modelstringModelo que la produjo.
languagestring o nullIdioma que reportó el proveedor, cuando reportó alguno.
audio_secondsintegerSegundos de audio facturados.
segment_countintegerNúmero de segmentos con tiempos.
created_atdate-timeCuándo se guardó la transcripción.
segmentsarraySegmentos con tiempos, ordenados por seq.

Cada entrada de segments tiene seq (entero desde 0), channel (canal de audio, 0 o 1), start_ms, end_ms y text.

Quién puede leerla ​

Una transcripción es el dato personal en bruto de una llamada, así que la ruta es estrecha:

  • Permitido: un login del dashboard (ddu_) con un asiento de supervisor o administrador, o un login account_admin sin asiento.
  • No permitido: una llave de API dd_ del tenant, un token de widget y un asiento de agente reciben todos 403 role_forbidden.

Qué se audita ​

Cada entrega anexa un evento de lectura en la misma transacción que la lectura: quién la leyó, cuándo, qué grabación y cuántos segmentos. El evento nunca contiene el texto. Si el evento no se puede escribir, no se devuelve texto y la respuesta es 503; reintenta más tarde.

Cuándo es 404 ​

404 es una sola respuesta para varias situaciones, de modo que la ruta no sirva para sondear otros tenants: la grabación pertenece a otro tenant, su audio fue purgado (la purga borra con él la transcripción), nunca fue elegible para una transcripción, o el id está mal formado. Una grabación bajo legal_hold conserva su transcripción.

Códigos de estado ​

CódigoSignificado
200La transcripción.
401Credenciales ausentes o inválidas.
403El rol de quien llama no puede leer transcripciones.
404No hay transcripción para esta grabación en este tenant.
503No se pudo registrar el evento de lectura, así que no se devolvió texto.

Si el proveedor de transcripción no está disponible ​

La transcripción corre después de la llamada, fuera de la ruta de la petición, y falla cerrado:

  • El gasto en transcripción de pago tiene un tope mensual por el freno de gasto de la plataforma. Un proveedor de pago sólo se usa cuando el tope es positivo; con un tope de 0 el trabajo se detiene sin gastar y no recurre en silencio a un motor local.
  • Si el motor de transcripción rechaza el proveedor solicitado, el trabajo termina sin guardar nada y se libera el gasto reservado. Si responde con un proveedor distinto del reservado, core tampoco guarda esa respuesta.
  • La elegibilidad se decide antes de cualquier gasto: el plan debe incluirla (Scale y Enterprise), la grabación debe estar disponible, dentro de los límites de duración, atendida por una persona y no ser una llamada de IA, y no tener una transcripción previa. Lo que no califica no se reserva, no se factura y no se vuelve a encolar.

El efecto visible para un cliente de la API es el mismo en todos los casos: la grabación no tiene transcripción y GET .../transcript responde 404. La respuesta no tiene un estado «pendiente».

Redacción de audio ​

La redacción nunca edita la grabación almacenada. La plataforma conserva el original intacto, con su retención y su retención legal, y construye una copia derivada con los tramos sensibles silenciados o sustituidos por un tono. Esa copia es la vista por defecto.

Qué se redacta ​

Un tramo es un rango de tiempo más una categoría de una lista cerrada. La petición no lleva ningún valor, y la redacción almacenada tampoco guarda ninguno:

CampoTipoNotas
start_msinteger, mín. 0Inicio del tramo.
end_msintegerFin del tramo.
categoryenumcard, ssn, bank_account, pin.

Sólo se pueden redactar grabaciones WAV. Cualquier otro formato es 422 unsupported_codec.

Pedir una redacción ​

http
POST /v1/recordings/{id}/redaction
json
{
  "method": "silence",
  "segments": [
    { "start_ms": 12400, "end_ms": 15800, "category": "card" }
  ]
}
  • segments es obligatorio: de 1 a 500 entradas.
  • method es silence (por defecto) o beep.
  • Los tramos se unen con los ya almacenados, y la copia se reconstruye a partir del original. La llamada es idempotente; version sube sólo cuando se añadió algo nuevo.
  • Quien llama necesita el mismo rol que para el original (ver abajo).

El cuerpo 200 es { "redaction": { ... } } con recording_id, method, segments, redacted_ms, version, codec, requested_by, created_at y updated_at. Códigos de estado: 400, 401, 403, 404, 409, 422.

Leer la redacción ​

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

Devuelve el mismo objeto redaction: tiempos, categorías, método y versión, nunca los valores y nunca llaves del almacén de objetos. 404 cuando la grabación no tiene redacción. Códigos de estado: 200, 401, 403, 404.

Reproducción y el original ​

POST /v1/recordings/{id}/playback-url devuelve la copia redactada cuando la grabación la tiene. Si la fila de redacción existe pero su copia ya no está (purgada), la ruta no recurre al original.

El audio sin redactar tiene su propia puerta:

http
POST /v1/recordings/{id}/original-url
json
{ "reason": "Dispute 2026-0417: customer denies the payment promise" }
  • Quién puede pedirlo: una llave dd_ del tenant o un login del dashboard con el rol account_admin. Cualquier otro recibe 403 role_forbidden.
  • reason es obligatorio, no vacío, de como máximo 500 caracteres.
  • El actor y el motivo se escriben en un registro de acceso de sólo-anexar antes de devolver la URL; si la entrada del registro no se puede escribir, no se emite ninguna URL.
  • El cuerpo 200 es una URL firmada de corta vida (url, expires_at). Códigos de estado: 400, 401, 403, 404, 409.

Aviso de monitoreo de pantalla y acuses de recibo ​

Antes de que se pueda observar la pantalla de un asiento, el asiento acusa recibo de un aviso versionado. Esta sección es sólo el contrato de las rutas. El texto legal del aviso no se publica en esta guía; ver Lo que no cubre esta guía.

Leer el aviso vigente ​

http
GET /v1/screen-monitor/notice

El cuerpo 200 es { "notice": { ... } } con version, lang, title, body, text_sha256 (SHA-256 en hexadecimal de body en UTF-8), effective_at y published_at. El aviso es un catálogo global de sólo-anexar: publicar una version más nueva invalida todos los acuses de las anteriores sin tocarlas.

  • Lo alcanzan una llave dd_ y un login ddu_; un token de widget ddw_ recibe 403.
  • 404 not_found cuando la bandera screen_monitor_enabled del tenant está apagada, y también cuando aún no se ha publicado ninguna versión.
  • Códigos de estado: 200, 401, 403, 404.

Acusar recibo desde el propio asiento ​

http
POST /v1/screen-monitor/acks
json
{ "notice_version": 3, "scope": "live_monitoring" }
CampoTipoNotas
notice_versioninteger, mín. 1Obligatorio. Debe ser la versión vigente.
scopeenumObligatorio: live_monitoring o screen_recording.
agent_iduuidOpcional. Si está presente, debe ser el asiento de quien llama.
  • Los dos alcances se acusan por separado: aceptar el monitoreo en vivo no autoriza la grabación, y una versión nueva del aviso invalida ambos.
  • Sólo puede acusar un login ddu_ con un asiento vinculado. Una llave dd_ recibe 403 forbidden; un ddu_ sin asiento activo recibe 403 seat_not_linked; un agent_id que no es el asiento de quien llama recibe 403 forbidden.
  • El asiento sale del bearer, nunca del cuerpo.
  • Repetir la misma versión y alcance devuelve el primer acuse (200, sin fila nueva). El libro es de sólo-anexar.
  • 404 not_found mientras screen_monitor_enabled esté apagada. Con la bandera activa: 409 no_notice_published cuando no existe ninguna versión, 409 stale_notice cuando notice_version no es la vigente.
  • El cuerpo 200 es { "ack": { ... } } con id, agent_id, notice_version, scope, text_sha256 (copiado del aviso que vio el asiento), channel (dashboard_checkin) y acked_at. Códigos de estado: 200, 400, 401, 403, 404, 409.

Listar los acuses ​

http
GET /v1/screen-monitor/acks?limit=50&cursor=...&agent_id=...

Del más reciente al más antiguo, paginado por cursor: limit de 1 a 200 (por defecto 50; un valor mayor se recorta, no se rechaza), cursor es el next_cursor de la página anterior y agent_id filtra a un solo asiento. El cuerpo es { "acks": [...], "next_cursor": ... } y next_cursor es null en la última página.

Sólo se permite a un asiento cuyo rol de plantilla sea supervisor o admin (403 role_forbidden en otro caso; una llave dd_ y un ddu_ sin asiento reciben 403). No depende de la bandera screen_monitor_enabled: es el registro de lo que se aceptó, y apagar la función ni lo borra ni lo oculta. Nada cruza entre tenants. Códigos de estado: 200, 400, 401, 403.

Grabación de pantalla ​

El navegador del agente captura su propia pantalla y la sube a core en trozos. Todo esto está detrás de la bandera del tenant screen_monitor_enabled (ver la nota bajo Disponibilidad) y detrás de un acuse aparte.

Consentimiento: el acuse screen_recording ​

Grabar necesita un acuse vigente con scope: "screen_recording" (ver Acusar recibo desde el propio asiento). Es independiente de live_monitoring: aceptar uno nunca autoriza el otro, y una versión nueva del aviso invalida ambos. GET /v1/me lo reporta por alcance en screen_monitor.scopes.<scope>.ack_current (ScreenMonitorStatus); un alcance está autorizado sólo cuando enabled es true y ack_current es true.

Subir un trozo ​

http
PUT /v1/screen-recordings/{id}/chunks/{n}?call_uuid=...
Content-Type: video/webm
  • id es un UUID que elige el cliente, uno por llamada, de modo que un reintento sea idempotente. n es el número de trozo, de 0 a 1 000 000. call_uuid es obligatorio (de 1 a 128 caracteres) y debe ser una llamada del asiento de quien llama.
  • El cuerpo es video/webm o video/mp4, de como máximo 4 000 000 de bytes por trozo (413 por encima de eso, 415 para otro tipo).
  • Sólo puede subir un login ddu_ con un asiento vinculado; una llave dd_, un ddu_ sin asiento y un token ddw_ reciben 403.
  • El asiento, la llamada y la retención vienen de core, no del cliente. El trozo se sella con la llave del tenant (AES-256-GCM) antes de llegar al almacén, ligado a id y n.
  • Sin un acuse screen_recording vigente la respuesta es 403 screen_recording_not_acknowledged, no se guarda nada y se registra un hueco not_armed.

201 significa que el trozo se selló y se guardó; 200 significa que esos mismos bytes ya estaban guardados (status: duplicate). El cuerpo es { "chunk": { ... } } con recording_id, seq, bytes (tamaño antes de sellar), status (stored o duplicate) y retained_until (una fecha, heredada de la grabación de voz de la misma llamada).

CódigoSignificado
404Bandera apagada, o call_uuid desconocido o de la llamada de otro agente (misma respuesta para ambos).
409 chunk_conflictEse n ya contiene otros bytes.
409 recording_conflictLa llamada ya tiene una grabación bajo otro id, o id pertenece a otra llamada.
410La grabación de pantalla se purgó al terminar su retención.
503El almacén no tomó el trozo; reinténtalo. Se registra un hueco upload_failed.

Otros códigos: 400, 401, 403, 413, 415.

Declarar un hueco ​

http
POST /v1/screen-recordings/gaps
json
{ "call_uuid": "...", "reason": "agent_stopped", "note": "capture ended by the agent" }

reason es not_armed, agent_stopped o upload_failed; note es opcional, de como máximo 500 caracteres. Es idempotente por llamada, motivo y origen, no necesita acuse (un hueco es evidencia, no contenido) y aplica las mismas reglas de asiento y de llamada que la subida. El cuerpo 200 es { "gap": { "call_uuid", "reason", "source" } } con source siempre agent para esta ruta; core escribe su propio hueco not_armed cuando llega un trozo sin acuse.

Retención, lecturas y purga ​

retained_until en la respuesta del trozo se hereda de la grabación de voz de la misma llamada, y subir a una grabación purgada al terminar su retención da 410. La spec vendorizada de v0.105.0 no publica una ruta para leer de vuelta una grabación de pantalla, ni una URL firmada para ella, ni una ruta de purga, así que esta guía no las describe.

Sesiones de monitoreo de pantalla en vivo ​

Un supervisor puede ver en vivo la pantalla de un agente. Core no ve el video: valida, escribe una fila en el libro y señala a ambos navegadores, que negocian el medio de par a par.

  1. Armar. PUT /v1/screen-monitor/armed con { "armed": true, "tab_id": "..." } (tab_id de 1 a 64 caracteres) desde el propio asiento del agente una vez que su dashboard tiene una captura. Armar exige que el asiento esté registrado (409 not_checked_in) y tenga un acuse live_monitoring vigente (409 no_ack). Una pestaña por asiento: armar con otro tab_id desplaza a la anterior. El estado armado vive en el proceso, así que un reinicio desarma a todos.
  2. Abrir. POST /v1/screen-monitor/sessions con { "agent_id": "..." } desde un asiento supervisor o admin. 201 devuelve { "session": { ... } } con result: "started". Todo resultado escribe una fila en el libro, también los rechazados. Códigos 409: no_ack, not_armed, agent_busy, agent_unreachable. Un agente desconocido, un agente de otro tenant y un agente inactivo dan el mismo 404.
  3. Señalizar. POST /v1/screen-monitor/sessions/{id}/signal con kind (offer, answer o candidate) y payload. offer sólo desde el agente, answer sólo desde el supervisor. El payload se reenvía y nunca se guarda; como máximo 16 384 bytes (413 payload_too_large) y 60 mensajes por 10 segundos por sesión (429 rate_limited con Retry-After). 202 devuelve delivered, false cuando la otra parte no tenía un socket vivo. Una sesión cerrada es 409 session_closed.
  4. Terminar. POST /v1/screen-monitor/sessions/{id}/end, cuerpo opcional { "reason": "peer_failed" }. Cualquiera de las partes puede llamarlo, es idempotente y funciona con la bandera apagada. El sistema también cierra una sesión viva al hacer checkout, al perder el socket, al caducar la credencial, o cuando dejan de cumplirse la bandera, el rol del supervisor o el acuse del agente.

GET /v1/screen-monitor/sessions lista el libro (asiento supervisor o admin, del más reciente al más antiguo, limit de 1 a 200 con 50 por defecto, cursor, agent_id, y result en started, ended, failed, refused). Una fila (ScreenMonitorSession) tiene id, supervisor_user_id, supervisor_id, agent_id, notice_version, result, reason (flag_off, role, agent_not_found, no_ack, not_armed, agent_busy, agent_stopped, credential_lapsed, checkout, peer_failed o null), started_at y ended_at. Nunca lleva payload de señalización y no depende de la bandera.

Quién puede cambiar la configuración de compliance ​

Escribir la configuración de compliance del tenant exige un administrador: una clave dd_ o un inicio de sesión account_admin (core#2438). Un inicio de sesión member recibe 403 role_forbidden en toda escritura. En el entorno de esta guía son:

  • PUT /v1/recordings/{id}/legal-hold, para poner o levantar una retención legal.
  • PUT /v1/recording-policy, la política de grabación del tenant.

La lectura no cambia: GET /v1/recording-policy y los metadatos de la propia grabación, donde se ve la retención, siguen abiertos a los mismos lectores que antes. La misma regla cubre la divulgación de voz artificial, las reglas de reintento y la pausa y reanudación de la IA; esas rutas se describen en la referencia de API generada, no en esta guía.

Lo que no cubre esta guía ​

La redacción de datos personales en la grabación de pantalla (core#2017) no está publicada en la spec de v0.105.0, así que esta guía no afirma nada sobre ella.

El texto legal del aviso de monitoreo y la matriz legal jurisdicción por jurisdicción no se publican en esta guía. Esperan la decisión que sigue macro-tasks#415, y el Roadmap los lista como no servidos. Las rutas de arriba sólo transportan el texto de aviso que publique la plataforma; no afirman nada sobre lo que exige la ley.

Cómo se detectan los tramos no forma parte de las rutas de redacción: el endpoint recibe tramos, no los encuentra. La redacción de audio Opus no está servida; sólo WAV, como indica el 422 de arriba.

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