Référence de l'API d'ingestion

Voici l'API HTTP neutre que chaque client intègre. Si vous construisez ou maintenez un package client, implémentez-le contre ce contrat. Toutes les routes sont en JSON sur HTTPS.

Chemin de base et versionnage

Les points d'entrée d'ingestion se trouvent sous /api/v1. Envoyez et acceptez application/json (le téléversement de sauvegarde est la seule exception en multipart/form-data).

Authentification

Chaque requête s'authentifie avec une clé d'API de projet (lm_...). Deux styles d'en-tête sont acceptés ; la forme bearer est recommandée :

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

La clé est mise en correspondance par son hachage SHA-256 et se résout vers un seul projet. Les échecs d'authentification renvoient 401 :

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

Limites de débit

  • Ingestion (/ingest, /logs, /dependencies, /heartbeats/*) : 300 requêtes par minute, indexées par jeton de projet.
  • Sauvegardes (/encryption-key, /backups*) : 60 requêtes par minute.

Dépasser une limite renvoie 429 Too Many Requests.

Quand l'ingestion est suspendue

Tant qu'un paiement reste dû sur l'abonnement de l'équipe, /ingest, /logs et /dependencies répondent 402 Payment Required et ne stockent rien :

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

Les pings de heartbeat continuent d'être enregistrés pendant cette période, pour qu'une équipe suspendue ne voie pas ses tâches planifiées passer pour cassées. Traitez un 402 comme un état à journaliser et à afficher, non comme une erreur à réessayer : il se lève de lui-même quand le paiement passe.

Un point d'entrée du coffre répond 402 dans la même période, avec son propre message : POST /backups. La lecture reste ouverte, matériel de clé compris, pour qu'une restauration de ce que vous avez déjà payé continue de fonctionner.

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

Lister, télécharger et supprimer une sauvegarde restent ouverts : une archive déjà stockée peut toujours être récupérée. Le point d'entrée de clé est celui à remarquer : il sert aussi le matériel dont monitor:restore a besoin, si bien que le déchiffrement côté client attend le paiement, là où le blob lui-même n'attend pas.


POST /api/v1/ingest, rapporter une exception

Rapporte une seule occurrence d'exception.

Corps de la requête

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"
  }
}

Règles des champs

ChampRequisType / limite
exception.classouichaîne, max 255
exception.messagenonchaîne, max 8192
exception.codenonquelconque
exception.filenonchaîne, max 1024
exception.linenonentier ≥ 0
exception.tracenontableau
context.environmentnonchaîne, max 100
context.releasenonchaîne, max 255 (un SHA hex active la corrélation de commit)
context.occurred_atnonchaîne, max 64 (date analysable)

Réponses

  • 202 Accepted: stockée :

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

  • 202 Accepted: quota dépassé, accusée mais non stockée :

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

  • 422 Unprocessable Entity: échec de validation.

issue_id est l'identifiant public de l'issue, un ULID. C'est la valeur que porte l'URL du tableau de bord, vous pouvez donc la journaliser et la coller dans la barre d'adresse. Ce n'est pas un numéro de ligne, et la réponse ne contient aucun compteur d'occurrences : ces nombres auraient indiqué à chaque projet combien d'exceptions la plateforme entière avait stockées.


POST /api/v1/logs, rapporter des logs applicatifs (lot)

Stocke un lot d'entrées de log. Conditionné à la fonctionnalité de plan logs.

Corps de la requête

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"
    }
  ]
}

Règles des champs

ChampRequisType / limite
logsouitableau, 1 à 500 entrées
logs.*.levelnonchaîne, max 20
logs.*.messageouichaîne, max 8192
logs.*.contextnontableau
logs.*.channelnonchaîne, max 100
logs.*.environmentnonchaîne, max 100
logs.*.releasenonchaîne, max 255
logs.*.logged_atnonchaîne, max 64

Réponses

  • 202 Accepted :

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

stored indique combien d'entrées ont réellement été enregistrées (un lot partiel est stocké lorsque le quota est presque plein).

  • 403 Forbidden: le plan n'inclut pas les logs :

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


POST /api/v1/dependencies, rapporter le composer.lock

Remplace l'instantané de dépendances du projet et déclenche un scan de vulnérabilités en arrière-plan.

Corps de la requête

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

Règles des champs

ChampRequisType / limite
packagesouitableau, 1 à 5000 entrées
packages.*.nameouichaîne, max 255
packages.*.versionouichaîne, max 100
packages.*.is_devnonbooléen

Réponse

  • 202 Accepted :

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


POST /api/v1/heartbeats/{slug}, pinguer une tâche planifiée

Signale qu'une tâche planifiée vient de s'exécuter. La requête ne porte aucun corps.

{slug} est normalisé en minuscules, chiffres et tirets. Le premier ping sur un slug inconnu enregistre le heartbeat non armé : il est consigné et n'alerte jamais tant qu'une période attendue n'a pas été définie dans le tableau de bord. Voir Heartbeats.

Réponses

  • 202 Accepted :

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

armed indique si une période attendue est définie, pour qu'un client distingue un ping consigné d'un ping surveillé.

  • 422 Unprocessable Entity : le slug se normalise en chaîne vide, ou le projet détient déjà le nombre maximal de heartbeats.

Points d'entrée du coffre de sauvegardes

Ceux-ci alimentent le coffre de sauvegardes chiffrées. Tous requièrent la fonctionnalité de plan backups. Tant qu'un paiement reste dû, POST /backups répond 402 Payment Required ; récupérer le matériel de clé, lister, télécharger et supprimer restent ouverts, pour que monitor:restore continue de fonctionner sur les archives déjà en place.

GET /api/v1/encryption-key

Sert le matériel de clé de l'équipe pour que le client puisse sceller et (avec la phrase secrète, en local) désenvelopper.

json
{
  "public_key": "base64...",
  "private_key_wrapped": "base64...",
  "kdf_salt": "base64..."
}
  • 403 si le plan n'inclut pas les sauvegardes.
  • 404 si l'équipe n'a pas configuré de clés de chiffrement.

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

Téléversement multipart/form-data d'un blob déjà chiffré.

ChampRequisRemarques
typeouidatabase ou files
namenonchaîne, max 255
fileouil'archive chiffrée
  • 201 Created renvoie les métadonnées de la sauvegarde stockée (même forme qu'une entrée de liste).
  • 403 si le plan n'inclut pas les sauvegardes.
  • 413 Request Entity Too Large si le téléversement dépasserait le quota de stockage :

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

GET /api/v1/backups/{uuid}

Diffuse le blob chiffré en téléchargement (<nom>.enc).

DELETE /api/v1/backups/{uuid}

Supprime la sauvegarde. Renvoie 204 No Content.


Récapitulatif des erreurs

StatutSignification
202 AcceptedIngéré (consultez stored pour savoir ce qui a été conservé).
201 CreatedSauvegarde téléversée.
204 No ContentSauvegarde supprimée.
401 UnauthorizedClé d'API manquante ou invalide.
402 Payment RequiredIngestion, matériel de clé et téléversements de sauvegarde suspendus tant qu'un paiement reste dû.
403 ForbiddenFonctionnalité absente du plan de l'équipe.
404 Not FoundClés de chiffrement non configurées (point d'entrée de clé).
413 Payload Too LargeQuota de stockage des sauvegardes dépassé.
422 Unprocessable EntityÉchec de validation.
429 Too Many RequestsLimite de débit dépassée.

Vous lisez la documentation Quiet Guard v1.0.