Conceptos
Modelo de datos
Las entidades principales de SIVO y cómo se relacionan entre sí. Para tu equipo técnico que necesita entender cómo modelar la integración.
Esta página describe las entidades principales de SIVO y sus relaciones. Útil para tu equipo de IT, arquitectos de soluciones e integradores que necesitan saber cómo modelar la integración con sus sistemas.
Vista general
┌─────────────────────────────────────────────────────────────────┐
│ Tenant │
│ ┌───────┐ ┌────────┐ ┌──────┐ ┌──────┐ ┌──────────────┐ │
│ │ Users │ │ Queues │ │ DIDs │ │ IVRs │ │ SIP Trunks │ │
│ └───┬───┘ └────┬───┘ └───┬──┘ └───┬──┘ └──────┬───────┘ │
│ │ │ │ │ │ │
│ └───────────┴──────────┴─────────┴─────────────┘ │
│ │ │
│ ┌────▼─────┐ │
│ │ Calls │ (CDR + recordings + │
│ │ │ transcripts + events) │
│ └──────────┘ │
└─────────────────────────────────────────────────────────────────┘
Todo cuelga del Tenant — el contenedor principal de aislamiento. Los datos de un tenant no se ven desde otro (ver Multi-tenant).
Entidades principales
Tenant
El tenant es el cliente. Cada org SIVO tiene uno o varios tenants.
| Campo | Tipo | Significado |
|---|---|---|
id | UUID | Identificador único interno |
slug | string | URL-friendly (ej. acme-corp) |
name | string | Nombre mostrado en la UI |
sip_domain | string | Dominio SIP (acme.sip.sivocenter.com) |
plan | enum | starter / pro / enterprise |
region | enum | eu / us / custom |
created_at | timestamp | Fecha de alta |
User
Cada persona con acceso a SIVO. Es a la vez agente (atiende llamadas) y usuario del panel.
| Campo | Tipo | Significado |
|---|---|---|
id | UUID | Identificador único |
tenant_id | UUID | Tenant al que pertenece |
email | string | Login + comunicaciones |
full_name | string | Nombre completo |
extension | string | Extensión SIP (3-5 dígitos) |
role | enum | agent / supervisor / admin / viewer |
status | enum | available / on_call / paused / acw / logged_out |
language | enum | es / en / de / fr / it / pt |
mfa_enabled | bool | Si tiene MFA activado |
Queue
Cola ACD. Distribuye llamadas entre agentes según una estrategia.
| Campo | Significado |
|---|---|
id, name, tenant_id | Identificación |
strategy | ring-all / longest-idle / round-robin / top-down / fewest-calls / random |
max_wait_time | Segundos antes de timeout |
wrap_up_time | ACW automático tras colgar |
moh_url | Música de espera |
announce_position | Si dice al caller “es el número N en cola” |
service_level_target | % objetivo de atendidas en menos de N seg |
Relación con users: muchos-a-muchos vía queue_members:
| Campo | Significado |
|---|---|
queue_id, user_id | Identificación |
tier | Prioridad (1 = principal, 2 = backup) |
level | Sub-prioridad dentro del tier |
DID
Direct Inward Dial — un número entrante.
| Campo | Significado |
|---|---|
id, tenant_id | Identificación |
number | E.164 (+34911234567) |
trunk_id | Por qué trunk entran las llamadas |
ivr_flow_id | IVR que ejecuta |
schedule_id | Horario asignado (opcional) |
out_of_hours_ivr_flow_id | IVR fuera de horario |
outbound_caller_id | Si se permite como caller ID saliente |
IVR Flow
Un flujo de llamada. Múltiples versiones por flow.
| Campo | Significado |
|---|---|
id, name, tenant_id | Identificación |
description | Descripción humana |
Y por versión (ivr_flow_versions):
| Campo | Significado |
|---|---|
flow_id, version | Identificación |
is_active | Solo una versión activa por flow |
nodes | JSON con los nodos (start, menu, queue, etc.) |
created_at, created_by | Auditoría |
SIP Trunk
Conexión con tu operador telefónico.
| Campo | Significado |
|---|---|
id, name, tenant_id | Identificación |
provider | zadarma / twilio / bandwidth / custom |
host | SIP host del registrador |
username, password_encrypted | Credenciales (password cifrada AES-256-GCM) |
allowed_cidrs | Array de IPs/CIDRs permitidos |
state | REGED / TRYING / FAIL / NOREG |
failover_trunk_id | Trunk de failover (opcional) |
Schedule
Horarios de atención y festivos.
| Campo | Significado |
|---|---|
id, name, tenant_id | Identificación |
timezone | IANA (Europe/Madrid) |
hours | JSON por día con apertura/cierre |
holidays | Array de fechas YYYY-MM-DD |
exceptions | Excepciones puntuales |
Call (CDR)
Una llamada. La entidad de mayor volumen.
| Campo | Significado |
|---|---|
id | UUID |
tenant_id | Tenant |
direction | inbound / outbound / internal |
caller_id_number, caller_id_name | Origen |
destination | Destino |
did_id | DID por el que entró (si inbound) |
agent_id | Agente que atendió (nullable) |
queue_id | Cola por la que pasó (nullable) |
ivr_flow_id | IVR que se ejecutó (nullable) |
status | answered / no_answer / busy / failed / abandoned |
started_at, answered_at, ended_at | Timestamps |
duration_sec, billsec | Duración total y de conversación |
hangup_cause | NORMAL_CLEARING, CALL_REJECTED, etc. |
recording_id | Si está grabada |
transcript_id | Si está transcrita |
mos_score | Calidad audio (1-5) |
salesforce_voicecall_id | Si se empujó a SF |
Recording
| Campo | Significado |
|---|---|
id, call_id, tenant_id | Identificación |
storage_url | URL pre-firmada |
format | wav / mp3 / ogg |
duration_sec, size_bytes | Tamaño |
expires_at | Cuándo se borra (sellado por política) |
provider | sivo_managed / s3 / gcs / azure / minio |
Transcript
| Campo | Significado |
|---|---|
id, call_id, tenant_id | Identificación |
provider | deepgram / elevenlabs / whisper |
language | ISO 639-1 (es, en) |
segments | JSON con turnos: [{speaker, start, end, text}, ...] |
expires_at | Sellado al crear |
Audit Log
Inmutable.
| Campo | Significado |
|---|---|
id, timestamp | Identificación |
tenant_id, actor_user_id | Actor |
actor_ip, actor_ua | Origen |
action | create / update / delete / access / login |
resource_type, resource_id | Objeto afectado |
diff | JSONB con antes/después |
cross_tenant | Si fue acción superadmin |
Identidades — IDs externos
Para integraciones, SIVO usa estos IDs estables que puedes guardar en tus sistemas:
| Sistema | ID a guardar |
|---|---|
| Salesforce VoiceCall | vendor_call_key (UUID generado por SIVO) |
| Webhooks tuyos | event_id (UUID por evento) |
| Tu CRM | call_id de SIVO |
| Tu sistema de tickets | call_id o transcript_id |
Todos son UUIDs, estables, nunca reutilizados.
Variables de sesión IVR
Variables disponibles en cualquier nodo del flow:
| Variable | Valor |
|---|---|
caller_id_number | Origen E.164 |
caller_id_name | Nombre si el operador lo envía |
did | DID por el que entró |
now | Timestamp UTC actual |
language | Idioma esperado |
attempt | N-ésimo intento si hubo retry |
Más las custom que defines en nodos input, webhook, function, ai_agent.
Relaciones cruzadas
Una llamada con todo enlazado
Call
├── tenant_id → Tenant
├── did_id → DID → IVR Flow → Versions → Nodes
├── agent_id → User → Queue Members → Queues
├── queue_id → Queue
├── recording_id → Recording → expires según Recording Policy
├── transcript_id → Transcript → expires según Transcription Policy
├── salesforce_voicecall_id → SF VoiceCall + Conversation + ConversationEntries
└── audit_logs entries asociadas
Eventos emitidos
Cada cambio relevante emite un event consumible vía webhook:
call.created call.answered call.transferred call.ended call.recorded
queue.entered queue.abandoned
agent.status_changed agent.paused
ivr.completed ai_agent.completed
transcript.segment transcript.completed
salesforce.voicecall_pushed
Schema completo en Webhooks.
Lo que NO almacena SIVO
Para evitar confusión:
- Contactos / Leads / Cases: viven en tu CRM (Salesforce, HubSpot, propio). SIVO solo enlaza por
caller_id_number. - Oportunidades / facturas: tampoco. SIVO es centralita, no CRM.
- Datos sensibles del caller (DNI, IBAN, etc.): si tu IVR los captura, los pasa a tu sistema vía webhook. SIVO no los guarda salvo en transcripciones (con retención configurable).
API REST
Cada entidad tiene su CRUD en la API:
GET /api/{resource}
POST /api/{resource}
GET /api/{resource}/{id}
PUT /api/{resource}/{id}
DELETE /api/{resource}/{id}
Documentado en /api con OpenAPI completo.
Buenas prácticas
- Usa el UUID de SIVO como source-of-truth para identificar llamadas en tu CRM. No uses el número de teléfono — un caller puede llamar desde varios.
- Suscríbete a webhooks específicos (
call.ended,transcript.completed) en lugar de hacer poll de la API. - Captura variables en el IVR que necesites para tu BI. Mejor capturar de más que tener que reconstruir.
- Documenta tu mapping: qué variable IVR equivale a qué campo en tu CRM. Útil cuando tu equipo crece.
- Audita el data-model anual: SIVO añade campos nuevos con cada release. Revisa el changelog para aprovecharlos.