API de NeuraVoz

Conecta tus agentes

La API sirve para una sola cosa: disparar los agentes que ya creaste en NeuraVoz desde tu propia plataforma. En cada llamada envías el número a contactar y los valores que el agente necesita (nombre, mensaje, monto, lo que sea). Los agentes se crean y configuran dentro de NeuraVoz — no por API.

Introducción

Base URL: https://neuravoz.com/v1

Todas las respuestas son JSON. Los timestamps son ISO 8601 UTC. Los números en formato E.164 (+18095551234).

Los ejemplos usan curl; cualquier cliente HTTP funciona.

¿No programas?

Mira la guía paso a paso para usar todo desde el panel sin escribir código.

Quickstart

Tres pasos para disparar tu primer agente desde tu plataforma:

  1. Crea el agente en NeuraVoz (panel → Agentes IA).
  2. Crea una API key en /dashboard/developers y obtén el id de tu agente con GET /v1/agents.
  3. Dispara una llamada enviando el número y los valores:
curl -X POST https://neuravoz.com/v1/calls \
  -H "Authorization: Bearer nvk_live_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "agent_id": "TU_AGENT_ID",
    "to": "+18095551234",
    "dynamic_variables": { "nombre": "Carlos", "monto": "$320" }
  }'

El agente llama al número to y conversa usando los valores que enviaste. Recibes el resultado por webhook (opcional).

Autenticación

Las API keys se crean en /dashboard/developers. Cada key empieza con nvk_live_ y se muestra una sola vez — guárdala segura.

Pásala en cada request como Authorization: Bearer ...:

curl https://neuravoz.com/v1/agents \
  -H "Authorization: Bearer nvk_live_abc123..."

Las keys se guardan hasheadas (SHA-256). No almacenamos el texto plano después del primer reveal.

Tus agentes

Lista los agentes y trabajos que creaste en NeuraVoz. Cada uno indica las variables que espera — esos son los valores que debes enviar al dispararle una llamada.

GET /v1/agents
Authorization: Bearer nvk_live_...

# Respuesta
{
  "object": "list",
  "data": [
    {
      "id": "uuid-del-agente",
      "name": "Recordatorio de citas",
      "kind": "job",              // "assistant" (atiende entrantes) | "job" (salida)
      "parent_id": "uuid-asistente",
      "voice_id": "kcQkGnn0HAT2JRDQ4Ljp",
      "language": "es",
      "first_message": "Hola {{nombre}}, le llamo de {{empresa}} por su cita {{fecha}}.",
      "variables": ["nombre", "empresa", "fecha"],   // <- lo que debes enviar
      "provider_agent_id": "agent_xxx",
      "created_at": "..."
    }
  ]
}

Filtra por tipo con ?kind=assistant o ?kind=job. Obtén uno solo con GET /v1/agents/{id}.

Los agentes se crean y editan en el panel de NeuraVoz, no por API.

Llamar en varios idiomas

Cada agente tiene su language y su voz fijos. Para llamar en otro idioma, crea un agente equivalente en ese idioma y, al disparar la llamada, elige el agent_id según el idioma del destinatario (ej. uno en es y otro en en). Todo lo demás del request es idéntico.

Disparar una llamada

Es el corazón de la API: le dices a un agente que llame a un número, con los valores de esa llamada.

POST /v1/calls
Authorization: Bearer nvk_live_...
Content-Type: application/json
Idempotency-Key: id-unico-por-llamada

{
  "agent_id": "uuid-del-agente",
  "to": "+18095551234",
  "dynamic_variables": {
    "nombre": "Carlos",
    "empresa": "Clínica Vista",
    "fecha": "mañana a las 3 PM"
  },
  "external_ref": "cita_98231"
}

# Respuesta 201
{
  "id": "conversation_id",
  "object": "call",
  "agent_id": "uuid",
  "from": "+13053492297",       // caller ID: el número del agente o el compartido
  "to": "+18095551234",
  "status": "initiated",
  "external_ref": "cita_98231",
  "rate_per_min": 0.18,
  "created_at": "..."
}

from es opcional: si el agente tiene un número propio asignado en NeuraVoz, la llamada sale con ese caller ID; si no, con el número compartido de la plataforma. No necesitas gestionar números por API.

Estado y resultado de una llamada

El id es el que devolvió POST /v1/calls. Además del estado, incluye outcome: el desenlace de la llamada (resumen, si cumplió el objetivo, duración, datos capturados y transcripción). Mientras la llamada no concluya, outcome es null — vuelve a consultarlo unos segundos después.

GET /v1/calls/{id}
Authorization: Bearer nvk_live_...

