Pour vos outils
API & MCP
Votre salon, branché sur votre tableur, votre automatisation ou votre assistant IA. Une clé par outil, des droits choisis un par un, chaque appel inscrit au journal d'audit. Le planning reste le vôtre.
En trois gestes
01
Créez une clé
Au QG : Paramètres → Applications connectées → Nouvelle application. Réservé au propriétaire du salon.
02
Choisissez les droits
Lecture et écriture sont deux droits distincts. Un tableur de suivi n'a aucune raison d'annuler un rendez-vous.
03
Branchez
Copiez le jeton
pgo_…: il n'est affiché qu'une fois. Révocable en un clic, avec une date d'expiration si vous voulez.
Assistant IA
Le serveur MCP
Claude, Cursor ou n8n lisent votre planning et vos clients, et posent un rendez-vous à votre place — après vous l'avoir demandé. Les outils MCP portent exactement les noms des opérations plus bas, et l'assistant ne voit que ceux que la clé autorise.
- Adresse
https://pre-go.fr/api/v1/mcp- Transport
- HTTP « Streamable », sans état : un POST, une réponse JSON. Pas de flux SSE.
- Authentification
- En-tête
Authorization: Bearer pgo_…, le même jeton que l'API. - Protocole
- 2025-06-18 · 2025-03-26 · 2024-11-05
Claude Code
claude mcp add --transport http prego https://pre-go.fr/api/v1/mcp \
--header "Authorization: Bearer pgo_…"Claude Desktop et clients stdio
Par le pont mcp-remote, dans le fichier de configuration MCP du client :
{
"mcpServers": {
"prego": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://pre-go.fr/api/v1/mcp",
"--header",
"Authorization: Bearer pgo_…"
]
}
}
}Les connecteurs distants de claude.ai et de ChatGPT exigent une connexion OAuth : Pre-Go ne la propose pas encore. Passez par un client qui accepte un jeton en en-tête.
Tableurs, scripts, automatisations
L'API REST
Du JSON sur HTTPS, pour Zapier, Make, n8n, Google Sheets ou un script maison. Commencez par GET /me : il dit quel salon et quels droits porte la clé.
curl -H "Authorization: Bearer pgo_…" https://pre-go.fr/api/v1/meBase
https://pre-go.fr/api/v1Jeton
Authorization: Bearer pgo_…ouX-Api-Key. Jamais dans l'URL.Dates et heures
Dates
YYYY-MM-DD, heuresHH:mmdans le fuseau du salon. Instants en ISO 8601 UTC.Montants
Euros TTC, en nombres décimaux.
Réponses
{ "data": … }, plusmeta(count,limit,offset,hasMore) pour une liste paginée.Cadence
120 appels par minute et par adresse IP. Au-delà : 429 et en-tête
Retry-After.
Les droits
Une clé ne porte que les droits cochés à sa création — modifiables ensuite au QG. Les droits marqués sensible écrivent ou lisent des données personnelles.
shop:readSalon Nom, adresse, fuseau horaire, horaires d'ouverture.services:readPrestations Catalogue : prix, durées, catégories.staff:readÉquipe Barbiers du salon : nom, titre, réservable ou non.availability:readDisponibilités Créneaux libres d'une journée, par prestation et barbier.appointments:readRendez-vous — lecture sensibleLe planning, avec le nom et les coordonnées des clients.appointments:writeRendez-vous — écriture sensibleCréer, déplacer, confirmer, annuler un rendez-vous. Mêmes notifications que depuis le QG.customers:readClients — lecture sensibleFichier client : coordonnées, visites, chiffre d'affaires.customers:writeClients — écriture sensibleCréer une fiche client, modifier ses coordonnées.sales:readEncaissements sensibleTickets de caisse et chiffre d'affaires sur une période.sms:readSMS Consommation SMS : volumes par barbier, par type et par jour, pour refacturer. Ni numéro ni texte des messages.inventory:readStocks — lecture Produits, quantités en stock, seuils d'alerte, prix d'achat et historique des mouvements.inventory:writeStocks — écriture sensibleEnregistrer une livraison, une perte ou un inventaire ; créer un produit, modifier ses prix et ses seuils.
Les opérations
24 opérations, chacune disponible en HTTP et en outil MCP sous le même nom. Les écritures ont des effets réels : le client et le barbier peuvent recevoir un e-mail ou un SMS, comme depuis le QG.
Démarrer
GET/me— Qui suis-je ?whoami
Droit : aucun · lecture
Renvoie l'application connectée, son salon et ses droits (scopes). Aucun droit requis : à appeler en premier pour savoir ce que le jeton permet.
Aucun paramètre.
curl -H "Authorization: Bearer pgo_…" "https://pre-go.fr/api/v1/me"Réponse
{
"data": {
"app": {
"id": "app_x",
"name": "Mon tableur"
},
"shop": {
"id": 4,
"slug": "le-barbier",
"timezone": "Europe/Paris"
},
"scopes": [
"shop:read",
"appointments:read"
]
}
}Salon, prestations, équipe
GET/shop— Informations du salonget_shop
Droit : shop:read · lecture
Renvoie le salon lié au jeton : nom, adresse, contact, fuseau horaire (toutes les heures de l'API sont exprimées dans ce fuseau), horaires d'ouverture et lien de réservation en ligne.
Aucun paramètre.
curl -H "Authorization: Bearer pgo_…" "https://pre-go.fr/api/v1/shop"Réponse
{
"data": {
"id": 4,
"name": "Le Barbier",
"slug": "le-barbier",
"timezone": "Europe/Paris",
"businessHours": {
"monday": {
"open": "09:00",
"close": "19:00",
"closed": false
}
},
"bookingUrl": "https://pre-go.fr/sites/le-barbier/booking"
}
}GET/services— Catalogue des prestationslist_services
Droit : services:read · lecture
Liste les prestations du salon avec prix (en euros TTC), durée (en minutes) et catégorie. Par défaut, seules les prestations actives.
| Paramètre | Où | Type | Description |
|---|---|---|---|
| includeInactive | query | boolean,string | true pour inclure les prestations archivées. |
curl -H "Authorization: Bearer pgo_…" "https://pre-go.fr/api/v1/services"Réponse
{
"data": [
{
"id": 12,
"name": "Coupe homme",
"category": "Haircut",
"price": 25,
"discountPrice": null,
"durationMinutes": 30,
"bookableOnline": true,
"isActive": true
}
]
}GET/staff— Équipe du salonlist_staff
Droit : staff:read · lecture
Liste les barbiers (et membres du back-office) du salon. acceptsBookings indique qui peut recevoir des rendez-vous ; utilisez leur id comme staffId ailleurs.
| Paramètre | Où | Type | Description |
|---|---|---|---|
| includeInactive | query | boolean,string | true pour inclure les membres désactivés. |
curl -H "Authorization: Bearer pgo_…" "https://pre-go.fr/api/v1/staff"Réponse
{
"data": [
{
"id": "mbr_x1",
"firstName": "Karim",
"lastName": "B.",
"title": "Barber",
"acceptsBookings": true,
"isActive": true
}
]
}GET/availability— Créneaux libres d'une journéeget_availability
Droit : availability:read · lecture
Renvoie les créneaux libres d'une journée pour une prestation, tous barbiers confondus ou pour un barbier donné. Mêmes règles que la réservation en ligne : horaires, congés, rendez-vous existants, créneaux passés exclus. Utilisez un créneau renvoyé ici pour create_appointment.
| Paramètre | Où | Type | Description |
|---|---|---|---|
| date* | query | string | Jour voulu, YYYY-MM-DD, dans le fuseau du salon. |
| serviceId* | query | integer | Prestation (voir list_services). |
| staffId | query | string | Barbier précis (voir list_staff). Absent : tous les barbiers. |
curl -H "Authorization: Bearer pgo_…" "https://pre-go.fr/api/v1/availability"Réponse
{
"data": {
"date": "2026-10-02",
"slots": [
{
"startTime": "10:00",
"endTime": "10:30",
"staffId": "mbr_x1"
}
]
}
}Rendez-vous
GET/appointments— Rendez-vous sur une périodelist_appointments
Droit : appointments:read · lecture
Liste les rendez-vous entre deux dates incluses (92 jours au plus), triés par date puis heure. Filtres facultatifs : barbier, client, statut. Heures au format HH:mm dans le fuseau du salon ; startsAt est l'instant UTC exact.
| Paramètre | Où | Type | Description |
|---|---|---|---|
| from* | query | string | Premier jour, YYYY-MM-DD. |
| to* | query | string | Dernier jour inclus, YYYY-MM-DD. |
| staffId | query | string | |
| customerId | query | string | |
| status | query | string | Un ou plusieurs statuts séparés par des virgules : pending, scheduled, confirmed, in_progress, completed, cancelled, no_show. |
| limit | query | integer | (défaut : 200) |
| offset | query | integer | (défaut : 0) |
curl -H "Authorization: Bearer pgo_…" "https://pre-go.fr/api/v1/appointments"Réponse
{
"data": [
{
"id": "apt_9f2",
"date": "2026-10-02",
"startTime": "10:00",
"endTime": "10:30",
"status": "confirmed",
"staff": {
"id": "mbr_x1",
"name": "Karim B."
},
"service": {
"id": 12,
"name": "Coupe homme"
},
"customer": {
"id": "c81e",
"name": "Jean Dupont",
"email": "jean@example.com",
"phone": "+33612345678"
},
"price": 25
}
],
"meta": {
"count": 1,
"limit": 200,
"offset": 0,
"hasMore": false
}
}GET/appointments/{id}— Détail d'un rendez-vousget_appointment
Droit : appointments:read · lecture
Renvoie un rendez-vous, avec toutes ses lignes de prestation.
| Paramètre | Où | Type | Description |
|---|---|---|---|
| id* | chemin | string | Identifiant du rendez-vous. |
curl -H "Authorization: Bearer pgo_…" "https://pre-go.fr/api/v1/appointments/<id>"POST/appointments— Créer un rendez-vouscreate_appointment
Droit : appointments:write · écriture
Réserve un créneau pour un client. Mêmes garde-fous que la réservation en ligne : refus d'un créneau passé ou déjà pris (409 conflict). Sans staffId, le salon choisit le barbier selon sa règle d'attribution. Le rendez-vous est confirmé d'office. Par défaut le client reçoit sa confirmation (e-mail, et SMS si le salon l'a activé) et le barbier est prévenu, comme pour une réservation en ligne. Vérifiez d'abord le créneau avec get_availability.
| Paramètre | Où | Type | Description |
|---|---|---|---|
| date* | corps | string | Jour du rendez-vous, YYYY-MM-DD. |
| startTime* | corps | string | Heure de début, HH:mm, fuseau du salon. |
| serviceId* | corps | integer | |
| staffId | corps | string | Barbier voulu. Absent : n'importe quel barbier disponible. |
| customerId | corps | string | Client existant (voir list_customers). Sinon, renseignez customer. |
| customer | corps | objet { name, email, phone } | Coordonnées du client s'il n'a pas de fiche. Rattaché à une fiche existante si l'e-mail ou le téléphone correspond sans ambiguïté. |
| customerNotes | corps | string | Demande du client, visible par le barbier. |
| notifyCustomer | corps | boolean | false pour ne rien envoyer au client ni au barbier.(défaut : true) |
curl -X POST -H "Authorization: Bearer pgo_…" \
-H "Content-Type: application/json" -d '{…}' "https://pre-go.fr/api/v1/appointments"Réponse
{
"data": {
"bookingGroupId": "bkg_1",
"appointments": [
{
"id": "apt_9f2",
"date": "2026-10-02",
"startTime": "10:00",
"status": "confirmed"
}
]
}
}PATCH/appointments/{id}— Modifier un rendez-vousupdate_appointment
Droit : appointments:write · écriture
Déplace un rendez-vous (date, heure, barbier), change son statut ou ses notes. Passe par la même logique que le planning du QG : le barbier est prévenu d'un déplacement ou d'une annulation, la liste d'attente est sollicitée sur un créneau libéré. Attention : comme dans le QG, un déplacement n'est pas refusé s'il chevauche un autre rendez-vous — vérifiez get_availability avant. L'encaissement (statut completed) se fait au QG, pas ici. Pour annuler, préférez cancel_appointment.
| Paramètre | Où | Type | Description |
|---|---|---|---|
| id* | chemin | string | |
| date | corps | string | Nouveau jour, YYYY-MM-DD. |
| startTime | corps | string | Nouvelle heure de début, HH:mm. |
| staffId | corps | string | Nouveau barbier. |
| durationMinutes | corps | integer | |
| status | corps | scheduled | confirmed | no_show | cancelled | |
| notes | corps | string | null | Note interne du salon. |
curl -X PATCH -H "Authorization: Bearer pgo_…" \
-H "Content-Type: application/json" -d '{…}' "https://pre-go.fr/api/v1/appointments/<id>"POST/appointments/{id}/cancel— Annuler un rendez-vouscancel_appointment
Droit : appointments:write · écriture
Annule un rendez-vous au nom du salon. Le barbier est prévenu et la liste d'attente est sollicitée, comme depuis le planning du QG. Le client n'est pas prévenu automatiquement (même comportement que le QG). Idempotent : annuler un rendez-vous déjà annulé le renvoie tel quel.
| Paramètre | Où | Type | Description |
|---|---|---|---|
| id* | chemin | string | |
| reason | corps | string | Motif, visible dans la fiche du rendez-vous. |
curl -X POST -H "Authorization: Bearer pgo_…" \
-H "Content-Type: application/json" -d '{…}' "https://pre-go.fr/api/v1/appointments/<id>/cancel"Clients
GET/customers— Rechercher dans le fichier clientlist_customers
Droit : customers:read · lecture
Liste les clients du salon, triés par nom. search cherche dans le prénom, le nom, l'e-mail et le téléphone (le format du numéro n'importe pas : 0612345678 trouve « 06 12 34 56 78 »). Un numéro enregistré ou modifié désormais est renvoyé au format international E.164 (+33612345678) ; une fiche plus ancienne garde le format saisi à l'époque, et un numéro non reconnu (étranger hors format international, coquille) reste tel que saisi.
| Paramètre | Où | Type | Description |
|---|---|---|---|
| search | query | string | |
| limit | query | integer | (défaut : 50) |
| offset | query | integer | (défaut : 0) |
curl -H "Authorization: Bearer pgo_…" "https://pre-go.fr/api/v1/customers"Réponse
{
"data": [
{
"id": "c81e",
"firstName": "Jean",
"lastName": "Dupont",
"email": "jean@example.com",
"phone": "+33612345678",
"totalVisits": 7,
"lastVisitDate": "2026-09-12T08:00:00.000Z"
}
],
"meta": {
"count": 1,
"limit": 50,
"offset": 0,
"hasMore": false
}
}GET/customers/{id}— Fiche d'un clientget_customer
Droit : customers:read · lecture
Renvoie la fiche d'un client : coordonnées, consentements, statistiques de visite. Ses rendez-vous s'obtiennent avec list_appointments et customerId.
| Paramètre | Où | Type | Description |
|---|---|---|---|
| id* | chemin | string |
curl -H "Authorization: Bearer pgo_…" "https://pre-go.fr/api/v1/customers/<id>"POST/customers— Créer une fiche clientcreate_customer
Droit : customers:write · écriture
Crée une fiche client. Si l'e-mail correspond déjà à une fiche, ou le téléphone avec un nom proche (un numéro peut être partagé en famille), renvoie 422 avec l'id existant dans details.existingCustomerId au lieu de créer un doublon ; passez allowDuplicate: true pour forcer.
| Paramètre | Où | Type | Description |
|---|---|---|---|
| firstName* | corps | string | |
| lastName | corps | string | (défaut : "") |
| corps | string | null | ||
| phone | corps | string | null | |
| emailOptIn | corps | boolean | |
| smsOptIn | corps | boolean | |
| allowDuplicate | corps | boolean | (défaut : false) |
curl -X POST -H "Authorization: Bearer pgo_…" \
-H "Content-Type: application/json" -d '{…}' "https://pre-go.fr/api/v1/customers"PATCH/customers/{id}— Modifier une fiche clientupdate_customer
Droit : customers:write · écriture
Met à jour les coordonnées ou les consentements d'un client. Seuls les champs envoyés changent ; null efface l'e-mail ou le téléphone.
| Paramètre | Où | Type | Description |
|---|---|---|---|
| id* | chemin | string | |
| firstName | corps | string | |
| lastName | corps | string | |
| corps | string | null | ||
| phone | corps | string | null | |
| emailOptIn | corps | boolean | |
| smsOptIn | corps | boolean |
curl -X PATCH -H "Authorization: Bearer pgo_…" \
-H "Content-Type: application/json" -d '{…}' "https://pre-go.fr/api/v1/customers/<id>"Encaissements
GET/sales— Encaissements sur une périodelist_sales
Droit : sales:read · lecture
Liste les tickets de caisse entre deux dates incluses (jours du salon, 92 jours au plus), du plus récent au plus ancien, avec un résumé : nombre de tickets, total encaissé et pourboires (tickets remboursés exclus du résumé). Montants en euros TTC.
| Paramètre | Où | Type | Description |
|---|---|---|---|
| from* | query | string | |
| to* | query | string | |
| staffId | query | string | |
| limit | query | integer | (défaut : 200) |
| offset | query | integer | (défaut : 0) |
curl -H "Authorization: Bearer pgo_…" "https://pre-go.fr/api/v1/sales"Réponse
{
"data": [
{
"id": "sal_1",
"receiptNumber": "T-2026-0042",
"createdAt": "2026-10-02T09:12:00.000Z",
"total": 30,
"tipAmount": 5,
"paymentMethod": "card",
"paymentStatus": "completed",
"staffId": "mbr_x1",
"customerId": "c81e",
"appointmentId": "apt_9f2"
}
],
"meta": {
"count": 1,
"limit": 200,
"offset": 0,
"hasMore": false
},
"summary": {
"salesCount": 1,
"total": 30,
"tips": 5
}
}SMS
GET/sms/usage— Consommation SMS sur une périodeget_sms_usage
Droit : sms:read · lecture
Volumes SMS entre deux jours inclus (jours du salon, 366 jours au plus ; par défaut le mois en cours) : total, par barbier, par type de message et par jour. Mêmes chiffres que l'écran « Consommation SMS » du QG. Seuls les SMS facturés comptent (statuts pending, sent, delivered) ; unbilled dit combien de tentatives ne l'ont pas été (numéro invalide, plafond atteint, erreur du fournisseur). messages = SMS envoyés (un par destinataire) ; segments = unités facturées (un message long en compte plusieurs) — c'est segments qu'on refacture. Le barbier d'un SMS est celui du rendez-vous qui l'a déclenché ; staffId: null = sans barbier (SMS de test…). Le détail ligne à ligne est dans list_sms_messages.
| Paramètre | Où | Type | Description |
|---|---|---|---|
| from | query | string | Premier jour inclus (YYYY-MM-DD, jour du salon). Absent avec to : mois en cours. |
| to | query | string | Dernier jour inclus (YYYY-MM-DD, jour du salon). Absent avec from : mois en cours. |
| staffId | query | string | Barbier (voir list_staff) : seuls les SMS de ses rendez-vous. Un identifiant d'un autre salon ne renvoie rien. |
curl -H "Authorization: Bearer pgo_…" "https://pre-go.fr/api/v1/sms/usage"Réponse
{
"data": {
"period": {
"from": "2026-09-01",
"to": "2026-09-30",
"timeZone": "Europe/Paris"
},
"totals": {
"messages": 412,
"segments": 431
},
"byStaff": [
{
"staffId": "mbr_k4r1m",
"name": "Karim Benali",
"messages": 240,
"segments": 251
},
{
"staffId": "mbr_s4m1",
"name": "Sami Haddad",
"messages": 170,
"segments": 178
},
{
"staffId": null,
"name": "Sans barbier",
"messages": 2,
"segments": 2
}
],
"byType": [
{
"type": "reminder_24h",
"label": "Rappel 24h",
"messages": 300,
"segments": 300
},
{
"type": "booking_confirmation",
"label": "Confirmation de réservation",
"messages": 110,
"segments": 129
},
{
"type": "sms_test",
"label": "SMS de test",
"messages": 2,
"segments": 2
}
],
"byDay": [
{
"date": "2026-09-01",
"messages": 14,
"segments": 15
}
],
"unbilled": 3
}
}GET/sms/messages— SMS envoyés, ligne à lignelist_sms_messages
Droit : sms:read · lecture
Le détail qui justifie une refacturation : un SMS par ligne, du plus récent au plus ancien, entre deux jours inclus (jours du salon, 366 jours au plus ; par défaut le mois en cours). Par défaut seuls les SMS facturés (statuts pending, sent, delivered) ; status=unbilled pour les tentatives non facturées, status=all pour tout. Chaque ligne donne le barbier du rendez-vous, le type de message, le nombre de segments facturés, et les identifiants du rendez-vous et du client. Ni numéro ni texte du message. day est le jour du salon qui sert aux totaux de get_sms_usage.
| Paramètre | Où | Type | Description |
|---|---|---|---|
| from | query | string | Premier jour inclus (YYYY-MM-DD, jour du salon). Absent avec to : mois en cours. |
| to | query | string | Dernier jour inclus (YYYY-MM-DD, jour du salon). Absent avec from : mois en cours. |
| staffId | query | string | Barbier (voir list_staff) : seuls les SMS de ses rendez-vous. Un identifiant d'un autre salon ne renvoie rien. |
| status | query | billed | unbilled | all | billed (défaut) : SMS facturés ; unbilled : tentatives non facturées ; all : tout.(défaut : "billed") |
| limit | query | integer | (défaut : 200) |
| offset | query | integer | (défaut : 0) |
curl -H "Authorization: Bearer pgo_…" "https://pre-go.fr/api/v1/sms/messages"Réponse
{
"data": [
{
"id": 98123,
"sentAt": "2026-09-30T21:30:00.000Z",
"day": "2026-09-30",
"staff": {
"id": "mbr_k4r1m",
"name": "Karim Benali"
},
"type": "reminder_24h",
"typeLabel": "Rappel 24h",
"segments": 1,
"status": "delivered",
"billed": true,
"appointmentId": "apt_9f2",
"customerId": "c81e"
}
],
"meta": {
"count": 1,
"limit": 200,
"offset": 0,
"hasMore": false
},
"period": {
"from": "2026-09-01",
"to": "2026-09-30",
"timeZone": "Europe/Paris"
}
}Stocks
GET/products— Produits et niveaux de stocklist_products
Droit : inventory:read · lecture
Liste les produits du salon (vente au comptoir, consommables, linge réutilisable) avec leur stock. stock.status vaut out (épuisé), low (au seuil minimum ou dessous, comme l'alerte du QG) ou ok. Filtre stock=low pour la liste à recommander (épuisés compris). summary porte sur tous les produits actifs, pas seulement la page : nombre, produits bas, épuisés, valeur du stock au prix d'achat (€ HT).
| Paramètre | Où | Type | Description |
|---|---|---|---|
| search | query | string | Cherche dans le nom, la référence (SKU), le code-barres et la marque. |
| categoryId | query | integer | Catégorie (voir list_product_categories). |
| kind | query | consumable | reusable | retail | retail : vente au comptoir ; consumable : produit entamé pendant les prestations ; reusable : linge, serviettes. |
| stock | query | low | out | low : au seuil minimum ou dessous (épuisés compris) ; out : épuisés seulement. |
| includeInactive | query | boolean,string | true pour inclure les produits archivés. |
| limit | query | integer | (défaut : 100) |
| offset | query | integer | (défaut : 0) |
curl -H "Authorization: Bearer pgo_…" "https://pre-go.fr/api/v1/products"Réponse
{
"data": [
{
"id": 31,
"name": "Cire mate 100 ml",
"sku": "CIRE-MAT-100",
"barcode": "3760000000017",
"brand": "Reuzel",
"category": {
"id": 2,
"name": "Coiffants"
},
"kind": "retail",
"sellingPrice": 19.9,
"costPrice": 9.5,
"taxRate": 20,
"stock": {
"current": 2,
"status": "low",
"minimum": 3,
"maximum": 12,
"reorderPoint": null,
"reorderQuantity": 6,
"tracked": true,
"allowNegative": false
},
"openUnit": null,
"reusable": null,
"isActive": true
}
],
"meta": {
"count": 1,
"limit": 100,
"offset": 0,
"hasMore": false
},
"summary": {
"products": 24,
"lowStock": 3,
"outOfStock": 1,
"stockValueAtCost": 812.4
}
}GET/products/{id}— Fiche d'un produitget_product
Droit : inventory:read · lecture
Renvoie un produit, son stock et ses dix derniers mouvements (le plus récent d'abord). L'historique complet s'obtient avec list_stock_movements et productId.
| Paramètre | Où | Type | Description |
|---|---|---|---|
| id* | chemin | integer |
curl -H "Authorization: Bearer pgo_…" "https://pre-go.fr/api/v1/products/<id>"GET/product-categories— Catégories de produitslist_product_categories
Droit : inventory:read · lecture
Liste les catégories de produits du salon, dans l'ordre d'affichage du QG. Utilisez leur id comme categoryId dans list_products, create_product et update_product.
Aucun paramètre.
curl -H "Authorization: Bearer pgo_…" "https://pre-go.fr/api/v1/product-categories"Réponse
{
"data": [
{
"id": 2,
"name": "Coiffants",
"description": null,
"parentId": null,
"color": "#3B82F6",
"isActive": true
}
]
}GET/stock-movements— Historique des mouvements de stocklist_stock_movements
Droit : inventory:read · lecture
Liste les entrées et sorties de stock, de la plus récente à la plus ancienne. type : purchase (réception), sale (vente en caisse), service_use (consommé pendant une prestation), waste (perte, casse, périmé), adjustment (correction ou inventaire), transfer. quantity est signée : positive pour une entrée, négative pour une sortie. Période facultative en jours du salon (92 jours au plus si from et to sont donnés).
| Paramètre | Où | Type | Description |
|---|---|---|---|
| productId | query | integer | Un seul produit (voir list_products). |
| type | query | purchase | sale | adjustment | waste | service_use | transfer | |
| from | query | string | Premier jour inclus, YYYY-MM-DD, fuseau du salon. |
| to | query | string | Dernier jour inclus, YYYY-MM-DD, fuseau du salon. |
| limit | query | integer | (défaut : 100) |
| offset | query | integer | (défaut : 0) |
curl -H "Authorization: Bearer pgo_…" "https://pre-go.fr/api/v1/stock-movements"Réponse
{
"data": [
{
"id": 912,
"product": {
"id": 31,
"name": "Cire mate 100 ml"
},
"type": "purchase",
"quantity": 6,
"stockBefore": 2,
"stockAfter": 8,
"unitCost": 9.5,
"totalCost": 57,
"reason": "Réception",
"reference": "BL-2026-118",
"recordedBy": "Karim B.",
"connectedApp": {
"id": "app_x",
"name": "Mon tableur"
},
"createdAt": "2026-10-02T08:30:00.000Z"
}
],
"meta": {
"count": 1,
"limit": 100,
"offset": 0,
"hasMore": false
}
}POST/products/{id}/stock-movements— Enregistrer une entrée, une perte ou un inventairecreate_stock_movement
Droit : inventory:write · écriture
Modifie le stock d'un produit en laissant une trace dans son historique. Quatre cas :
- type: "purchase" + quantity > 0 : livraison reçue, le stock monte de quantity.
- type: "waste" + quantity > 0 : perte, casse ou périmé, le stock baisse de quantity.
- type: "adjustment" + quantity signée (≠ 0) : correction ponctuelle.
- type: "adjustment" + countedStock : inventaire, le stock devient exactement countedStock.
Les quantités sont des unités entières (flacons fermés pour un consommable). Une sortie qui ferait passer le stock sous zéro est refusée (422) sauf si le produit l'autorise. Pour un réutilisable (linge), une réception ou une perte change aussi le nombre possédé.
Idempotence : avec une reference (n° de bon de livraison…), un second appel identique sur le même produit renvoie le mouvement déjà enregistré avec replayed: true au lieu de compter deux fois.
Une vente se fait en caisse au QG, pas ici.
| Paramètre | Où | Type | Description |
|---|---|---|---|
| id* | chemin | integer | |
| type* | corps | purchase | waste | adjustment | |
| quantity | corps | integer | Unités. > 0 pour purchase et waste ; signée pour adjustment. |
| countedStock | corps | integer | Inventaire : le stock compté. Seulement avec type adjustment, à la place de quantity. |
| reason | corps | string | Motif lisible au QG. Par défaut : Réception, Perte, Correction ou Inventaire. |
| reference | corps | string | N° de bon de livraison, de facture… Rend l'appel idempotent. |
| unitCost | corps | number | Prix d'achat unitaire HT de cette livraison (€). |
curl -X POST -H "Authorization: Bearer pgo_…" \
-H "Content-Type: application/json" -d '{…}' "https://pre-go.fr/api/v1/products/<id>/stock-movements"Réponse
{
"data": {
"movement": {
"id": 912,
"type": "purchase",
"quantity": 6,
"stockBefore": 2,
"stockAfter": 8,
"reference": "BL-2026-118"
},
"product": {
"id": 31,
"name": "Cire mate 100 ml",
"stock": {
"current": 8,
"status": "ok"
}
}
},
"replayed": false
}POST/products— Créer un produitcreate_product
Droit : inventory:write · écriture
Ajoute un produit au catalogue du salon. Prix en euros : sellingPrice TTC, costPrice HT. Si un produit porte déjà ce sku (casse ignorée), renvoie 422 avec son id dans details.existingProductId au lieu de créer un doublon ; passez allowDuplicateSku: true pour forcer. initialStock crée le stock de départ avec un mouvement « Stock initial » dans l'historique.
| Paramètre | Où | Type | Description |
|---|---|---|---|
| name* | corps | string | |
| sku* | corps | string | |
| costPrice* | corps | number | |
| sellingPrice* | corps | number | |
| kind | corps | consumable | reusable | retail | retail : vente au comptoir ; consumable : entamé pendant les prestations ; reusable : linge.(défaut : "retail") |
| barcode | corps | string | null | |
| brand | corps | string | null | |
| description | corps | string | null | |
| categoryId | corps | integer | null | |
| taxRate | corps | number | TVA en %, 20 par défaut.(défaut : 20) |
| minStockLevel | corps | integer | Seuil d'alerte : à ce stock ou dessous, le produit passe en « bas ».(défaut : 0) |
| maxStockLevel | corps | integer | null | |
| reorderPoint | corps | integer | null | |
| reorderQuantity | corps | integer | null | |
| capacityPerUnit | corps | number | Consommable : contenance d'une unité (ml, g, doses). |
| supplierSku | corps | string | null | |
| leadTimeDays | corps | integer | null | |
| initialStock | corps | integer | (défaut : 0) |
| allowDuplicateSku | corps | boolean | (défaut : false) |
curl -X POST -H "Authorization: Bearer pgo_…" \
-H "Content-Type: application/json" -d '{…}' "https://pre-go.fr/api/v1/products"PATCH/products/{id}— Modifier un produitupdate_product
Droit : inventory:write · écriture
Met à jour la fiche d'un produit : prix, seuils de stock, référence, catégorie, archivage (isActive: false). Seuls les champs envoyés changent ; null efface un champ facultatif. Le stock lui-même ne se modifie pas ici : utilisez create_stock_movement, qui garde l'historique.
| Paramètre | Où | Type | Description |
|---|---|---|---|
| id* | chemin | integer | |
| name | corps | string | |
| sku | corps | string | |
| barcode | corps | string | null | |
| brand | corps | string | null | |
| description | corps | string | null | |
| categoryId | corps | integer | null | |
| costPrice | corps | number | |
| sellingPrice | corps | number | |
| taxRate | corps | number | |
| minStockLevel | corps | integer | |
| maxStockLevel | corps | integer | null | |
| reorderPoint | corps | integer | null | |
| reorderQuantity | corps | integer | null | |
| supplierSku | corps | string | null | |
| leadTimeDays | corps | integer | null | |
| isActive | corps | boolean | false pour archiver le produit, true pour le réactiver. |
curl -X PATCH -H "Authorization: Bearer pgo_…" \
-H "Content-Type: application/json" -d '{…}' "https://pre-go.fr/api/v1/products/<id>"Les erreurs
Toujours { "error": { "code", "message", "details"? } }. Le code ne change jamais ; le message dit quoi corriger.
unauthorized401Jeton absent, inconnu, expiré ou révoqué.forbidden_scope403Le jeton n'a pas le droit (scope) requis par cette opération.not_found404Ressource introuvable dans ce salon.method_not_allowed405Méthode HTTP non prise en charge sur ce chemin. L'en-têteAllowliste les bonnes.invalid_request400Paramètres invalides.detailsliste les champs en cause.conflict409Le créneau n'est plus libre, ou l'état a changé entre-temps.unprocessable422Requête valide, mais refusée par une règle métier (date passée, statut, doublon…).rate_limited429Trop d'appels. AttendreRetry-Aftersecondes.internal_error500Erreur côté Pre-Go. Réessayer plus tard.
Ce qui vous protège
- Un salon par clé. Le jeton ne voit que le salon qui l'a créé. Une ressource d'un autre salon répond « introuvable ».
- Rien n'est gardé en clair. Pre-Go ne stocke que l'empreinte du jeton. Perdu, il se régénère ; il ne se relit pas.
- La clé meurt avec son créateur. Révoquée, expirée, ou si son créateur n'est plus propriétaire du salon : elle ne répond plus, vérifié à chaque appel.
- Tout est tracé. Chaque appel, lecture comprise, entre au journal d'audit du salon, au nom de l'application. Les données lues n'y sont pas recopiées.
- Les mêmes règles qu'au QG. Un rendez-vous posé par l'API passe par les mêmes contrôles de créneau et envoie les mêmes notifications. Le stock ne bouge que par un mouvement daté et signé.