Skip to content

Conventions REST — Public API ​

Méthodes HTTP ​

VerbeSémantique StormeoOS
GET /resourceListe paginée ({ data, total, limit, offset })
GET /resource/:idLecture d'une ressource (objet brut)
POST /resourceCréation — renvoie 201 Created + ressource
PATCH /resource/:idMise à jour partielle (à privilégier)
PUT /resource/:idRemplacement complet (même payload qu'un POST)
DELETE /resource/:idSuppression — renvoie 204 No Content

Règle interne R-005 : PATCH pour les mises à jour partielles, PUT réservé aux remplacements complets. Si un seul des deux est documenté pour une ressource, utilisez-le.

Pagination ​

Toutes les routes de listing acceptent :

Query paramTypeDéfautMax
limitint50100
offsetint0(illimité)

Les valeurs hors bornes sont clampées silencieusement (pas d'erreur). Pour parcourir un grand jeu :

GET /clients?limit=100&offset=0
GET /clients?limit=100&offset=100
GET /clients?limit=100&offset=200
...

Le champ total de la réponse permet de calculer le nombre de pages.

Format JSON ​

Encodage ​

  • Charset : UTF-8
  • Content-Type requête : application/json pour POST/PATCH/PUT (sinon 415 Unsupported Media Type)
  • Content-Type réponse : application/json; charset=utf-8
  • Taille max body : 10 MB (filet global Express)

Dates ​

Toutes les dates sont au format ISO 8601 UTC :

json
{
  "createdAt": "2026-04-27T10:30:00.000Z",
  "dueDate": "2026-05-15T00:00:00.000Z"
}

Acceptées en entrée :

  • ISO 8601 complet : 2026-04-27T10:30:00.000Z
  • Date seule : 2026-04-27 (interprétée comme 00:00:00 UTC)

Identifiants ​

  • Numériques (int) pour la plupart des ressources : id: 42
  • Chaînes (uuid ou similaire) pour : userId, certains tokens, traceId
  • Pas de slugs dans les identifiants externes (les slugs sont des champs de display)

Booléens ​

true / false JSON natifs. Pas de "yes", "1", 0.

Valeurs nulles ​

null est utilisé pour les champs explicitement vides. undefined (champ absent) signifie "ne pas modifier" en PATCH.

Filtrage ​

Certaines routes acceptent des filtres en query string. Exemples :

GET /websites?clientId=42
GET /tickets?status=open&priority=high
GET /invoices?clientId=42&since=2026-01-01

Le filtrage agencyId est toujours implicite et obligatoire (lié à la clé API). Aucun moyen de le bypasser.

Tri ​

Quand supporté, via le query param sort :

GET /clients?sort=name             # ascendant
GET /clients?sort=-createdAt       # descendant (préfixe -)

Les champs triables sont documentés sur chaque endpoint.

Validation Zod ​

Tous les bodies POST/PATCH/PUT sont validés avec Zod (safeParse). Les schémas dérivent de shared/schema.ts (table source de vérité), avec :

  • omit des champs système (id, createdAt, updatedAt, agencyId)
  • partial() pour les PATCH
  • safeParse (jamais parse) pour récupérer les erreurs sans throw

Les erreurs Zod sont retournées sous details: parsed.error.flatten(). Voir errors.md.

Multi-tenant ​

L'agencyId est résolu côté serveur depuis la clé API. Vous ne pouvez pas le passer en body ni le surcharger. Si vous tentez :

json
POST /clients
{ "name": "Acme", "agencyId": 999 }

Le champ agencyId est ignoré (omitted dans le schéma Zod) et écrasé par celui de votre clé.

Conséquences :

  • Toutes les listes ne renvoient que les ressources de votre agence
  • Toute lecture par ID hors agence → 404 (pas 403, pour ne pas leak l'existence)
  • Toute relation FK doit pointer vers une ressource de la même agence (vérifié côté serveur, sinon 400)

Webhooks émis (effets de bord) ​

Plusieurs mutations émettent un webhook si vous avez souscrit. Le format est documenté ici pour info, le détail dans ../webhooks/public-api-webhooks.md.

ActionEvent
POST /clientsclient.created
PATCH/PUT /clients/:idclient.updated
DELETE /clients/:idclient.deleted
POST /contactscontact.created
...(idem pour chaque ressource)

CORS ​

L'API publique n'expose pas de CORS pour les origins navigateur arbitraires. Elle est conçue pour un appel server-to-server. Si vous appelez depuis un navigateur, passez par un proxy serveur.

Versionning ​

  • Path versioning : /api/public/v1/*
  • Breaking changes → /v2. La v1 reste supportée 12 mois après la sortie de v2.
  • Additions non-breaking (nouveaux endpoints, nouveaux champs optionnels en réponse) : OK sans bump de version.
  • Voir changelog.md pour l'historique.

User-Agent recommandé ​

Identifiez votre intégration dans le User-Agent — utile pour le support :

User-Agent: AcmeAgency-Sync/1.2.0 (+https://acme.fr/integrations/stormeo)

Loggé dans public_api_logs.userAgent côté serveur.

StormeoOS API