Clients — CRUD
Gestion des clients de l'agence (entités à qui sont rattachés sites web, factures, services, contacts).
Source : server/publicApi/routes/crm.ts:47-164. Schéma : insertClientSchema dans shared/schema.ts (champ agencyId omis — résolu serveur).
Vue d'ensemble
| Méthode | Path | Scope | Réponse |
|---|---|---|---|
GET | /clients | clients:read | 200 liste paginée |
GET | /clients/:id | clients:read | 200 objet client |
POST | /clients | clients:write | 201 client créé |
PATCH | /clients/:id | clients:write | 200 client mis à jour |
PUT | /clients/:id | clients:write | 200 client remplacé |
DELETE | /clients/:id | clients:delete | 204 |
Webhooks émis : client.created, client.updated, client.deleted.
Schéma Client
Champs principaux (consulter shared/schema.ts pour la liste complète) :
| Champ | Type | Création | Description |
|---|---|---|---|
id | int | — (auto) | ID auto-incrémenté |
agencyId | int | — (résolu serveur) | Agence propriétaire |
name | string | requis | Raison sociale |
email | string | null | optionnel | Email principal |
phone | string | null | optionnel | Téléphone |
address, city, postalCode, country | string | null | optionnel | Adresse postale |
siret, vatNumber | string | null | optionnel | Identifiants légaux (FR) |
notes | text | null | optionnel | Notes internes |
createdAt, updatedAt | ISO date | — (auto) | Timestamps |
Les champs exacts dépendent du schéma Drizzle de
clients. En cas de doute, faire unGET /clients/:idsur un existant pour voir la structure réelle.
GET /clients
Liste paginée des clients de l'agence.
Query params
| Param | Type | Défaut | Description |
|---|---|---|---|
limit | int | 50 | Max résultats (clamp 1-100) |
offset | int | 0 | Offset de pagination |
Réponse 200
{
"data": [
{ "id": 1, "name": "Acme SARL", "email": "contact@acme.fr", "createdAt": "2026-01-15T09:00:00.000Z" },
{ "id": 2, "name": "Beta Corp", "email": null, "createdAt": "2026-02-03T14:30:00.000Z" }
],
"total": 142,
"limit": 50,
"offset": 0
}Exemple
curl -H "x-api-key: spk_..." \
"https://beta.stormeo.io/api/public/v1/clients?limit=20&offset=0"GET /clients/:id
Lecture d'un client par ID.
Réponses
200: objet client400 ID invalide::idnon numérique404: client introuvable ou appartenant à une autre agence (404 par sécurité, pas 403)
Exemple
curl -H "x-api-key: spk_..." \
https://beta.stormeo.io/api/public/v1/clients/42POST /clients
Création d'un client.
Body (JSON)
Champs validés via insertClientSchema.omit({ agencyId: true }). Le champ agencyId envoyé dans le body est ignoré — résolu depuis la clé.
{
"name": "Acme SARL",
"email": "contact@acme.fr",
"phone": "+33 1 23 45 67 89",
"address": "12 rue des Lilas",
"city": "Paris",
"postalCode": "75011",
"country": "FR",
"siret": "12345678900012",
"vatNumber": "FR12345678900",
"notes": "Compte premium, contact direct CEO"
}Réponses
201: client créé (objet complet avecidgénéré)400 Données invalides: Zod a échoué, voirdetails403 PERMISSION_DENIED: scopeclients:writemanquant
Webhook émis
client.created avec payload { "client": <objet créé> }.
Exemple
curl -X POST \
-H "x-api-key: spk_..." \
-H "Content-Type: application/json" \
-d '{"name":"Acme SARL","email":"contact@acme.fr"}' \
https://beta.stormeo.io/api/public/v1/clientsPATCH /clients/:id
Mise à jour partielle. Seuls les champs présents dans le body sont modifiés.
Body
insertClientSchema.omit({ agencyId: true }).partial() — tous les champs sont optionnels.
{ "email": "nouveau@acme.fr" }Réponses
200: client mis à jour (objet complet)400 ID invalideouDonnées invalides404: client introuvable / hors agence403 PERMISSION_DENIED
Webhook émis
client.updated avec { "client": <objet mis à jour> }.
Exemple
curl -X PATCH \
-H "x-api-key: spk_..." \
-H "Content-Type: application/json" \
-d '{"phone":"+33 9 87 65 43 21"}' \
https://beta.stormeo.io/api/public/v1/clients/42PUT /clients/:id
Remplacement complet. Body identique à celui d'un POST (tous les champs requis sont à fournir).
Préférez
PATCHsauf si vous voulez explicitement remettre ànullles champs absents. Le comportement actuel délègue àstorage.updateClient(mêmes effets que PATCH côté code) ; PUT reste exposé pour conformité REST.
Exemple
curl -X PUT \
-H "x-api-key: spk_..." \
-H "Content-Type: application/json" \
-d '{"name":"Acme SARL (renommé)","email":"contact@acme.fr"}' \
https://beta.stormeo.io/api/public/v1/clients/42DELETE /clients/:id
Suppression définitive (hard delete) avec nettoyage des FK :
services.clientId→0(orphelins)websites.clientId→null- Le client est ensuite supprimé
Réponses
204 No Content: suppression réussie400 ID invalide404: client introuvable / hors agence403 PERMISSION_DENIED: scopeclients:deletemanquant
Webhook émis
client.deleted avec { "id": 42 }.
Exemple
curl -X DELETE \
-H "x-api-key: spk_..." \
https://beta.stormeo.io/api/public/v1/clients/42⚠️ Suppression irréversible. Pour les clients avec historique de facturation, considérez plutôt un PATCH avec un champ de désactivation (à venir :
archivedAt).