Galmia
Documentación de la API
galmia.ai →

API de Galmia

Con esta API puedes enviar a Galmia los datos de un formulario desde tu propio sistema: tu sitio web, tu CRM, tu app o cualquier proceso que ya tengas andando. Lo que entra por acá llega igual que si la persona hubiera llenado el formulario en la web de Galmia: queda el registro, se crea el lead, el negocio recibe su aviso y la recepcionista IA entra a trabajar.

Está escrito para que lo lea quien programa la integración. No hace falta conocer Galmia por dentro.

Qué necesitas antes de empezar

  • Una clave de API. La genera el dueño de la cuenta desde el panel, en Configuración → API y claves.
  • El identificador del formulario al que vas a enviar los datos. También está en el panel, y la API te lo puede listar.

1. Dirección y formato

QuéValor
Basehttps://api.agendario.cl/api/public/v1/
FormatoJSON en el cuerpo y en la respuesta (Content-Type: application/json)
AutenticaciónHeader Authorization: Bearer <tu-clave>

El dominio de la API conserva el nombre anterior de la plataforma; es el correcto y no va a cambiar sin aviso previo.

Todas las respuestas correctas devuelven un objeto JSON. Los errores vienen siempre con la misma forma, descrita en la sección 7.


2. Autenticación

Cada llamada lleva tu clave en el header Authorization:

La clave se ve así: glm_live_ seguido de una cadena larga. En los ejemplos de esta guía va en la variable de entorno GALMIA_API_KEY, que es también la forma en que conviene tenerla en tu servidor: nunca escrita dentro del código.

export GALMIA_API_KEY="la-clave-que-te-dio-el-panel"

curl https://api.agendario.cl/api/public/v1/forms/ \
  -H "Authorization: Bearer $GALMIA_API_KEY"

Tres cosas que conviene saber de las claves:

  • Se muestran una sola vez. Al generarla, el panel te la enseña y después guarda únicamente su huella. Si la pierdes, no se recupera: se genera otra y se revoca la anterior.
  • Van en tu servidor, nunca en el navegador. Una clave en el HTML o en el JavaScript de tu sitio queda a la vista de cualquier visitante. Si lo que necesitas es capturar datos desde una página web, usa el formulario incrustable de Galmia, que está hecho para eso y no necesita clave.
  • Se pueden revocar en cualquier momento desde el mismo panel. La revocación es inmediata.

Permisos

Cada clave lleva los permisos que le dieron al crearla. Un endpoint al que le falta su permiso responde 403, aunque la clave sea válida.

PermisoPara qué sirve
forms:readListar formularios y consultar sus campos
forms:writeEnviar formularios

Conviene darle a cada integración solo lo que necesita: si una clave hecha para enviar formularios se filtra, lo máximo que alguien puede hacer con ella es enviar formularios.


3. Listar tus formularios

GET /api/public/v1/forms/

Requiere forms:read.

curl https://api.agendario.cl/api/public/v1/forms/ \
  -H "Authorization: Bearer $GALMIA_API_KEY"
{
  "data": [
    {
      "id": 42,
      "slug": "contacto-sitio-web",
      "name": "Contacto sitio web",
      "layout": "two-steps",
      "is_active": true
    }
  ]
}

Los dos sirven para referenciar el formulario y los endpoints aceptan cualquiera de los dos. Para guardar la referencia en tu código preferimos el id: el slug se puede cambiar a mano desde el panel, y el id no cambia nunca. (Renombrar el formulario ya no mueve su slug, así que esto dejó de ser una trampa, pero el id sigue siendo la referencia más segura.)


4. Ver los campos de un formulario

GET /api/public/v1/forms/{id-o-slug}/

Requiere forms:read. Te dice exactamente qué claves esperar en el envío, así no tienes que adivinarlas:

