Referencia de la API de ingesta

Esta es la API HTTP neutral que integra cada cliente. Si construye o mantiene un paquete cliente, impleméntelo contra este contrato. Todas las rutas son JSON sobre HTTPS.

Ruta base y versionado

Los puntos de entrada de ingesta se encuentran bajo /api/v1. Envíe y acepte application/json (la subida de copias de seguridad es la única excepción, en multipart/form-data).

Autenticación

Cada petición se autentica con una clave de API de proyecto (lm_...). Se aceptan dos estilos de encabezado; la forma bearer es la recomendada:

http
Authorization: Bearer lm_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
http
X-Monitor-Key: lm_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

La clave se coteja por su hash SHA-256 y se resuelve hacia un único proyecto. Los fallos de autenticación devuelven 401:

json
{ "message": "Missing API key." }
json
{ "message": "Invalid API key." }

Límites de tasa

  • Ingesta (/ingest, /logs, /dependencies, /heartbeats/*): 300 peticiones por minuto, indexadas por token de proyecto.
  • Copias de seguridad (/encryption-key, /backups*): 60 peticiones por minuto.

Superar un límite devuelve 429 Too Many Requests.

Cuando la ingesta está suspendida

Mientras quede un pago pendiente en la suscripción del equipo, /ingest, /logs y /dependencies responden 402 Payment Required y no almacenan nada:

json
{ "message": "Ingestion is suspended while a payment is outstanding. Your existing data stays readable in the dashboard." }

Los pings de heartbeat se siguen registrando durante ese periodo, para que las tareas programadas de un equipo suspendido no parezcan rotas. Trate un 402 como un estado que registrar y mostrar, no como un error que reintentar: se levanta solo cuando el pago pasa.

Un punto de entrada de la bóveda responde 402 en el mismo periodo, con su propio mensaje: POST /backups. La lectura sigue abierta, incluido el material de clave, para que una restauración de lo que ya ha pagado siga funcionando.

json
{ "message": "Backup uploads are suspended while a payment is outstanding. Existing backups stay downloadable." }

Listar, descargar y eliminar una copia siguen abiertos: un archivo ya almacenado puede recuperarse igualmente. El punto de entrada de clave es el que conviene notar: también sirve el material que necesita monitor:restore, de modo que el descifrado del lado del cliente espera al pago, mientras que el blob no.


POST /api/v1/ingest, reportar una excepción

Reporta una única ocurrencia de excepción.

Cuerpo de la petición

json
{
  "exception": {
    "class": "RuntimeException",
    "message": "Undefined array key \"id\"",
    "code": 0,
    "file": "/app/Http/Controllers/OrderController.php",
    "line": 88,
    "trace": [ { "file": "...", "line": 12, "function": "handle" } ]
  },
  "context": {
    "environment": "production",
    "release": "9f2c1ab3d4e5",
    "occurred_at": "2026-06-28T10:15:00+00:00"
  }
}

Reglas de los campos

CampoRequeridoTipo / límite
exception.classcadena, máx. 255
exception.messagenocadena, máx. 8192
exception.codenocualquiera
exception.filenocadena, máx. 1024
exception.linenoentero ≥ 0
exception.tracenoarray
context.environmentnocadena, máx. 100
context.releasenocadena, máx. 255 (un SHA hex activa la correlación de commit)
context.occurred_atnocadena, máx. 64 (fecha analizable)

Respuestas

  • 202 Accepted: almacenada:

``json { "message": "accepted", "stored": true, "issue_id": "01kw6tkrd8wjbfv2pktr7ssw43" } ``

  • 202 Accepted: cuota superada, confirmada pero no almacenada:

``json { "message": "accepted", "stored": false } ``

  • 422 Unprocessable Entity: fallo de validación.

issue_id es el identificador público de la incidencia, un ULID. Es el mismo valor que lleva la URL del panel, así que puede registrarlo y pegarlo en la barra de direcciones. No es un número de fila, y la respuesta no incluye ningún contador de ocurrencias: esos números habrían indicado a cada proyecto cuántas excepciones había almacenado toda la plataforma.


POST /api/v1/logs, reportar logs de aplicación (lote)

Almacena un lote de entradas de log. Condicionado a la funcionalidad de plan logs.

Cuerpo de la petición

json
{
  "logs": [
    {
      "level": "error",
      "message": "La passerelle de paiement a expiré",
      "context": { "order_id": 1234 },
      "channel": "payments",
      "environment": "production",
      "release": "9f2c1ab",
      "logged_at": "2026-06-28T10:15:00+00:00"
    }
  ]
}

Reglas de los campos

CampoRequeridoTipo / límite
logsarray, de 1 a 500 entradas
logs.*.levelnocadena, máx. 20
logs.*.messagecadena, máx. 8192
logs.*.contextnoarray
logs.*.channelnocadena, máx. 100
logs.*.environmentnocadena, máx. 100
logs.*.releasenocadena, máx. 255
logs.*.logged_atnocadena, máx. 64

Respuestas

  • 202 Accepted:

``json { "message": "accepted", "stored": 137 } ``

stored indica cuántas entradas se han registrado realmente (un lote parcial se almacena cuando la cuota está casi llena).

  • 403 Forbidden: el plan no incluye los logs:

``json { "message": "Application logs are not available on your current plan." } ``


POST /api/v1/dependencies, reportar el composer.lock

Sustituye la instantánea de dependencias del proyecto y desencadena un escaneo de vulnerabilidades en segundo plano.

Cuerpo de la petición

json
{
  "packages": [
    { "name": "laravel/framework", "version": "11.9.0", "is_dev": false },
    { "name": "phpunit/phpunit", "version": "11.2.0", "is_dev": true }
  ]
}

Reglas de los campos

CampoRequeridoTipo / límite
packagesarray, de 1 a 5000 entradas
packages.*.namecadena, máx. 255
packages.*.versioncadena, máx. 100
packages.*.is_devnobooleano

Respuesta

  • 202 Accepted:

``json { "message": "accepted", "dependencies": 142 } ``


POST /api/v1/heartbeats/{slug}, hacer ping a una tarea programada

Señala que una tarea programada acaba de ejecutarse. La petición no lleva cuerpo.

{slug} se normaliza a minúsculas, dígitos y guiones. El primer ping sobre un slug desconocido registra el heartbeat sin armar: queda consignado y nunca alerta hasta que se define un periodo esperado en el panel. Vea Heartbeats.

Respuestas

  • 202 Accepted:

``json { "message": "pong", "armed": true } ``

armed indica si hay un periodo esperado definido, para que un cliente distinga un ping consignado de uno vigilado.

  • 422 Unprocessable Entity: el slug se normaliza a una cadena vacía, o el proyecto ya contiene el número máximo de heartbeats.

Puntos de entrada de la bóveda de copias de seguridad

Estos alimentan la bóveda de copias de seguridad cifradas. Todos requieren la funcionalidad de plan backups. Mientras quede un pago pendiente, POST /backups responde 402 Payment Required; recuperar el material de clave, listar, descargar y eliminar siguen abiertos, para que monitor:restore siga funcionando sobre los archivos que ya tiene.

GET /api/v1/encryption-key

Sirve el material de clave del equipo para que el cliente pueda sellar y (con la frase secreta, en local) desenvolver.

json
{
  "public_key": "base64...",
  "private_key_wrapped": "base64...",
  "kdf_salt": "base64..."
}
  • 403 si el plan no incluye las copias de seguridad.
  • 404 si el equipo no ha configurado claves de cifrado.

GET /api/v1/backups

json
{
  "backups": [
    {
      "id": "9b1c...uuid",
      "type": "database",
      "name": "nightly",
      "size_bytes": 10485760,
      "checksum": "sha256...",
      "created_at": "2026-06-28T03:00:00+00:00"
    }
  ]
}

POST /api/v1/backups

Subida multipart/form-data de un blob ya cifrado.

CampoRequeridoObservaciones
typedatabase o files
namenocadena, máx. 255
fileel archivo cifrado
  • 201 Created devuelve los metadatos de la copia de seguridad almacenada (misma forma que una entrada de la lista).
  • 403 si el plan no incluye las copias de seguridad.
  • 413 Request Entity Too Large si la subida superaría la cuota de almacenamiento:

``json { "message": "Backup storage quota exceeded.", "used_bytes": 5012345678, "limit_bytes": 5000000000 } ``

GET /api/v1/backups/{uuid}

Transmite el blob cifrado como descarga (<nombre>.enc).

DELETE /api/v1/backups/{uuid}

Elimina la copia de seguridad. Devuelve 204 No Content.


Recapitulación de errores

EstadoSignificado
202 AcceptedIngerido (consulte stored para saber qué se ha conservado).
201 CreatedCopia de seguridad subida.
204 No ContentCopia de seguridad eliminada.
401 UnauthorizedClave de API ausente o inválida.
402 Payment RequiredIngesta, material de clave y subidas de copias suspendidos mientras quede un pago pendiente.
403 ForbiddenFuncionalidad ausente del plan del equipo.
404 Not FoundClaves de cifrado no configuradas (punto de entrada de clave).
413 Payload Too LargeCuota de almacenamiento de copias de seguridad superada.
422 Unprocessable EntityFallo de validación.
429 Too Many RequestsLímite de tasa superado.

Está leyendo la documentación Quiet Guard v1.0.