API REST

Integra CallHalla
en tus sistemas

Una API REST sobre la misma plataforma que usa la aplicación: agentes, campañas, llamadas, contactos, números de teléfono y webhooks. Esta página documenta lo que existe hoy.

Autenticación

Todas las peticiones llevan la cabecera Authorization. Hay dos mecanismos:

JWT de sesión

El que usa la propia aplicación web. El token de acceso se obtiene al iniciar sesión y se renueva automáticamente vía POST /api/auth/refresh con la cookie segura de refresco.

API keys (agl_…)

Claves de integración para tráfico servidor a servidor. Se crean en Ajustes → API Keys y empiezan por el prefijo agl_. La clave completa solo se muestra una vez: el sistema guarda un hash y conserva los primeros 8 caracteres para que puedas identificarla.

Cabecera de autenticación
Authorization: Bearer <token>
Primera petición
curl "https://callhalla.io/api/agents" \
  -H "Authorization: Bearer agl_live_..."

Convenciones

URL base

Todas las rutas viven bajo el prefijo /api, con recursos en kebab-case y verbos REST semánticos (GET para leer, POST para crear o accionar, PATCH para editar, DELETE para borrar).

https://callhalla.io/api

Respuestas exitosas

La API usa dos estructuras: la entidad directa (o un array plano) para recursos individuales y listados simples, y un envoltorio de paginación para colecciones voluminosas.

Recurso único o listado plano
{
  "id": "agent-uuid-123",
  "name": "Asistente Comercial",
  "type": "natural",
  "isActive": true
}
Listado paginado
{
  "data": [
    {
      "id": "contact-uuid-999",
      "firstName": "Alan",
      "phone": "+34600000000",
      "status": "pending"
    }
  ],
  "pagination": {
    "page": 1,
    "pageSize": 25,
    "totalItems": 142,
    "totalPages": 6
  }
}

Parámetros de paginación: page (base 1, por defecto 1) y pageSize o limit (por defecto 25).

Errores

Todos los errores devuelven JSON con la misma estructura — nunca HTML ni texto plano. El campo correlationId permite a soporte localizar tu petición en los logs.

{
  "success": false,
  "error": "Agent limit reached. Maximum allowed: 3",
  "code": "PLAN_LIMIT_EXCEEDED",
  "statusCode": 403,
  "timestamp": "2026-05-26T09:20:00.000Z",
  "correlationId": "8f2d9c1a-7b3c-4d5e-8f9a-0b1c2d3e4f5a"
}
CódigoHTTPCausa común
VALIDATION_ERROR400Parámetros mal formados o tipos incorrectos
AUTHENTICATION_ERROR401Token JWT ausente o expirado, o API key inválida
AUTHORIZATION_ERROR403Rol de usuario insuficiente
NOT_FOUND404El recurso no existe
CONFLICT_ERROR409Operación denegada por el estado actual (p. ej. pausar una campaña ya pausada)
INSUFFICIENT_CREDITS402Saldo de créditos de llamada agotado
PLAN_LIMIT_EXCEEDED403Cuota máxima del plan alcanzada (agentes, números…)
RATE_LIMIT_ERROR429Límite de peticiones por ventana rebasado
PAYMENT_ERROR402Error al procesar el cobro
EXTERNAL_SERVICE_ERROR502Fallo en un proveedor externo (telefonía, voz…)
DATABASE_ERROR500Error interno de base de datos
CONFIGURATION_ERROR500Fallo de configuración del servidor
WEBHOOK_VALIDATION401Firma del carrier telefónico incorrecta

Recursos principales

Los grupos de endpoints disponibles, con los representativos de cada recurso. No es el catálogo completo: preferimos documentar poco y que sea exacto.

Agentes

Crea y gestiona tus agentes de voz.

  • GET/api/agents— Listar agentes
  • POST/api/agents— Crear un agente

Campañas

Crea campañas de llamadas y contrólalas (ejecutar, pausar, reanudar, cancelar).

  • GET/api/campaigns— Listar campañas
  • POST/api/campaigns— Crear una campaña
  • POST/api/campaigns/:id/execute— Ejecutar una campaña