curl https://api.agendario.cl/api/public/v1/forms/42/ \
  -H "Authorization: Bearer $GALMIA_API_KEY"
{
  "data": {
    "id": 42,
    "slug": "contacto-sitio-web",
    "name": "Contacto sitio web",
    "layout": "two-steps",
    "is_active": true,
    "fields": [
      {
        "name": "servicio",
        "type": "select",
        "label": "¿Qué servicio te interesa?",
        "required": true,
        "options": ["Limpieza facial", "Depilación láser"]
      },
      { "name": "name", "type": "text", "label": "Nombre", "required": true },
      { "name": "whatsapp", "type": "phone", "label": "WhatsApp", "required": true }
    ]
  }
}

El name de cada campo es la clave que va en el envío. Los tipos posibles son text, email, tel, phone, select, textarea, checkbox, date y number.

Dos detalles del esquema:

  • name y whatsapp aparecen siempre, incluso si el negocio no los declaró como preguntas: son obligatorios en todo envío.
  • Un campo phone acepta además el código de país en una clave aparte, <campo>_countryCode. Si no lo mandas se asume +56.

5. Enviar un formulario

POST /api/public/v1/forms/{id-o-slug}/submissions/

Requiere forms:write.

curl -X POST https://api.agendario.cl/api/public/v1/forms/42/submissions/ \
  -H "Authorization: Bearer $GALMIA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: contacto-9f3c1a" \
  -d '{
    "fields": {
      "name": "Ana Soto",
      "whatsapp": "912345678",
      "whatsapp_countryCode": "+56",
      "email": "ana@example.com",
      "servicio": "Limpieza facial"
    },
    "source_url": "https://miclinica.cl/contacto",
    "utm": { "utm_source": "google", "utm_medium": "cpc" }
  }'
CampoObligatorioQué es
fieldssíObjeto con las respuestas. Las claves son los name del esquema, y los valores texto, número o booleano
fields.namesíNombre de la persona
fields.whatsappsíSu número de WhatsApp
source_urlnoPágina donde se originó el contacto
referrernoDe dónde venía
user_agentnoNavegador de la persona, si lo tienes
utmnoObjeto con utm_source, utm_medium, utm_campaign, utm_content, utm_term
timestampnoMomento del envío, como texto

Respuesta 201:

{
  "submission_id": "7c9f0b5e-1d2a-4f3b-8c7d-6e5f4a3b2c1d",
  "lead_id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
  "created_at": "2026-10-26T15:04:05.123456-03:00"
}

Guarda el submission_id: es la referencia del envío y lo que nos sirve para encontrarlo si algo no cuadra. El lead_id es el contacto en el embudo del negocio, por si quieres cruzarlo con tu propio sistema; en casos raros puede venir null, y eso no significa que el envío se haya perdido.

Qué pasa después del envío

Lo mismo que si la persona hubiera llenado el formulario en la web:

  1. Queda el registro del envío con todas sus respuestas.
  2. Se crea el lead en el embudo del negocio (o se actualiza el que ya existía para ese contacto).
  3. El negocio recibe su aviso por correo.
  4. Si la cuenta lo tiene configurado, sale el mensaje de WhatsApp al contacto y la recepcionista IA queda a cargo de la conversación.
  5. Si la cuenta tiene la Conversions API de Meta configurada, se envía el evento de conversión.

Es decir: un envío por API no es "solo guardar un dato". Dispara la misma operación que el formulario. Tenlo presente si estás importando datos históricos — para eso no uses esta API.


6. Idempotencia

Si tu proceso puede reintentar un envío (un timeout, una cola que repite), manda el header Idempotency-Key con un valor propio de ese envío:

Idempotency-Key: contacto-9f3c1a

La clave la eliges tú y puede tener el largo que quieras. Vale para ese formulario: la misma clave contra otro formulario es otro envío.

Cuando llega una clave de idempotencia que ya se usó en las últimas 24 horas, la API no crea nada nuevo y responde 200 con el envío original:

{ "submission_id": "7c9f0b5e-...", "duplicate": true }

Dos puntos sobre los que conviene ser claro: la ventana son 24 horas, no para siempre; y la protección es por clave de API, así que dos integraciones distintas pueden usar el mismo número de pedido sin pisarse.


