La API y los webhooks de Remute
Lee tus llamadas, contactos y citas, consulta la disponibilidad y recibe un evento firmado en cuanto pasa algo. Incluido en Pro y Business.
Descripción OpenAPI (JSON)Resumen
La URL base es https://remuteai.com/api/v1. Las peticiones y las respuestas son JSON. Cada consulta se limita al espacio de trabajo al que pertenece la clave.
La API está disponible en los planes Pro y Business. Con una clave de un espacio Gratis recibes un error 403 plan_required.
curl "https://remuteai.com/api/v1/calls?limit=5" \
-H "Authorization: Bearer rk_live_YOUR_KEY"{
"data": [
{
"id": "a90c…",
"started_at": "2026-10-26T09:12:40+00:00",
"duration_seconds": 142,
"from_number": "+34600000000",
"language": "es",
"outcome": "booked",
"summary": "…",
"contact_id": "41b7…",
"agent_id": "9b54…"
}
],
"has_more": true,
"next_cursor": "MjAyNi0x…"
}Claves de API
Crea las claves en la app, en Configurar, Desarrolladores (propietarios y administradores). Una clave empieza por rk_live_ seguido de 32 letras y cifras, y se muestra una sola vez al crearla. Solo guardamos su hash SHA-256, así que no podemos enseñártela otra vez: si la pierdes, revócala y crea otra.
Envíala en la cabecera Authorization: Authorization: Bearer rk_live_… . Hay dos niveles de permisos.
- read: acceso de solo lectura a todos los endpoints GET.
- read_write: lo mismo, y además crear y editar contactos y citas y gestionar endpoints de webhook.
Una clave ausente, con formato incorrecto, desconocida o revocada devuelve 401 unauthorized; una clave read en una llamada de escritura, 403 insufficient_scope.
Endpoints
| Endpoint | Qué hace |
|---|---|
GET /me | La clave, sus permisos y su espacio de trabajo. |
GET /calls | Lista de llamadas, de más reciente a más antigua. |
GET /calls/{id} | Una llamada con transcripción, URL de grabación y los datos recogidos. |
GET /contacts, GET /contacts/{id} | Contactos. |
GET /appointments, GET /appointments/{id} | Citas. La lista acepta from y to (ISO 8601) para filtrar por hora de inicio. |
GET /availability | Huecos libres de los próximos 14 días, calculados igual que los usa el asistente. Opcional date=AAAA-MM-DD. |
POST /contacts, PATCH /contacts/{id} | Crea un contacto (teléfono en E.164; si el teléfono ya existe se actualiza ese contacto) o edita nombre, email, idioma y notas (clave read_write). |
POST /appointments, PATCH /appointments/{id} | Reserva una cita, o la cambia de hora, la cancela o la edita (clave read_write). Responde 409 slot_taken si la hora se solapa con otra cita. |
GET /webhooks, GET /webhooks/{id} | Tus endpoints de webhook. |
POST /webhooks | Crea un endpoint (clave read_write). Devuelve el secreto de firma una sola vez. |
DELETE /webhooks/{id} | Borra un endpoint (clave read_write). |
Cada escritura queda registrada en el registro de auditoría de tu espacio. Los cambios hechos por la API también disparan los eventos de webhook correspondientes (appointment.booked, appointment.changed, appointment.cancelled, contact.created).
Paginación, límites y errores
- Las listas (llamadas, contactos, citas) van de más reciente a más antigua. Usa limit (de 1 a 100, 25 por defecto) y pasa el valor de next_cursor como cursor para pedir la página siguiente. El cursor es opaco. Cuando has_more es false no hay más páginas.
- Límite de uso: 60 peticiones por minuto y clave. Si lo superas recibes 429 rate_limited con una cabecera Retry-After de 60 segundos.
- Los errores tienen la forma {"error": {"code": "…", "message": "…"}}. Códigos posibles: unauthorized (401), plan_required e insufficient_scope (403), not_found (404), method_not_allowed (405), invalid_request (400), limit_reached (409), rate_limited (429), internal_error (500), unavailable (503).
- Un espacio de trabajo puede tener hasta 10 endpoints de webhook.
Webhooks
Añade un endpoint en la app (Configurar, Desarrolladores) o con POST /webhooks. Elige los eventos que quieras o usa * para todos. Enviamos cada evento a tu URL como un POST con cuerpo JSON, y tu servidor lo confirma respondiendo con cualquier estado 2xx.
| Evento | Cuándo |
|---|---|
call.completed | Se ha guardado una llamada. Incluye resumen y resultado; no incluye la transcripción (pide la llamada por id). |
appointment.booked | Una cita nueva. |
appointment.changed | Cambió la hora de inicio, la de fin o el estado. |
appointment.cancelled | Se canceló una cita. |
contact.created | Un contacto nuevo. |
{
"id": "6f1c0a52-3b7e-4c1e-9a55-0d2c7b1d9e11",
"type": "appointment.booked",
"created_at": "2026-10-26T09:14:03.120Z",
"workspace_id": "c2a4…",
"data": {
"id": "8d3e…",
"starts_at": "2026-10-28T09:00:00+00:00",
"ends_at": "2026-10-28T09:30:00+00:00",
"status": "scheduled",
"contact_id": "41b7…",
"call_id": "a90c…",
"notes": null,
"created_at": "2026-10-26T09:14:03.100+00:00"
}
}curl -X POST https://remuteai.com/api/v1/webhooks \
-H "Authorization: Bearer rk_live_YOUR_READ_WRITE_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/remute-hook","events":["call.completed","appointment.booked"]}'El id del evento es el mismo que la cabecera webhook-id. La entrega es «al menos una vez», así que usa el id para ignorar duplicados.
Verificar la firma
Cada petición lleva las tres cabeceras de Standard Webhooks (el esquema que usa Svix), así que cualquier librería de Svix o standardwebhooks la verifica.
- webhook-id: el id del evento.
- webhook-timestamp: tiempo Unix, en segundos, en que se firmó el intento.
- webhook-signature: v1, una coma y el base64 de un HMAC-SHA256. Se calcula sobre id.timestamp.cuerpo (los tres unidos con puntos) usando como clave la parte de tu secreto whsec_ decodificada de base64.
Usa el cuerpo en bruto, tal como llega: si lo conviertes a JSON y lo vuelves a serializar, los bytes cambian. Compara en tiempo constante y rechaza marcas de tiempo muy alejadas de ahora (sugerimos 5 minutos) para evitar repeticiones. Cada reintento se vuelve a firmar con una marca de tiempo nueva.
import { createHmac, timingSafeEqual } from "node:crypto";
// rawBody: the request body exactly as received (a string, not re-serialised JSON)
export function verify(rawBody, headers, secret) {
const id = headers["webhook-id"];
const ts = headers["webhook-timestamp"];
const sigs = headers["webhook-signature"];
if (!id || !ts || !sigs) return false;
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false; // replay window: 5 min
const key = Buffer.from(secret.replace(/^whsec_/, ""), "base64");
const expected = createHmac("sha256", key).update(`${id}.${ts}.${rawBody}`).digest();
return sigs.split(" ").some((entry) => {
const [version, sig] = entry.split(",");
if (version !== "v1" || !sig) return false;
const given = Buffer.from(sig, "base64");
return given.length === expected.length && timingSafeEqual(given, expected);
});
}El secreto de firma se devuelve una sola vez al crear el endpoint con la API, y propietarios y administradores también pueden verlo en la app.
Reintentos y límites de la entrega
- Esperamos hasta 8 segundos la respuesta. Un tiempo agotado, un error de red o cualquier estado fuera de 2xx cuenta como fallo. No seguimos redirecciones.
- Tras un intento fallido reintentamos a 1 minuto, 5 minutos, 30 minutos, 2 horas y 12 horas (seis intentos en total). Después la entrega se marca como fallida.
- Si 10 entregas seguidas agotan sus intentos, el endpoint se desactiva (verás «Desactivado tras fallos repetidos» en la app).
- Solo se aceptan URL https, con el puerto por defecto y sin credenciales. Se rechazan localhost, las direcciones privadas y de enlace local (10.x, 192.168.x, 127.x, 169.254.x, etc.) y los nombres que acaban en .local o .internal, al registrar el endpoint y de nuevo en cada envío.
Límites reales de hoy. Un trabajo programado busca reintentos pendientes cada minuto, así que un reintento puede llegar hasta un minuto después de su hora. Comprobamos la dirección tal como está escrita: un dominio público que apunte a una IP privada no se detecta, porque nuestros servidores no resuelven el DNS antes de enviar. No dependas de los webhooks para nada que no tolere un retraso.
Calendario (.ics)
En Configurar, Desarrolladores puedes crear una dirección de calendario privada. Pégala en Google Calendar (Otros calendarios, Desde URL), Outlook o Apple Calendar para ver allí tus citas de Remute.
- Es de un solo sentido: los cambios que hagas en tu calendario no vuelven a Remute.
- Incluye las citas de los últimos 30 días y todas las futuras, hasta 2.000.
- Las apps de calendario lo actualizan cada pocas horas, no al instante.
- Quien tenga la dirección puede leer el calendario, así que trátala como una contraseña. Tiene un límite de 60 peticiones por hora.
Preguntas
¿Funciona con Zapier, Make o n8n?
Sí, con sus pasos genéricos de webhook y HTTP: apunta un endpoint de webhook a la URL que te den, o consulta la API con una clave. Todavía no hay una app propia en sus catálogos.
¿Puedo crear citas o contactos con la API?
Todavía no. Hoy la API lee llamadas, contactos y citas y gestiona endpoints de webhook.
¿Qué planes incluyen la API?
Pro y Business. Los espacios Gratis reciben un error 403 plan_required.
¿Hay un entorno de pruebas?
No. Las claves son claves reales sobre los datos de tu propio espacio.
Construye sobre tu línea de teléfono.
Crea una cuenta gratis para explorar la app y pasa a Pro para conseguir una clave.
Crear cuenta gratis