Appearance
Hoja de ruta
English version: Roadmap.
Da por hecho que nada de lo que hay aquí se sirve salvo que la entrada diga «publicado» o «en vivo»
Esta página es el registro de las superficies diseñadas pero no construidas, mantenido para que un diseño nunca se confunda con la API en vivo. Si una entrada no está marcada explícitamente como publicada o en vivo, el core actual no la sirve — no construyas todavía contra ella. Las entradas que se diseñaron aquí y se entregaron después se quedan en la página, marcadas y enlazadas a su referencia, de modo que el registro de lo que se prometió y de lo que llegó está en una sola página. La superficie implementada es exactamente la que describen la API REST y los Eventos WebSocket.
Webhooks de salida
Empuje de servidor a servidor de hechos de la plataforma a tus endpoints — publicado en core (MT-CTI-04, fases 1-4): el registro de endpoints /v1/webhooks, un outbox escrito en la misma transacción que el hecho, un despachador con firmas HMAC, una escalera de reintentos con tope y un registro de entregas de sólo anexar. La guía de integración es Webhooks de salida (integración con CRM).
Está en una versión publicada de core desde la v0.36.0 y en la especificación vendorizada a partir de la cual este sitio genera su Referencia de la API, que manda sobre las formas de petición y respuesta; la guía sigue siendo el recorrido de integración.
No hay que confundirlos con los webhooks de SMS entrantes, que están en vivo: la plataforma aloja endpoints firmados que los proveedores de SMS llaman con acuses de entrega y respuestas de consumidores — mira Webhooks en la Referencia de la API.
Lo que prometía la vista previa de diseño de esta página y lo que se construyó de verdad — el registro de ambos, que es para lo que sirve esta página:
| Prometido aquí | Construido |
|---|---|
Cargas: mensajes dialer.v1 como protojson (CallEvent, CallDetailRecord, ComplianceDecision) | Un sobre v1 {event, event_id, occurred_at, tenant_id, data} cuyo data es la proyección pública de /v1 del recurso — la misma forma que responde su GET, no protojson. Las decisiones de cumplimiento no son un evento; el catálogo de seis nombres es call.ended, call.answered, promise.recorded, sms.received, sms.optout, recording.available. |
Cabecera de enrutado X-DD-Event-Type | X-DD-Event |
X-DD-Delivery-ID único | X-DD-Delivery-Id — la clave de idempotencia del receptor, como se prometió |
X-DD-Signature: t=<unix>,v1=<hex> sobre "<t>.<raw body>", en tiempo constante, tolerancia de ~5 minutos | Como se prometió, más X-DD-Signature-Previous durante una ventana de rotación de 24 h |
Responder 2xx en 10 s | 15 s para toda la petición, 5 s de ellos para conectar |
| Reintentos con retroceso exponencial; al menos una vez; sin orden entre entregas | Como se prometió. La escalera tiene tope y está acotada por un número máximo de intentos, luego pasa a dead-letter; la deduplicación es por X-DD-Delivery-Id (entrega) y event_id (hecho), no por callId/decisionId. |
| CRUD de endpoints en autoservicio + registro de entregas por tenant | Como se prometió: CRUD, rotación de secretos, GET /v1/webhooks/{id}/deliveries con cada intento y una reentrega manual que anexa. |
Alineación con protojson
El repo de contratos define dialer.v1 (mira Contratos), pero la API REST habla hoy su propio JSON en snake_case con disposiciones en minúsculas (answered_human, …), no protojson con nombres de enum (DISPOSITION_ANSWERED_HUMAN). Trabajo de alineación (el punto del CDR está entregado en main de core; los webhooks y el resto de la superficie REST conservan su propia forma):
- Publicado en core
v0.87.0(core#1472), y en la Referencia de la API:GET /v1/reports/cdr, el CDR como protojson canónicodialer.v1.CallDetailRecord(camelCase, nombres de enum, marcas de tiempo RFC 3339, valores por defecto de proto3 omitidos), con sus nombres de campo y de enum comprobados por los tests de core contra el.protoen el tag decontractsfijado — miraGET /v1/reports/cdr. Responde los mismos filtros, la misma paginación por keyset y el mismo aislamiento por tenant que/v1/call_attempts, que conserva su forma snake_case. Una fila de la tabla de sólo anexarcall_attemptses un registro, así que una corrección es su propio registro; una disposición fuera del enum cerrado del contrato viaja enlabels.disposition_code. - Publicado en core
v0.86.0(publicado comov0.86.0-prod-0.1), y en la Referencia de la API:GET /v1/dispositions, el catálogo del enumdialer.v1.Dispositioncon cada valor REST en minúsculas, su nombre de enum, su número de enum y una descripción. Lista el conjunto cerrado del contrato y deja fueraunspecified;call_attempts.dispositionsigue siendo un vocabulario abierto y puede llevar códigos que no están en el catálogo (abandoned,delivered,ai_conversation, …). - Publicado: el mapeo de las disposiciones en minúsculas del motor a la nomenclatura del enum Protobuf es una sola tabla en el código, derivada del espejo del enum que el CI compara con el tag de
contractsfijado; un valor nuevo del enum sin su pareja REST pone el CI en rojo, y una comprobación de fuentes impide que los valores del contrato se tecleen como cadenas sueltas en otro sitio. No se inventó una tercera forma: REST conserva el valor en minúsculas (como en la consulta de CDR) y el catálogo lleva a su lado el nombre del enum.
Endpoints de reportes de cumplimiento
- La atestación del aviso de recogida está publicada en core
v0.88.0(core#1587, ADR #211): el agente anexa lo que declaró para una llamada,GET /v1/call_attemptsy el CSV de intentos exponen uno de cinco estados, y la versión 2 del paquete de defensa lleva cada declaración. La clave de aplicación, apagada por defecto y propiedad del fundador, puede exigir la declaración antes de que se cierre una llamada de deuda contactada. Mira Atestación del aviso de recogida. - El reporte durable de marcaciones bloqueadas se publicó bajo otras rutas:
GET /v1/stats/blocked(conteos por barrera + serie diaria sobre la evidencia de sólo anexargate_blocks) y el paqueteGET /v1/reports/violations-prevented(JSON/CSV). El nombre propuestoGET /v1/reports/compliance/blockedqueda sustituido por éstos. - Publicado en core
v0.86.0(publicado comov0.86.0-prod-0.1), y en la Referencia de la API:GET /v1/consumers/{id}, la ficha del deudor. El consumidor se identifica por elconsumer_refque tu CMS envió en la importación (la plataforma no tiene un registro de consumidores aparte; es la clave bajo la que Reg F ya cuenta). La ficha lleva las deudas del consumidor, cada una con su contador de Reg F y su propia próxima ventana permitida, los registros de cese y desistimiento, los conteos de DNC por lista (nunca los números) y la próxima ventana del consumidor en conjunto en UTC y en la hora local del destino. Todo se calcula cuando lo pides, a partir de los registros de sólo anexar de llamadas, conversaciones, cese y desistimiento y DNC, ejecutando las mismas comprobaciones de horas de silencio, matriz estatal y Reg F que controlan una marcación;not_evaluated_gatesnombra lo que la ventana no cubre (consentimiento, divulgación de IA y de voz artificial, estado de la campaña, frescura del DNC). Cuando la ficha no puede decidir diceundecidabley por qué; nunca responde «llama ahora» por defecto. ElGET /v1/debts/{id}/defense-packetsellado sigue siendo el paquete para litigios. - Los archivos del paquete de defensa están publicados en core
v0.88.0(core#1578): unPOSTexplícito archiva el ZIP con la retención informada por el almacén y una marca de tiempo RFC 3161; las dos operacionesGETlistan las atestaciones y devuelven el kit de verificación sin conexión. La guía de integración distingue la retención de objetosCOMPLIANCE/GOVERNANCEde la retención configuradabucket_locky guía a un tercero poropenssl ts -verify. (Contrato: las operacionesarchiveDefensePacket,listDefensePacketArchivesygetDefensePacketAttestation; campos del archivo: el esquemaDefensePacketArchive.)
Cuentas de usuario, roles, SSO, MFA
- Cuentas de usuario del dashboard — publicado: inicio de sesión con correo + contraseña que genera una sesión
ddu_revocable, cierre de sesión, restablecimiento de contraseña y gestión de usuarios (crear, deshabilitar, rehabilitar — las filas son evidencia de auditoría y nunca se borran). Los llamantes de máquina a máquina siguen usando claves de API por tenant, y no hay suplantación conX-Tenant-ID. - Roles — publicado, pero deliberadamente pequeño: un
rolede dos valores en cada usuario (member/account_admin). Sólo unaccount_adminpuede escribir las filas de toda la empresa que heredan las sedes hermanas; unmemberrecibe403. El rol es de sólo lectura por la API — la promoción es un gesto del operador, no una petición. No hay un sistema general de roles/permisos. - SSO (SAML) — publicado en core
v0.86.0(publicado comov0.86.0-prod-0.1); sus rutas están en la Referencia de la API (el contrato se describe en Autenticación). Inicio de sesión iniciado por el SP a través del IdP del propio tenant, configurado por unaccount_admin, con validación estricta de aserciones, sin aprovisionamiento just-in-time y un intercambio en dos pasos para la sesiónddu_. Está inerte en una celda que no tiene URL base de SP. Exigir SSO a un tenant es un ajuste por tenant (sso_required_enforced) que sale apagado; encenderlo es una decisión de aplicación forzosa. El botón «Iniciar sesión con SSO» del dashboard y la pantalla de configuración del IdP se publican en el dashboard v0.41.0 (dashboard#532, dashboard#520). El cierre de sesión único está publicado en corev0.88.0(core#1581): unLogoutRequestfirmado del IdP del tenant, enviado por POST a/v1/auth/sso/{tenant_id}/slo, revoca todas las sesionesddu_de la persona que nombra suNameID(falla con cierre por defecto con un400uniforme, y unNameIDdesconocido responde exactamente igual que uno conocido), y elPOST /v1/auth/logoutde una sesión nacida de SSO devuelve además la URL de cierre de sesión del IdP cuando el IdP publicó una; la revocación local nunca depende del IdP. El inicio de sesión iniciado por el IdP no se admite, deliberadamente: una respuesta no solicitada sería un vector de CSRF de inicio de sesión y de repetición, que el intercambio en dos pasos cierra, así que un inicio de sesión siempre empieza en la plataforma. - MFA (TOTP + códigos de recuperación) — publicado en core
v0.86.0(publicado comov0.86.0-prod-0.1); sus rutas están en la Referencia de la API (el contrato se describe en Autenticación). Opcional por usuario: una persona registra una app autenticadora (TOTP de RFC 6238) y recibe diez códigos de recuperación de un solo uso, mostrados una vez; con un factor activo,POST /v1/auth/logindevuelve unchallengede un solo uso en lugar de una sesión y el tokenddu_sólo se genera enPOST /v1/auth/mfa/verify. Las claves de API de tenant (dd_) no se ven afectadas. Exigir un segundo factor a todos los usuarios de un tenant es un ajuste por tenant (mfa_required_enforced) que sale apagado; encenderlo es una decisión de aplicación forzosa. La vía administrativa de recuperación está publicada en corev0.88.0(core#1580): unaccount_adminpuede quitar el factor de otra persona tras registrar un motivo, lo que invalida los códigos de recuperación, revoca las sesiones en vivo de la persona y anexa un evento de auditoría; un tenant que exige MFA envía a la persona a un registro forzoso en su siguiente inicio de sesión. El SMS sigue fuera de los factores admitidos.
Superficies del puesto del agente
GET /v1/agent/queue— publicado en corev0.86.0(publicado comov0.86.0-prod-0.1), y en la Referencia de la API. Devuelve lo que el marcador tiene delante del puesto del token que llama: la presencia del puesto, la llamada en vivo, las devoluciones de llamada que ese puesto programó y que aún no se han ejecutado, y las ofertas entrantes en vivo dirigidas a él (vacío salvo que el flujo de la cola entrante del tenant esté encendido). Es una lectura que compone cuatro fuentes existentes, no un modelo de cola propio, y lleva sólo ids, fechas y prioridad: ni números de teléfono ni notas. Necesita una sesión de inicio de sesión (ddu_) ligada a un puesto de agente; una clave de API de tenant (dd_) no tiene puesto y recibe403, y un token de widget (ddw_) queda fuera de la lista de rutas permitidas. No hay una cola de vista previa por agente que mostrar (en modo de vista previa la cuenta se elige al marcar la llamada, y ninguna fila la reserva) y las devoluciones de llamada no se asignan a agentes (el agente de una devolución es su autor), así que ninguna de las dos aparece.PATCH /v1/agents/{id}/status— publicado en la misma versión que lo anterior. Es una fachada sobre la máquina de estados de agente existente, no un segundo modelo de presencia:{"status": "available" | "paused" | "offline"}se traduce a los verbos existentes (unpauseo fin del wrap-up,pausecon unreasonobligatorio del conjunto cerradomanual,break,lunch,training,meeting, y el check-out). Una transición que la máquina de estados no admite responde409con el estado actual del puesto enerror.current_state;offline → availablees una de ellas, porque el check-in sigue siendo el verbo que decide la capacidad y el registro SIP. Cualquier otrostatus, opausedsin unreasonválido, es400, un agente de otro tenant es404y un token de widget es403. La presencia también cambia mediante checkin/checkout y el propio marcador.- Un estado de presencia
wrap_up— publicado en core: una llamada contestada puede pasar a un agente awrap_upcuando el tope de ACW es positivo, yPOST /v1/agents/{id}/wrap-upcierra explícitamente ese estado de ACW. El ajuste gobernadoagent_wrap_up_secondsvale0por defecto, así que el ACW está disponible pero apagado por defecto; habilitarlo es una decisión del operador de la plataforma. Mira el ADR #101 de core, los endpoints de agente y core v0.85.0. La capacidad permanece encore@main. - Voz dentro del widget del agente — construida, y armada por entorno por el operador de la plataforma. El marco registra un softphone propio con una credencial SIP generada para esa única sesión de agente; donde el carril no está armado, la llamada sigue sonando en el dispositivo del puesto y el marco lo dice. Tu
<iframe>necesitaallow="microphone; autoplay"en ambos casos — mira Widget del agente (incrustación). - Un teclado de marcación (teclear un número) dentro del widget — publicado en core
v0.86.0(publicado comov0.86.0-prod-0.1) y en el marco de referencia, y en la Referencia de la API.POST /v1/dial/manualtoma un número E.164 que el agente tecleó y lo resuelve contra los teléfonos de las propias cuentas del tenant: exactamente una cuenta → la llamada pasa por las mismas barreras de cumplimiento que una marcación con vista previa y se atribuye a esa cuenta; ninguna, varias, sin campaña o un número en cuarentena →422y ninguna llamada. Un número sin cuenta no es marcable desde el widget. Qué hace y sus resultados están en Marcar un número tecleado (teclado de marcación). La marcación con vista previa (POST /v1/campaigns/{id}/dial, sobre una fila de llamada que ya lleva una campaña y una cuenta) sigue funcionando sin cambios.
Control de telefonía y AMD
- Audio del supervisor (escuchar / susurrar / intervenir / tomar el control) — publicado (control de telefonía v0.4): los endpoints de supervisión están en vivo, el Live Monitor los maneja, y
supervision.started/endedse emiten por el piso en vivo. - AMD (detección de contestador automático) — publicado para las campañas creadas con
amd_enabled. Cuando se contesta la llamada, la plataforma escucha un pitido de buzón de voz durante 5 segundos. Un pitido dentro de esa ventana es un veredictomachine, y la llamada se cierra comoanswered_machine, conamd_verdict: "machine"en su fila deGET /v1/call_attempts; mira llamadas contestadas sin puente. Si no se oye ningún pitido en la ventana, el veredicto eshuman. Ese sesgo es a propósito: un buzón que pita más tarde se trata como una persona, en lugar de arriesgarse a colgarle a una.- Una máquina no es una entrega, y no se vuelve a marcar el mismo día. Si no se aplica a la llamada ninguna regla de reintento activa tuya para
answered_machine, la plataforma aplica una por defecto: la cuenta no se vuelve a ofrecer hasta las 08:00 del día siguiente en la hora local del consumidor (en cada zona horaria a la que se asignen sus números), de modo que como máximo hay un buzón de voz por cuenta y día. Sin ella, una campaña seguía llamando al número hasta que el límite 7-en-7 de Reg F lo bloqueaba (medido el 2026-10-01: 7 llamadas en 20 segundos). Una regla de reintento propia paraanswered_machine, para toda tu cuenta o para la campaña de la llamada, sustituye a la de por defecto; las cadencias recomendadas incluyen una que reprograma una máquina para 24 horas después. - El filtro de rebobinado
amd_verdictscoincide con el último intento realizado y aceptaunspecified | human | machine | not_sure; un valor desconocido devuelve422con cierre por defecto. Los veredictos nuevos también aparecen comocall.amd_verdicten el flujo de eventos en vivo. Se fusionó en core#1458 y se publicó en corev0.86.0(publicado comov0.86.0-prod-0.1).
- Una máquina no es una entrega, y no se vuelve a marcar el mismo día. Si no se aplica a la llamada ninguna regla de reintento activa tuya para
- API de recuperación de grabaciones — publicada: el listado, la consulta por grabación, las URL de reproducción firmadas y la retención legal están en vivo.
- Cuadrícula de horario por día para campañas — publicada en core: las campañas admiten un horario semanal anulable (
mon…sun) que sólo estrecha las ventanas de toda la campaña y de horas de silencio; un horario ausente conserva el comportamiento anterior, y los horarios mal formados o vacíos fallan con cierre por defecto. El campo lo acepta y lo devuelve la API de campañas, con422para una ventana ilegible o fuera del día. Mira el ADR #163 de core, la API de campañas y core v0.85.0. Permanece encore@main. - Inicio/fin de calendario de la campaña — publicado en core
v0.87.0:starts_atyends_atanulables son valores de reloj de pared en eldefault_timezonede la campaña; el flag operativocampaign_window_enabled, apagado por defecto, controla el planificador que arranca las campañas de voz elegibles y las detiene enends_at. Mira Inicio y fin de calendario y el ADR #206 de core. - Llamadas entrantes en una troncal BYOC de toda la empresa — publicado en core
v0.88.0(core#1565):scope: "empresa"aceptasource_ips, el origen identifica la cuenta y el DID marcado selecciona la sede de destino. El registro y la revocación están restringidos aaccount_admin; cada dirección de origen sigue siendo única en toda la plataforma. Mira Llamadas entrantes en una troncal BYOC de toda la empresa y el ADR #203 de core.
Importación y tuberías de datos
- Carga CSV multipart para
/v1/debts/import— publicada en corev0.86.0(publicado comov0.86.0-prod-0.1), y en la Referencia de la API. El formulario acepta un archivotext/csven memoria, un mapeo explícito de destino a cabecera ycomma/semicolon/tab; UTF-8 (BOM opcional), y los límites por defecto de 4 MB y 10.000 filas (ajustes por tenant) fallan con cierre por defecto antes de importar. Ambas formas entran en el mismo pipeline de validación y normalización por fila. - Semillas de migración de Reg F en
/v1/debts/import—last_conversation_atpublicado en corev0.90.0(core#1633, ADR #212; JSON desde core#1626, CSV desde core#1631), y en la Referencia de la API. Una cartera migrada puede declarar tanto sus intentos previos (prior_attempts_7d, ADR #99) como su última conversación, de modo que el contador 7-en-7 de Reg F y el enfriamiento de 7 días posterior al contacto parten del historial real del cliente en lugar de cero. Mira Semillas de migración de Reg F. - Plantillas de mapeo en el servidor para el mapeador de CSV — publicadas en core
v0.86.0(publicado comov0.86.0-prod-0.1; core#1461):/v1/import-mappings, por tenant y de sólo anexar. Editar el mapeo o las opciones anexa una versión nueva y nunca reescribe la que usó una importación; las plantillas se archivan, nunca se borran; y una importación que nombra una plantilla con?mapping_id=(enPOST /v1/debts/importoPOST /v1/debt-lists/{id}/import) registra la versión que usó (GET /v1/import-mappings/{id}/uses). El dashboard lee y guarda las plantillas desde el servidor desde el dashboard v0.41.0 (dashboard#513) y ofrece mover una vez las que se guardaban en el navegador. Mira Plantillas de mapeo de importación. - Cuotas de peticiones por clave en
/v1— publicadas en corev0.86.0(publicado comov0.86.0-prod-0.1) (core#1471, ADR #193), y en la Referencia de la API. Cada clavedd_tiene su propio presupuesto por minuto, cada respuesta contada llevaX-RateLimit-*, y un429 rate_limitedllevaRetry-After; los frenos de ventana fija (inicio de sesión, tokens de widget, control de llamadas, disposiciones, invitaciones) también gananRetry-After. Los frenos de tasa de marcación/SMS y los topes mensuales de gasto (429 throttled/429 sms_spend_cap_exceeded) deliberadamente no lo llevan: la plataforma no sabe cuándo vuelve su capacidad. Mira Límites de tasa y topes.
Matriz de cobertura legal y texto del aviso de monitoreo
No se sirve. La matriz legal jurisdicción por jurisdicción que respalda la retención de grabaciones, el precio de la retención por encima del mínimo y el texto legal del aviso de monitoreo de pantalla esperan una decisión que se sigue en macro-tasks#415. Lo que core sirve hoy es sólo el contrato: los mínimos y las fuentes que devuelve GET /v1/business-types, que citan normas federales de EE. UU. y no la ley estatal, y las rutas de aviso y acuse descritas en Transcripciones de grabaciones, redacción y el aviso de pantalla. No leas ninguna de las dos como una declaración de lo que exige la ley.
Canales
La voz, el SMS y el correo electrónico están en vivo en core. El correo se publicó en core v0.97.0 con direcciones ligadas a su procedencia, supresión de sólo anexar, plantillas aprobadas, envíos disparados por disposición, email_blast, eventos firmados del proveedor y baja con un clic; sigue apagado por defecto por tenant. Mira la guía del canal de correo. El SMS tiene envíos puntuales controlados, un libro mayor unificado, enrutado de proveedor por región y webhooks firmados del proveedor — mira la referencia de SMS y Webhooks. WhatsApp no está construido.