7. Errores

Todos los errores tienen la misma forma:

{
  "error": {
    "code": "form_not_found",
    "message": "No encontramos un formulario activo con la referencia \"43\" en tu cuenta.",
    "details": {}
  }
}

Ramifica siempre por code, nunca por message: el texto puede cambiar, el código no.

HTTPcodeQué pasó y qué hacer
401invalid_api_keyFalta la clave, o está mal escrita, revocada o vencida. Revisa el header o genera otra
403scope_missingLa clave es válida pero no tiene el permiso del endpoint. El mensaje dice cuál falta
404form_not_foundEl formulario no existe, está desactivado o no es de tu cuenta
400validation_errorFalta fields, o falta el nombre o el WhatsApp dentro de fields
429rate_limitedTe pasaste de tu cuota de llamadas. Espera los segundos del header Retry-After
429too_many_rejectedTe rechazamos demasiadas peticiones seguidas. No es tu cuota: la clave está mal o le falta el permiso. Arréglalo antes de reintentar
500internal_errorUn problema nuestro. Si se repite, escríbenos con la hora exacta

Un detalle a propósito: un formulario de otra cuenta responde 404, igual que uno que no existe. No hay forma de averiguar desde afuera qué formularios tienen las demás cuentas.


8. Límites de uso

Los límites son por clave, no por dirección IP, así que no te afecta que tus llamadas salgan todas del mismo servidor.

OperaciónLímite
Enviar formularios60 por hora, por clave
Lecturas (listar, ver campos)600 por hora, por clave
Peticiones rechazadas (401 y 403)60 por hora, por dirección IP

La última fila cuenta solo lo que rechazamos, y va por dirección IP en vez de por clave —cuando la clave no sirve, no hay clave que contar—. Una integración que funciona nunca la toca. Si la ves, el problema no es tu volumen: revisa la clave y sus permisos antes de seguir reintentando, porque mientras acumules rechazos esa dirección queda bloqueada aunque después mandes la clave buena.

Cada cuenta puede tener hasta 10 claves activas a la vez. Si necesitas una más, revoca alguna que ya no uses.

El límite de envíos es estrecho a propósito: cada envío manda correos y mensajes de WhatsApp reales, que el negocio paga. Si tu volumen legítimo es mayor, escríbenos y lo subimos para tu clave.

Al pasarte, la API responde 429 con el header Retry-After en segundos. Reintenta después de ese tiempo, de preferencia con una espera que vaya creciendo.


9. Versionado y cambios

La versión va en la ruta: /api/public/v1/.

Mientras siga siendo v1:

  • Podemos agregar campos a las respuestas y parámetros opcionales al cuerpo. Tu integración no debería romperse por un campo nuevo que no conoce, así que no valides que la respuesta tenga exactamente las claves de hoy.
  • No vamos a quitar ni renombrar campos existentes, ni a cambiar el significado de un code de error.

Si alguna vez hay un cambio que rompe el contrato, sale como v2 y te avisamos con al menos 60 días de anticipación, con la v1 andando en ese tiempo.


10. Checklist de integración

  • La clave vive en una variable de entorno del servidor, no en el código ni en el repositorio.
  • La clave tiene solo los permisos que esta integración necesita.
  • Guardas el id numérico del formulario, no el slug.
  • Mandas Idempotency-Key si tu proceso puede reintentar.
  • Manejas el 429 esperando lo que dice Retry-After.
  • Ramificas por error.code y no por el texto del mensaje.
  • Probaste un envío real y lo viste llegar al panel del negocio.

11. Contacto

Escríbenos a soporte@galmia.ai. Para que podamos ayudarte rápido, incluye:

  • El submission_id si lo tienes, o el prefijo de tu clave (los caracteres que el panel sigue mostrando, por ejemplo glm_live_a1b2c3).
  • La hora exacta del intento.
  • La petición que enviaste y la respuesta que recibiste.

Nunca nos mandes tu clave completa, ni por correo ni por WhatsApp. Con el prefijo nos alcanza para identificarla.