Llamadas

Historial y detalle. Las llamadas se generan al ejecutar campañas o al recibir llamadas entrantes; no se crean directamente por API.

  • GET/api/calls— Listar llamadas (paginado)
  • GET/api/calls/:id— Detalle de una llamada

Contactos

Consulta los contactos de tu cuenta. Se cargan por CSV dentro de una campaña.

  • GET/api/contacts— Listar contactos
  • POST/api/campaigns/:campaignId/contacts/upload— Subir contactos (CSV) a una campaña

Números de teléfono

Busca números disponibles y gestiona los de tu cuenta.

  • GET/api/phone-numbers— Listar tus números
  • POST/api/phone-numbers/buy— Comprar un número

Webhooks

Suscripciones a eventos con entrega firmada y reintentos.

  • GET/api/webhooks— Listar webhooks
  • POST/api/webhooks— Crear un webhook

Ejemplos

Listado paginado de llamadas
curl "https://callhalla.io/api/calls?page=1&pageSize=25" \
  -H "Authorization: Bearer agl_live_..."
Crear un webhook (el secreto HMAC se genera y devuelve al crearlo)
curl -X POST "https://callhalla.io/api/webhooks" \
  -H "Authorization: Bearer agl_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Mi integración",
    "url": "https://example.com/webhooks/callhalla",
    "events": ["call.completed", "campaign.completed"]
  }'

Webhooks

Recibe un POST con JSON en tu URL cada vez que ocurre un evento al que estés suscrito. El payload siempre tiene la misma forma:

Payload de ejemplo
{
  "event": "call.completed",
  "timestamp": "2026-06-12T10:30:00.000Z",
  "data": { ... }
}

Eventos disponibles

Estos son los eventos que acepta la API al crear un webhook:

Llamadas salientes

  • call.started
  • call.ringing
  • call.answered
  • call.completed
  • call.failed
  • call.transferred
  • call.no_answer
  • call.busy
  • call.voicemail

Llamadas entrantes

  • inbound_call.received
  • inbound_call.answered
  • inbound_call.completed
  • inbound_call.missed

Campañas

  • campaign.started
  • campaign.paused
  • campaign.resumed
  • campaign.completed
  • campaign.failed
  • campaign.cancelled

Flujos

  • flow.started
  • flow.completed
  • flow.failed

Citas

  • appointment.booked
  • appointment.confirmed
  • appointment.cancelled
  • appointment.rescheduled
  • appointment.completed
  • appointment.no_show
  • appointment.reminder_sent

Formularios

  • form.submitted
  • form.lead_created

Firma HMAC

Cada entrega incluye la cabecera X-Webhook-Signature: un HMAC-SHA256 en hexadecimal del cuerpo, calculado con el secreto del webhook (generado al crearlo). También se envían X-Webhook-Event (evento) y X-Webhook-Delivery (id único de entrega).

Reintentos

Si tu endpoint no responde 2xx, la entrega se reintenta hasta 5 veces en total, esperando 1, 5, 15, 30 y 60 minutos entre intentos. Cada petición tiene un timeout de 30 segundos. Puedes consultar las entregas en GET /api/webhooks/:id/logs y probar tu configuración con POST /api/webhooks/:id/test.

Verificación de la firma en Node
const crypto = require("crypto");

function verifyWebhook(rawBody, signatureHeader, secret) {
  // signatureHeader = "sha256=<hex>"
  const expected =
    "sha256=" +
    crypto.createHmac("sha256", secret)
      .update(rawBody)
      .digest("hex");
  return (
    signatureHeader.length === expected.length &&
    crypto.timingSafeEqual(
      Buffer.from(signatureHeader),
      Buffer.from(expected)
    )
  );
}

app.post("/webhooks/callhalla", (req, res) => {
  const ok = verifyWebhook(
    req.rawBody,
    req.headers["x-webhook-signature"],
    process.env.CALLHALLA_WEBHOOK_SECRET
  );
  if (!ok) return res.status(401).end();
  res.status(200).end();
});

¿Listo para integrar?

Crea tu cuenta, genera una API key en Ajustes y haz tu primera petición en minutos.