# Respuesta
{
  "id": "conversation_id",
  "status": "completed",
  "duration_seconds": 47,
  "cost": 0.15,
  "recording_url": null,
  "transcription": "...",
  "dynamic_variables": { ... },
  "external_ref": "cita_98231",
  "outcome": {
    "status": "done",
    "title": "Confirmación de cita",
    "summary": "El cliente confirmó su cita para mañana a las 3 PM.",
    "successful": "success",          // success | failure | unknown
    "duration_seconds": 47,
    "data_collected": { ... },        // datos estructurados capturados
    "transcript": [
      { "role": "agent", "message": "Hola Carlos..." },
      { "role": "user",  "message": "Sí, ahí estaré" },
      { "role": "agent", "message": "...", "tools": ["reportar_solicitud"] }
    ]
  }
}

Listar llamadas

GET /v1/calls?limit=50
GET /v1/calls?external_ref=cita_98231   # filtra por tu propio identificador

Valores por llamada

Piensa en cada llamada como una fila de un CSV, pero enviada por API: el número a marcar (to) más los valores que el agente necesita, en dynamic_variables.

El agente referencia esos valores en su primer mensaje y su prompt con doble llave:

# En NeuraVoz el agente dice:
"Hola {{nombre}}, le llamo de {{empresa}} por su pedido {{orden}}."

# Tú, en cada POST /v1/calls, mandas los valores de ESA llamada:
{
  "agent_id": "uuid",
  "to": "+18095551234",
  "dynamic_variables": {
    "nombre": "Carlos",
    "empresa": "Vista",
    "orden": "ORD-8821"
  }
}

Hasta 50 variables por llamada, de máximo 500 caracteres cada una. Nombres válidos: [a-zA-Z_][a-zA-Z0-9_]{0,63}. Los valores que no envíes usan un default seguro para que el agente nunca se corte por falta de una variable. Descubre qué variables espera cada agente en GET /v1/agents.

Llamadas programadas

Agrega scheduled_at (ISO-8601, hasta 30 días adelante) y la llamada queda encolada hasta ese momento.

POST /v1/calls
{
  "agent_id": "uuid",
  "to": "+18095551234",
  "scheduled_at": "2026-10-15T14:30:00Z",
  "dynamic_variables": { "nombre": "Lucia" }
}

# Respuesta 202
{ "object": "scheduled_call", "id": "uuid", "scheduled_at": "...", "status": "scheduled" }

Un worker dispara la llamada con tolerancia de ±1 minuto. La Idempotency-Key también evita duplicados en la cola.

Idempotency

POST /v1/calls acepta el header opcional Idempotency-Key. Si reintentas con la misma key dentro de 24h, la API devuelve la respuesta original sin crear una segunda llamada.

Recomendado: un UUID por intención de llamada, así un reintento de tu sistema no duplica cargos.

Webhooks (resultados)

Opcional. Recibe en tu URL el resultado de cada llamada (terminó, falló, duración, costo). Configúralos en /dashboard/developers o por API.

POST /v1/webhooks
{
  "url": "https://api.tuapp.com/webhooks/neuravoz",
  "events": ["call.completed", "call.failed"]
}

# Respuesta 201
{ "id": "uuid", "url": "...", "events": [...], "secret": "whsec_xxx" }  // secret solo al crear

Verificar la firma

Cada request incluye X-NeuraVoz-Signature: t=<timestamp>,v1=<hmac_hex>:

import { createHmac } from "node:crypto";

function verify(secret, header, rawBody) {
  const [tsPart, sigPart] = header.split(",");
  const ts = tsPart.split("=")[1];
  const sig = sigPart.split("=")[1];
  const mac = createHmac("sha256", secret).update(`${ts}.${rawBody}`).digest("hex");
  return mac === sig && Math.abs(Date.now()/1000 - parseInt(ts,10)) < 300; // 5 min
}

Payload

{
  "id": "evt_xxxx",
  "type": "call.completed",
  "created_at": "...",
  "data": {
    "id": "conversation_id",
    "to": "+18095551234",
    "duration_seconds": 47,
    "cost": 0.15,
    "status": "completed",
    "agent_id": "uuid",
    "external_ref": "cita_98231",
    "dynamic_variables": { ... }
  }
}

Tu endpoint debe responder 2xx. Reintentos con backoff: 1m → 5m → 30m → 2h → 12h. Usa X-NeuraVoz-Event-Id para deduplicar.

Eventos

  • call.queued — llamada creada, en cola
  • call.ringing — sonando
  • call.answered — contestada
  • call.completed — terminada (con duración y costo)
  • call.failed — falló (ocupado, sin respuesta, error)

Errores

Formato uniforme:

{
  "error": {
    "code": "insufficient_balance",
    "message": "Balance $0.20 below minimum $0.50 for agent calls"
  }
}

Códigos comunes: unauthorized (401), insufficient_scope (403), agent_not_found (404), insufficient_balance (402), rate_limited (429), provider_error (502).

Rate limits

Por defecto: 60 requests por minuto por API key. Si lo superas, recibes 429 rate_limited (ventana fija de 1 minuto).

Para volumen alto, dispara llamadas individuales con Idempotency-Key y reintentos exponenciales. ¿Necesitas un límite mayor? Escríbenos indicando el caso de uso.