Servia API
Un endpoint, un mensaje por request. Tu plataforma de automatización (ManyChat u otra) envía cada mensaje del cliente a Servia; Servia responde con el texto para enviar y señales estructuradas para rutear tu flujo. El «cerebro» — servicios, productos, precios, horarios, equipo, pagos — se configura en tu dashboard, no en el flujo.
Quickstart
1. Consigue tu API key. Al suscribirte, tu key llega por email (se muestra una sola vez) junto con el acceso a tu dashboard.
2. Conecta tu flujo. En ManyChat: Actions → Make External Request, o instala la app de Servia y arrastra la action «AI Conversation Turn» (mapping pre-configurado).
POST https://api.serviaagent.com/v1/turn
Authorization: Bearer <TU_API_KEY>
Content-Type: application/json
{
"contact_id": "{{user_id}}",
"message": "{{last_text_input}}",
"contact_name": "{{first_name}}"
}3. Mapea la respuesta y rutea. En Response mapping: $.reply → tu campo de respuesta, $.route → tu campo de ruta, y los $.fields.* que uses. Un nodo Send Message envía la respuesta y un nodo Condition sobre la ruta decide qué sigue.
App de ManyChat (integración en 1 click)
La forma más simple: instalá la App «Servia» en tu cuenta de ManyChat, pegá tu API key una sola vez, y en el flow builder arrastrá el bloque «AI Conversation Turn». La URL, la autenticación, el body y el mapping de la respuesta ya vienen configurados — sin JSON, sin mapping manual.
El bloque deja en Custom User Fields listos para tus condiciones: ai_reply, ai_route,ai_status, ai_booking_date, ai_booking_time, ai_booking_service,ai_checkout_url, ai_order_id, ai_price, ai_score, ai_image_url. Opcionalmente podés forzar el modo (Agenda / Vende / Responde) y el idiomaen ese paso — una misma key sirve varios flujos.
Triggers (Servia inicia un flujo tuyo): Appointment booked (recién agendó:date, time, service, pax, client_name) · Appointment reminder due (2–24h antes de la cita, para que TU flujo mande el recordatorio:appointment_id, date, time, service, client_name, business_name) · Purchase completed (el pago de un checkout del asistente se confirmó: order_id, total, currency, product).
¿No querés instalar la app? Todo lo de abajo funciona igual con un External Request — es el mismo endpoint.
Autenticación
Cada request lleva Authorization: Bearer <API_KEY>. Las keys tienen el prefijo sk_servia_, se muestran una sola vez al emitirse y se almacenan hasheadas — si la pierdes, se rota desde el dashboard. Una key inválida responde 401; todo lo demás responde 200 siempre (ver «Errores»).
POST /v1/turn
Request
| Campo | Requerido | Descripción |
|---|---|---|
| contact_id | Sí | Id del contacto en tu plataforma ({{user_id}} en ManyChat). La memoria del asistente es por contacto: el cliente vuelve días después y el bot recuerda. |
| message | Sí | El texto del cliente (se acepta text como alias). |
| contact_name | No | Nombre visible del contacto; se usa para crear la ficha del cliente en el primer mensaje. |
| request_id | No | Clave de idempotencia. Si no la envías, un hash de (contacto, mensaje) deduplica los dobles disparos accidentales por una ventana corta — los reintentos de ManyChat son seguros. |
| mode | No | Modo del asistente para ESTE turno: book (agenda), sell (vende) o answer (solo responde). Pisa el modo por defecto de la key — así una sola key sirve varios flujos (uno de ventas, otro de agenda). Un valor inválido se ignora y se usa el default de la key. |
| language | No | Idioma para este turno: es o en. Pisa el idioma por defecto de la key; inválido → default. |
Response — el sobre siempre-200
{
"status": "ok",
"reply": "¡Listo! Te agendé el corte con Vale el jueves 21 a las 10:00.",
"route": "booked",
"fields": {
"booking_date": "2026-08-21",
"booking_time": "10:00",
"booking_service": "Corte de pelo"
},
"handoff": false,
"ms": 2841
}| Campo | Descripción |
|---|---|
| status | Salud del turno: ok · timeout · error · rate_limited · disabled · quota_exhausted. Distinto de ok ⇒ reply puede venir vacío: envía tu mensaje de respaldo. |
| reply | El texto a enviar al cliente, tal cual. |
| route | Adónde debe ir tu flujo (tabla abajo). Derivada de hechos observados — «booked» significa que la cita YA existe en el calendario, no que el modelo dijo que la agendó. |
| fields | Mapa plano de strings para mapear con JSON path (tabla abajo). Solo trae las keys relevantes al turno. |
| handoff | true si la conversación pasó a modo humano (Live Chat). |
| attachments | Fotos del catálogo propuestas este turno: [{ url, caption? }]. fields.image_url refleja la primera. |
| products | Productos recomendados este turno: [{ id, name, price, currency, image?, variant? }]. Mapeable por índice ($.products[0].image); fields.product_id refleja el primero. |
| ms | Milisegundos que tomó el turno (diagnóstico). |
Rutas (route)
| route | Qué hacer en tu flujo |
|---|---|
| continue | Nada especial: enviar reply y esperar el próximo mensaje (cada mensaje del cliente vuelve a disparar el flujo). |
| booked | La cita quedó agendada en el calendario. Confirmación, tags, CRM. |
| checkout | Se generó un link de pago este turno. El reply ya lo incluye; fields.checkout_url te lo da aparte si quieres tu propio botón. |
| purchased | El pago fue confirmado por el proveedor. Se emite EXACTAMENTE UNA VEZ por orden — dispara tu post-venta. Con la app instalada también llega como trigger. |
| handoff | Pasar a un humano (Live Chat de tu plataforma). El asistente deja de responder hasta que la conversación vuelva a automático. |
| fallback | El asistente no pudo generar respuesta y sirvió una disculpa estática. Puedes reemplazarla por tu propio mensaje de respaldo. |
Campos (fields.*)
| Key | Aparece cuando… |
|---|---|
| booking_date | …se agendó una cita (route=booked). Formato YYYY-MM-DD. |
| booking_time | …se agendó una cita. Formato HH:mm. |
| booking_service | …se agendó una cita: nombre del servicio. |
| booking_pax | …la cita es para más de una persona. |
| checkout_url | …se generó un link de pago (route=checkout). |
| order_id | …se generó un checkout o se confirmó una compra: id de la orden. |
| price | …hay checkout o compra: monto total. |
| currency | …hay checkout o compra: moneda (MXN, USD, ARS…). |
| product | …el turno giró en torno a un producto: su nombre. |
| product_id | …hay productos recomendados o vendidos: id del primero. |
| image_url | …el asistente propuso fotos: URL de la primera. |
| qualification_score | …en modo sell: puntaje de calificación del lead. |
| mode | …siempre: el modo efectivo con el que corrió el turno (book/sell/answer) — útil para depurar overrides por request. |
| language | …siempre: el idioma efectivo del turno (es/en). |
POST /v1/turn/dynamic
El mismo pipeline, con la respuesta en formato Dynamic Block de ManyChat (version: v2 + content.messages): úsalo en un bloque Dynamic y ManyChat renderiza directo, sin mapping. Qué envía:
- Galería de productos — si el turno recomendó productos con foto, llegan como carrusel de cards (Messenger e Instagram lo renderizan nativo; en canales sin cards ManyChat degrada a texto + fotos).
- Botón «Pagar ahora» — si el turno generó un checkout, debajo de la respuesta va un botón URL con el link de pago (y el reply conserva el link en texto para canales sin botones).
- Las señales de
/v1/turn(status,route,fields,handoff) viajan como keys extra que el renderer ignora. Si tu flujo necesita rutear, usa/v1/turncon response mapping.
Modos del asistente
Cada API key opera en un modo, configurable desde el dashboard: book (agenda citas), sell (vende productos y califica leads) o answer (responde preguntas del negocio, sin agendar ni vender). Idioma es o en. Los precios, el stock y la disponibilidad salen siempre de tu catálogo — el asistente jamás inventa un precio ni confirma una cita que no existe.
Límites y garantías
- Cada mensaje del cliente = 1 request = 1 mensaje de tu plan. Avisos por email al 80% y 100% del cupo.
- Al agotarse el cupo, según la política configurada en tu cuenta: pausa hasta el próximo período (default), upgrade automático de plan, o crédito prepagado. El sobreuso se factura a US$0.02 por mensaje.
- Respuesta siempre <10 s (deadline interno de 8.5 s; si se excede,
status=timeouty tu fallback responde). - Reintentos seguros: deduplicación por
request_idy por (contacto, mensaje); los mensajes de un mismo contacto se procesan en serie. - Rate limit de red: 300 requests/min. Los controles reales son por key (tope diario) y por contacto.
Errores
Filosofía: ManyChat no puede rutear respuestas no-200, así que todo request autenticado responde 200 y el resultado viaja en status. Solo dos excepciones, ambas señales de configuración: 401 (API key inválida o ausente) y 404 (el API no está habilitado para tu cuenta). Si contact_id o message faltan, recibes 200 con status=error y reply vacío.
Soporte
¿Dudas o un caso que no cubre esta página? Escríbenos a info@saviabot.com — respondemos en horas hábiles.