API pública y Webhooks

Synvaxis expone una API REST en el namespace /api/v1/ y un sistema de webhooks salientes firmados con HMAC-SHA256 para que tus sistemas (CRM, ERP, app interna) reaccionen en tiempo real a eventos del bot.

Disponibilidad por plan #

API y webhooks están incluidos en todos los planes activos. La diferencia entre planes es el rate limit por clave:

CapacidadStarterProBusiness
API key con scope `read`
API key con scope `write`
Webhooks salientes
Rate limit por clave60 / min120 / min600 / min

> Las claves se generan desde Developers en el dashboard (sidebar). Cada clave se muestra una sola vez al crearla — guárdala antes de cerrar el modal.

Autenticación #

Todas las llamadas a /api/v1/* requieren el header:

http
Authorization: Bearer syn_<tu_clave>

Las claves comienzan con syn_ seguido de 40 caracteres hexadecimales. Sólo guardamos un hash sha-256; si la pierdes, debes revocarla y generar una nueva.

Headers que devuelve la API

Cada respuesta incluye:

http
x-request-id: 9f3c…           # útil para reportar incidencias a soporte

x-ratelimit-limit: 60 # techo en la ventana de 60s

x-ratelimit-remaining: 54

x-ratelimit-reset: 2026-04-27T12:34:56.000Z

Si superas el rate limit, recibes 429 con header retry-after en segundos.

Endpoints #

Todos los endpoints GET aceptan ?limit=N (1-200, default 50) y ?cursor= para paginación. La respuesta tiene la forma:

json
{ "data": [ … ], "next_cursor": "<id|null>" }
MétodoRutaScopeDescripción
`GET``/api/v1/_meta`readIdentidad de la clave + plan + rate limit
`GET``/api/v1/contacts`readLista contactos del tenant
`POST``/api/v1/contacts`writeCrea un contacto
`GET``/api/v1/conversations`readLista conversaciones (filtros: `platform`, `is_bot_active`)
`GET``/api/v1/conversations/{id}`readDetalle de una conversación
`GET``/api/v1/messages?conversation_id=…`readMensajes de una conversación
`GET``/api/v1/orders`readLista órdenes (filtros: `status`, `payment_status`, `conversation_id`)
`GET``/api/v1/orders/{id}`readDetalle de una orden
`GET``/api/v1/products`readLista productos (filtro: `is_active`)
`GET``/api/v1/products/{id}`readDetalle de producto (incluye `add_ons`, `knowledge_base`)
`GET``/api/v1/appointments`readLista citas (filtros: `status`, `from`, `to`)
`GET``/api/v1/appointments/{id}`readDetalle de cita

Ejemplo — listar contactos

bash
curl https://app.synvaxis.com/api/v1/contacts?limit=10 \

-H "Authorization: Bearer syn_abcd…"

json
{

"data": [

{ "id": "…", "phone": "+5215512345678", "name": "María", "status": "active", … }

],

"next_cursor": null

}

Ejemplo — crear contacto (write)

bash
curl -X POST https://app.synvaxis.com/api/v1/contacts \

-H "Authorization: Bearer syn_xyz…" \

-H "Content-Type: application/json" \

-d '{"phone":"+5215512345678","name":"María"}'

Forma de los errores

json
{

"error": {

"code": "rate_limited",

"message": "Rate limit exceeded (60 requests / 60s). Retry after 2026-04-27T12:34:56.000Z.",

"request_id": "9f3c…"

}

}

Códigos posibles: unauthorized (401), forbidden (403), not_found (404), invalid_request (400), conflict (409), rate_limited (429), internal (500).

Webhooks salientes (Business) #

En lugar de hacer polling, registra una URL HTTPS y Synvaxis te enviará un POST JSON cada vez que ocurra un evento que te interesa.

Eventos disponibles

EventoCuándo se dispara
`message.received`Llega un mensaje entrante (WhatsApp / Messenger)
`message.sent`El bot terminó de enviar una respuesta (un evento por turno)
`conversation.handed_off`Una conversación se escala a humano
`order.created`Se crea una orden (e-commerce)
`order.paid`Una orden se marca como pagada
`appointment.scheduled`Se agenda una cita
`appointment.cancelled`Se cancela una cita

Forma del payload

json
{

"event": "order.paid",

"data": {

"order_id": "…",

"external_id": "…",

"platform": "shopify",

"total": 1500,

"customer_phone": "+5215512345678",

"customer_name": "María",

"conversation_id": "…"

},

"timestamp": "2026-04-27T12:34:56.789Z",

"request_id": "8f1a…"

}

Headers que enviamos

http
X-Synvaxis-Signature: sha256=<hex>      # HMAC del body con tu secret

X-Synvaxis-Event: order.paid

X-Synvaxis-Request-Id: 8f1a…

X-Synvaxis-Delivery-Id: 7c2b… # útil para correlacionar con el log

X-Synvaxis-Attempt: 1 # número de intento (1..5)

User-Agent: Synvaxis-Webhook/1.0

Verificación de la firma

Calcula el HMAC-SHA256 del body crudo con tu secret (devuelto al crear el webhook) y compara con el header X-Synvaxis-Signature (sin el prefijo sha256=).

js
// Node.js / Express

import crypto from 'node:crypto';

app.post('/hooks/synvaxis', express.raw({ type: 'application/json' }), (req, res) => {

const sig = (req.headers['x-synvaxis-signature'] || '').replace(/^sha256=/, '');

const expected = crypto.createHmac('sha256', SYNVAXIS_SECRET).update(req.body).digest('hex');

if (sig.length !== expected.length || !crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {

return res.sendStatus(401);

}

const event = JSON.parse(req.body.toString());

// ... procesa event.event y event.data ...

res.sendStatus(200);

});

Reintentos

Si tu endpoint responde con un status fuera de 2xx o tarda más de 8 segundos, el dispatcher marca la entrega como fallida y la reencola con backoff exponencial:

IntentoEspera antes del retry
1 → 230 segundos
2 → 32 minutos
3 → 410 minutos
4 → 51 hora
5 → final6 horas

Tras 5 fallos consecutivos la entrega se marca failed definitivamente. Tras 20 fallos consecutivos del mismo endpoint, lo marcamos como roto y dejamos de enviar nuevas entregas hasta que actualices la URL.

> Puedes reintentar manualmente cualquier delivery desde el dashboard

> en Perfil → API & Webhooks → Deliveries.

Buenas prácticas #

  • Devuelve 200 lo antes posible (idealmente <2s) y haz el procesamiento real en background. Synvaxis no necesita esperar a que termines.
  • Verifica siempre la firma antes de confiar en el body. Sin verificación, cualquiera con tu URL puede inyectar eventos falsos.
  • Persiste request_id en tus logs — soporte usa ese ID para investigar incidencias.
  • Si reciben el mismo request_id dos veces, puedes hacer dedup. Stripe-style: el mismo evento puede reentregarse en condiciones de red.
¿Te fue útil?