Conecta tus sistemas con la API de Luna Salud: activa tu token y haz tu primera consulta
La API de Luna Salud te permite consultar la información de tu cuenta de forma programática: citas, pacientes, notas clínicas, pagos, biomarcadores y resultados de laboratorio. Es una API REST principalmente de consulta, con escritura acotada: además de leer tus datos para reportes e integraciones, puedes registrar pacientes, actualizar sus datos de contacto, agendar citas y cancelarlas desde tu propio sistema. Nada se elimina por la API. Esta guía te lleva desde habilitar el acceso hasta tu primera solicitud exitosa.
¿Para qué sirve la API?
La API te da acceso directo a los datos de tu organización para usarlos fuera de Luna Salud. Algunos ejemplos:
Reportes personalizados
Conecta los datos de tu clínica con Google Sheets, Excel o Power BI y arma reportes a tu medida.
Conciliación de pagos
Consulta los pagos registrados con el endpoint /payments y concílialos con tu contabilidad o tu ERP.
Dashboards en tiempo real
Construye tableros con las métricas de citas, pacientes e ingresos de tu organización.
Seguimiento de laboratorio
Lee resultados de laboratorio y biomarcadores para alimentar sistemas de monitoreo clínico, con webhooks que te avisan cuando hay datos nuevos.
Agenda desde tu sistema
Consulta los horarios libres con /availability y agenda la cita con POST /appointments desde tu sitio web, app o CRM.
Registro de pacientes
Da de alta pacientes desde tu formulario o CRM con POST /patients y mantén su teléfono y dirección al día.
Antes de empezar: habilita el acceso a la API
El acceso a la API se habilita por organización y no viene activado de fábrica. Para poder generar tu token necesitas tres cosas:
- Acceso a la API habilitado para tu organización. Lo activa el equipo de Luna Salud; pídelo por WhatsApp y te lo habilitamos.
- Rol de Administrador. Solo los administradores pueden ver y generar el token de acceso.
- Tu token. Cada administrador tiene el suyo y se genera al entrar a Herramientas de Desarrollo — te enseñamos dónde en la siguiente sección.
¿No ves la pestaña «Herramientas de Desarrollo»?
Esa pestaña solo aparece cuando eres administrador y la API está habilitada para tu organización. Si eres administrador y no la ves en Cuenta → Organización, la API aún no está activada para tu clínica: escríbenos por WhatsApp y la habilitamos.
Si alguien de tu equipo intenta usar la API sin que esté habilitada, recibirá un error 403 con el mensaje «El acceso a la API no está habilitado para esta organización».
Activa tu token de acceso, paso a paso
Inicia sesión como administrador
Entra a account.lunahealth.app con una cuenta que tenga rol de Administrador.
Abre Herramientas de Desarrollo
Ve a Cuenta → Organización y entra a la pestaña Herramientas de Desarrollo. Ahí vive todo lo relacionado con la API: tu token, la documentación y la configuración de webhooks.
Ubica tu token
En la sección Token de Acceso de Luna Health ya está tu token: Luna Salud lo genera al abrir esta pestaña. Si ves el botón «Obtener Token de Acceso», púlsalo para generarlo.
Muéstralo y cópialo
Pulsa «Mostrar Token» y luego «Copiar al Portapapeles». Guárdalo en un lugar seguro (un gestor de secretos o las variables de entorno de tu servidor).
Utiliza esta clave para autorizar en el servicio API de Luna Health.
Tu token vence a los 90 días
Cada token es válido por 90 días. Cuando expira, tus solicitudes empiezan a devolver un error 401 ({"error":"Unauthorized"}). La solución es regenerarlo desde esta misma pantalla y actualizar tus integraciones con el token nuevo.
Regenerar invalida el token anterior al instante. Cualquier sistema que siga usando el token viejo dejará de funcionar en ese momento, así que planea el cambio.
Autentícate: tu primera solicitud
Todas las solicitudes van a la misma URL base:
https://account.lunahealth.app/apiY todas requieren tu token en el encabezado Authorization con el prefijo Bearer. Esta solicitud lista tus pacientes y es perfecta para verificar que todo funciona:
# Tu primera solicitud: listar pacientes
curl "https://account.lunahealth.app/api/patients?rowsPerPage=5&page=0" \
-H "Authorization: Bearer TU_TOKEN_DE_ACCESO"Si recibes un 200 OK con un JSON como este, ya estás dentro:
{
"items": [
{
"id": "pat456",
"first_name": "María",
"last_name": "García",
"email": "maria@ejemplo.com"
}
],
"meta": { "totalRowCount": 128, "page": 0, "rowsPerPage": 5 }
}Si en cambio recibes un 401 o un 403, salta a la sección de errores comunes más abajo: ahí está el significado exacto de cada mensaje y cómo resolverlo.
Endpoints disponibles
La mayoría de los endpoints son de consulta (método GET); los que escriben datos están marcados con su método. Todos devuelven JSON y siempre están limitados a tu organización: nunca verás ni modificarás información de otra clínica, y los endpoints de pacientes jamás exponen cuentas del personal.
| Endpoint | Qué devuelve | Filtros y parámetros |
|---|---|---|
| /appointments | Citas de tu organización. | from, to (fecha ISO), status (NEW, PENDING, CONFIRMED, COMPLETED, CANCELED), patientId, rowsPerPage (5–200), page, sortDir |
| /availability | Horarios libres de un profesional de salud para un servicio en un día. | staffId, serviceId, date (AAAA-MM-DD) obligatorios; locationId |
| POST /appointments | Agenda una cita presencial para un paciente existente. Requiere permiso de escritura. | patientId, staffId, serviceId, startTime obligatorios; locationId, reasonForVisit |
| POST /appointments/{id}/cancel | Cancela una cita. No se puede cancelar una cita completada o marcada como inasistencia. Requiere permiso de escritura. | notifyPatient (opcional, false por omisión) |
| /staff | Profesionales de salud que se pueden agendar: ID, nombre, apellido y título. | serviceId, rowsPerPage, page |
| /services | Servicios de tu organización con su duración. | staffId, rowsPerPage, page |
| /patients | Directorio de pacientes. | active, query (coincidencia exacta de nombre, apellido o correo), rowsPerPage (5–200), page, sortDir |
| POST /patients | Registra un paciente nuevo. Requiere permiso de escritura. | first_name, last_name obligatorios; phone, email, curp, birthdate, gender |
| PATCH /patients/{id} | Actualiza el teléfono y la dirección de un paciente. Requiere permiso de escritura. | phone, address (address_line1, address_line2, city, state, postal_code, country) |
| /patient | Perfil básico de un paciente. | id (obligatorio) |
| /patient-charts | Notas clínicas y expediente estructurado: consultas, signos vitales, alergias, diagnósticos y procedimientos. | patientId (obligatorio) |
| /biomarkers | Biomarcadores de un paciente, con conteos por estado. | patientId (obligatorio), start_date, end_date, status (OPTIMAL, ACCEPTABLE, CRITICAL, IN_VERIFICATION), page, limit (1–100) |
| /lab-tests | Estudios de laboratorio de un paciente. | patientId (obligatorio), start_date, end_date, page, limit (1–100) |
| /lab-test-biomarkers | Biomarcadores de un estudio específico, con valores, unidades y rangos de referencia. | labTestId (obligatorio) |
| /payments | Pagos (recibos) de tu organización. | from, to, status (PAID, PENDING, CANCELED, REFUNDED), paymentMethod (CARD, BANK, CASH, INSURANCE, OTHER), patientId, rowsPerPage (5–200), page, sortDir |
| /payment | Un pago específico. | id (obligatorio) |
| /webhooks/config | La configuración de webhooks de tu organización (nunca incluye la clave secreta). | — |
Referencia técnica completa
Cada endpoint tiene su esquema de respuesta detallado, todos los parámetros y ejemplos de código en Node.js y Python en docs.lunasalud.mx. Este artículo es la guía de arranque; la referencia es esa.
Agenda citas desde tu sistema
Con dos solicitudes puedes ofrecer horarios reales y reservar la cita: primero consultas los horarios libres y luego agendas el que elija tu paciente. Las citas aparecen al instante en el calendario de tu clínica.
Necesitas una clave con permiso de escritura
Las claves generadas antes de que existiera la escritura son de solo lectura. Si al agendar recibes un 403 con el mensaje «Esta clave de API es de solo lectura», un administrador debe pulsar «Regenerar Token de Acceso» en Herramientas de Desarrollo. La clave nueva ya incluye permiso de escritura; recuerda actualizarla en tus integraciones.
Ten a la mano los IDs
Necesitas el ID del paciente, del profesional de salud y del servicio. Los encuentras con /patients, /staff y /services (o en las respuestas de /appointments: staffs[].id, service.id, location.id). Si el paciente es nuevo, regístralo antes con POST /patients.
Consulta los horarios libres
Pide a /availability los horarios de un día. Ya descuenta citas existentes, tiempo bloqueado y la anticipación mínima de tu clínica, y cada horario dura lo que dura el servicio.
Agenda el horario elegido
Envía el start_time del horario a POST /appointments. La hora de fin se calcula sola con la duración del servicio.
# Horarios libres del 20 de octubre de 2026
curl "https://account.lunahealth.app/api/availability?staffId=stf789&serviceId=srv001&date=2026-10-20" \
-H "Authorization: Bearer TU_TOKEN_DE_ACCESO"{
"date": "2026-10-20",
"timezone": "America/Mexico_City",
"slots": [
{ "start_time": "2026-10-20T10:00:00-06:00", "end_time": "2026-10-20T10:30:00-06:00" },
{ "start_time": "2026-10-20T10:30:00-06:00", "end_time": "2026-10-20T11:00:00-06:00" }
]
}# Agenda el horario de las 10:00
curl -X POST "https://account.lunahealth.app/api/appointments" \
-H "Authorization: Bearer TU_TOKEN_DE_ACCESO" \
-H "Content-Type: application/json" \
-d '{"patientId":"pat456","staffId":"stf789","serviceId":"srv001","startTime":"2026-10-20T10:00:00-06:00","reasonForVisit":"Revisión anual"}'Si todo está bien recibes un 200 con la cita creada, en el mismo formato que /appointments y con estado CONFIRMED.
Reglas al agendar por la API
- Solo citas presenciales con un profesional de salud y un servicio.
- La hora de inicio debe ser futura, estar dentro de la disponibilidad del profesional y estar libre. Si alguien la ocupó entre tu consulta y tu reserva, vuelve a pedir los horarios.
- El profesional debe ofrecer el servicio y estar visible en el calendario interno.
- No se envía confirmación ni recordatorios al paciente. Si tu sistema necesita avisarle, hazlo desde tu lado. Tu profesional de salud sí recibe la notificación en la plataforma.
Cancela una cita
Envía POST /appointments/{id}/cancel con una clave con permiso de escritura. Por omisión no se avisa al paciente; si quieres que reciba el mensaje de cancelación según la configuración de tu clínica, envía {"notifyPatient": true}. Repetir la solicitud no duplica la cancelación, y una cita completada o marcada como inasistencia ya no se puede cancelar.
# Cancela la cita y avisa al paciente
curl -X POST "https://account.lunahealth.app/api/appointments/abc123/cancel" \
-H "Authorization: Bearer TU_TOKEN_DE_ACCESO" \
-H "Content-Type: application/json" \
-d '{"notifyPatient":true}'Ejemplos prácticos
Citas de un mes, con su respuesta
# Citas de agosto 2026, 50 por página
curl "https://account.lunahealth.app/api/appointments?from=2026-08-01T00:00:00Z&to=2026-08-31T23:59:59Z&rowsPerPage=50&page=0" \
-H "Authorization: Bearer TU_TOKEN_DE_ACCESO"{
"items": [
{
"id": "abc123",
"status": "CONFIRMED",
"title": "Consulta general",
"start_time": "2026-08-15T10:00:00.000Z",
"end_time": "2026-08-15T10:30:00.000Z",
"telemedicine": false,
"patient": { "id": "pat456", "first_name": "María", "last_name": "García" },
"staffs": [{ "id": "stf789", "first_name": "Ana", "last_name": "López" }],
"service": { "id": "srv001", "name": "Consulta general" },
"location": { "id": "loc001", "name": "Consultorio Roma Norte" }
}
],
"meta": { "totalRowCount": 42, "page": 0, "rowsPerPage": 50 }
}Pagos con tarjeta del mes
# Pagos pagados con tarjeta en agosto 2026
curl "https://account.lunahealth.app/api/payments?from=2026-08-01T00:00:00Z&to=2026-08-31T23:59:59Z&status=PAID&paymentMethod=CARD" \
-H "Authorization: Bearer TU_TOKEN_DE_ACCESO"Biomarcadores críticos de un paciente
# Solo los biomarcadores en estado crítico
curl "https://account.lunahealth.app/api/biomarkers?patientId=pat456&status=CRITICAL" \
-H "Authorization: Bearer TU_TOKEN_DE_ACCESO"Límites y paginación
- 120 consultas y 40 escrituras por minuto por usuario. Son límites independientes: tus consultas no consumen el cupo para agendar. Si te pasas, recibirás un 429; cada respuesta trae los encabezados
X-RateLimit-RemainingyX-RateLimit-Reset, y un rechazo traeRetry-Aftercon los segundos a esperar. - Paginación en todos los listados. Usa
page(empieza en 0) conrowsPerPage(5–200 en citas, pacientes y pagos) olimit(1–100 en biomarcadores y estudios de laboratorio). El total viene enmeta. - La paginación profunda está limitada. Si
page × rowsPerPagesupera 10,000, recibirás un 400. No es un capricho: en lugar de recorrer miles de páginas, acota confrom/too los filtros de fecha y recorre ventanas más pequeñas.
El patrón recomendado para sincronizar datos
Recorre por ventanas de fecha (por ejemplo, semana por semana con from y to) en lugar de paginar todo el histórico de golpe. Es más rápido, no choca con el límite de paginación y te permite reanudar donde te quedaste.
Errores comunes y cómo resolverlos
Los errores llegan con su código HTTP y un mensaje claro. Estos son los que verás con más frecuencia:
| Código | Mensaje | Cómo resolverlo |
|---|---|---|
| 401 | {"error":"Unauthorized"} |
El token no es válido. Revisa, en este orden: que envías Authorization: Bearer TU_TOKEN (con el prefijo Bearer y un espacio); que no pasaron sus 90 días; que nadie lo regeneró después de que lo copiaste; y que su dueño sigue siendo administrador activo. En cualquiera de esos casos, copia o regenera el token en Herramientas de Desarrollo. |
| 403 | «El acceso a la API no está habilitado para esta organización.» | Tu organización aún no tiene la API activada. Escríbenos por WhatsApp para habilitarla. |
| 404 | «Paciente no encontrado.» / «Recurso no encontrado.» | El ID no existe o pertenece a otra organización. Verifica que el ID venga de una consulta previa a tu propia cuenta. |
| 400 | «El desplazamiento de paginación es demasiado grande.» | Superaste el límite de 10,000 registros de profundidad. Acota con filtros de fecha en lugar de paginar tan profundo. |
| 429 | «Límite de solicitudes excedido.» | Superaste el límite por minuto (120 consultas o 40 escrituras). Espera los segundos que indica Retry-After y reintenta. |
| 403 | «Esta clave de API es de solo lectura. Pide a un administrador que regenere la clave para habilitar la escritura.» | Tu clave es anterior a la escritura. Un administrador debe regenerarla en Herramientas de Desarrollo. |
| 400 | «Esta cita ya no se puede cancelar porque se completó o se marcó como inasistencia.» | Al cancelar con POST /appointments/{id}/cancel: la cita ya ocurrió. Si necesitas corregirla, hazlo desde la plataforma. |
| 400 | «Este horario está fuera de la disponibilidad del profesional. Por favor elige un horario disponible.» | El horario no está en la disponibilidad o ya se ocupó. Vuelve a consultar /availability y elige otro. |
| 400 | «La hora de inicio de la cita debe ser en el futuro.» | Enviaste una hora que ya pasó. Revisa la fecha y que startTime incluya el desfase horario, por ejemplo -06:00. |
| 400 | «Este profesional de salud no ofrece el servicio seleccionado.» | El servicio no está asignado a ese profesional. Elige otro servicio o asígnaselo desde la plataforma. |
| 409 | «Ya existe un paciente con estos datos en tu organización.» | Al registrar con POST /patients: ya hay un paciente con ese correo, o con el mismo nombre y fecha de nacimiento. Usa su ID existente. |
Webhooks: entérate sin preguntar
Además de consultar la API, puedes configurar un webhook para que Luna Salud avise a tu servidor cuando haya datos nuevos, en lugar de estar consultando cada cierto tiempo. Hoy los avisos son de estudios de laboratorio: lab_test.processed cuando se procesa un estudio y lab_test.failed si su procesamiento falla.
Sucede algo en Luna Salud
Se procesa un estudio de laboratorio de un paciente
Luna Salud te notifica
Enviamos un POST a la URL que configuraste, firmado con tu clave secreta
Tu sistema reacciona
Consulta el detalle con la API y actualiza tus tableros o alertas
La configuración vive en la misma pestaña de Herramientas de Desarrollo, en la sección Configuración de Webhook:
X-Luna-Signature: la firma HMAC-SHA256 (hexadecimal) del cuerpo JSON con tu clave secreta. Calcúlala en tu servidor y compárala para confirmar que el aviso viene de Luna Salud. Cada aviso se envía una sola vez, sin reintentos: si tu servidor no responde, consulta los datos con la API. Usa «Probar Webhook» para mandar un evento de prueba antes de conectar nada en producción.Puedes consultar tu configuración actual (URL, eventos suscritos y estado) con GET /webhooks/config. Por seguridad, ese endpoint nunca devuelve la clave secreta; los cambios de configuración se hacen siempre desde la plataforma, no por la API.
Seguridad de tu token
Tu token da acceso a la información de toda tu organización, incluyendo datos clínicos de pacientes, y si tiene permiso de escritura también puede registrar pacientes y agendar o cancelar citas. Trátalo como una contraseña:
- Nunca lo pongas en código del navegador, apps móviles ni repositorios públicos como GitHub.
- Nunca lo compartas por WhatsApp, correo o chat, ni con proveedores que no lo necesiten.
- Nunca lo escribas directo en el código: úsalo desde variables de entorno o un gestor de secretos en tu servidor.
¿Se filtró tu token?
Regenéralo de inmediato en Cuenta → Organización → Herramientas de Desarrollo con «Regenerar Token de Acceso». El token filtrado queda invalidado al instante y solo el nuevo seguirá funcionando.
Y si un administrador deja tu clínica, se archiva su cuenta o pierde el rol de Administrador, su token deja de funcionar solo. Otro administrador debe darle a tu integración un token nuevo.
Preguntas frecuentes
¿Por qué no veo la pestaña Herramientas de Desarrollo en mi cuenta?
El acceso a la API se habilita por organización y la pestaña solo aparece para administradores con la API activada. Si eres administrador y no la ves en Cuenta → Organización, la API aún no está habilitada para tu clínica: escríbenos por WhatsApp y la activamos.
¿Mi token de API expira?
Sí. Cada token es válido por 90 días. Al expirar, tus solicitudes devuelven un error 401 (Unauthorized); genera uno nuevo con Regenerar Token de Acceso en Herramientas de Desarrollo y actualiza tus integraciones con el token nuevo.
¿Puedo crear o modificar citas y pacientes desde la API?
Sí, de forma acotada. Puedes registrar pacientes (POST /patients), actualizar su teléfono y dirección (PATCH /patients/{id}), agendar citas presenciales (POST /appointments) y cancelarlas (POST /appointments/{id}/cancel). Necesitas una clave con permiso de escritura: si la tuya es anterior, regenérala en Herramientas de Desarrollo. Por ahora no se pueden reagendar ni eliminar citas o pacientes por la API; eso se hace desde la plataforma.
¿Cuántas solicitudes puedo hacer a la API?
Hasta 120 consultas y 40 escrituras por minuto por usuario, con límites independientes. Si superas el límite recibirás un error 429 con el encabezado Retry-After; espera esos segundos y reintenta. Para volúmenes grandes, recorre los datos por ventanas de fecha con los filtros from y to en lugar de paginar todo el histórico de golpe.
¿Qué hago si mi token se filtró o alguien más lo conoce?
Regenéralo de inmediato en Cuenta → Organización → Herramientas de Desarrollo con Regenerar Token de Acceso. El token anterior queda invalidado al instante y solo el nuevo funcionará; actualiza tus integraciones para no quedarte sin acceso.
¿Listo para construir?
La referencia técnica completa tiene el esquema de cada endpoint con todos los parámetros y ejemplos de código en Node.js y Python.


