Resumen del API

Todos los endpoints excepto GET /health requieren el header x-api-key con el valor de la variable de entorno API_KEY. La comparación es constante en tiempo (crypto.timingSafeEqual).

Endpoints

GET/healthsin auth
Healthcheck con disponibilidad de LibreOffice.
POST/templatesrequiere x-api-key
Sube una plantilla nueva (multipart). Slug único.
GET/templatesrequiere x-api-key
Lista las plantillas registradas.
GET/templates/:slugrequiere x-api-key
Descarga la plantilla original.
PUT/templates/:slugrequiere x-api-key
Reemplaza el .docx y/o el schema.
DELETE/templates/:slugrequiere x-api-key
Elimina la plantilla y su schema.
POST/renderrequiere x-api-key
Genera el documento (.docx o .pdf).

Formato de errores

Toda respuesta de error usa la siguiente envoltura:

{
  "error": {
    "code": "TEMPLATE_NOT_FOUND",
    "message": "Template 'factura' does not exist",
    "requestId": "5d8c1e4f-...",
    "details": { "slug": "factura" }
  }
}
  • code — string en MAYÚSCULAS, mapeable 1:1 al status HTTP.
  • message — humano-legible, no revela detalles internos.
  • requestId — uuid v4 generado por el server (o ecoado del header x-request-id si lo envías). Útil para rastrear en logs.
  • details — opcional, varía por error. Para validaciones (zod/ajv) trae los issues exactos.
Tabla completa de códigos
Ver /errors para la matriz HTTP-status × código y los casos en que se dispara cada uno.

Convenciones

  • JSON body en POST /render con límite de 1 MB.
  • Multipart form-data en POST/PUT /templates con límite configurable (MAX_UPLOAD_MB).
  • Stream binario en respuestas de descarga (GET /templates/:slug, POST /render).
  • Content-Disposition con filename ASCII-safe + filename* RFC 5987 para non-ASCII.
  • Request-Id ecoado en header x-request-id de cada respuesta.