Developers · API v1

Conectá tu óptica
con cualquier sistema.

REST sobre HTTPS, JSON, Bearer token. Sin SDK obligatorio. Funciona desde cualquier lenguaje que tenga curl.

Autenticación

Todas las llamadas requieren el header Authorization: Bearer lk_live_xxx. Generá tu key desde /ajustes/api. La key se muestra una sola vez: copialá al crearla.

curl
curl https://lunara-publico.vercel.app/api/v1/clientes \
  -H "Authorization: Bearer lk_live_xxxxxxxxxxxxxxxxxxxxxxxx"

Las keys pueden tener scopes: read:clientes, read:recetas, read:inventario, *. Si la key no tiene el scope requerido, devolvemos 403.

GET /api/v1/clientes

Lista pacientes del tenant. Soporta búsqueda libre, paginación.

ParamTipoDescripción
qstring?Búsqueda libre (DNI, nombre, teléfono)
limitnumber?Máx 500. Default 50.
offsetnumber?Default 0.
Request
GET https://lunara-publico.vercel.app/api/v1/clientes?q=quispe&limit=20
Response 200
{
  "ok": true,
  "total": 137,
  "limit": 20,
  "offset": 0,
  "items": [
    { "dni": "70123456", "nombre": "María", "apellidos": "Quispe Mamani", "telefono": "+51999123456" }
  ]
}

GET /api/v1/recetas

Recetas RX del tenant. Filtrá por DNI del paciente.

ParamTipoDescripción
dnistring?Si se pasa, devuelve solo recetas de ese paciente
limitnumber?Máx 500. Default 50.
Request
GET https://lunara-publico.vercel.app/api/v1/recetas?dni=70123456
Response 200
{
  "ok": true,
  "total": 3,
  "items": [
    {
      "dni": "70123456",
      "fecha": "2026-05-12",
      "od": { "esfera": -2.50, "cilindro": -0.50, "eje": 90 },
      "oi": { "esfera": -2.25, "cilindro": -0.25, "eje": 85 },
      "add": 1.50
    }
  ]
}

GET /api/v1/inventario

Productos con stock. Útil para sincronizar con ERP o BI.

ParamTipoDescripción
stockMinnumber?Solo productos con stock ≥ X. Default 0.
limitnumber?Máx 1000. Default 100.
Request
GET https://lunara-publico.vercel.app/api/v1/inventario?stockMin=1&limit=200

Webhooks salientes

En /ajustes/api agregás una URL HTTPS y elegís qué eventos querés recibir. Cuando ese evento pasa, LUNARA hace POST con JSON.

ParamTipoDescripción
cliente.creadoeventoNuevo paciente registrado
venta.cerradaeventoVenta finalizada (TPV o proforma convertida)
taller.listoeventoOrden de taller cambió a estado "listo"
*eventoRecibir todos
POST de LUNARA hacia tu URL
POST https://tu-sistema.com/webhook
content-type: application/json
x-lunara-event: venta.cerrada

{
  "evento": "venta.cerrada",
  "tenant": "sicuani",
  "ts": "2026-06-15T18:42:11.000Z",
  "data": {
    "folio": "B001-1234",
    "cliente_dni": "70123456",
    "total": 690.00,
    "metodo_pago": "YAPE"
  }
}

Reintento: si tu endpoint responde 4xx/5xx, LUNARA no reintenta (mantenelo simple). Si tu sistema cae, vas a perder eventos — para auditoría usa también la API GET.

Errores

StatusSignifica
401Authorization faltante o key inválida
403Tu key no tiene el scope requerido
422Datos inválidos en el cuerpo
429Demasiados requests · esperá
500Error interno · escribinos al WA

Ejemplos en otros lenguajes

JavaScript / Node
const r = await fetch('https://lunara-publico.vercel.app/api/v1/clientes', {
  headers: { Authorization: 'Bearer lk_live_xxx' },
});
const { items } = await r.json();
Python
import requests
r = requests.get(
    'https://lunara-publico.vercel.app/api/v1/clientes',
    headers={'Authorization': 'Bearer lk_live_xxx'},
)
print(r.json()['items'])
PHP
$ch = curl_init('https://lunara-publico.vercel.app/api/v1/clientes');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization: Bearer lk_live_xxx']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$data = json_decode(curl_exec($ch), true);

Límites

  • Plan Básico: 1,000 requests/día · 1 webhook URL
  • Plan Pro: 10,000 requests/día · 5 webhooks
  • Plan Enterprise: sin límite · webhooks ilimitados
  • Vitalicia: equivalente a Enterprise
¿Necesitás algo más?

Si tu integración necesita un endpoint que todavía no expusimos, lo agregamos en menos de 1 semana. Hablanos directo.