Aller au contenu

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

  1. 01

    Créez une clé

    Au QG : Paramètres → Applications connectées → Nouvelle application. Réservé au propriétaire du salon.

  2. 02

    Choisissez les droits

    Lecture et écriture sont deux droits distincts. Un tableur de suivi n'a aucune raison d'annuler un rendez-vous.

  3. 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/me
  • Base

    https://pre-go.fr/api/v1
  • Jeton

    Authorization: Bearer pgo_… ou X-Api-Key. Jamais dans l'URL.

  • Dates et heures

    Dates YYYY-MM-DD, heures HH:mm dans le fuseau du salon. Instants en ISO 8601 UTC.

  • Montants

    Euros TTC, en nombres décimaux.

  • Réponses

    { "data": … }, plus meta (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
includeInactivequeryboolean,stringtrue 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
includeInactivequeryboolean,stringtrue 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*querystringJour voulu, YYYY-MM-DD, dans le fuseau du salon.
serviceId*queryintegerPrestation (voir list_services).
staffIdquerystringBarbier 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*querystringPremier jour, YYYY-MM-DD.
to*querystringDernier jour inclus, YYYY-MM-DD.
staffIdquerystring
customerIdquerystring
statusquerystringUn ou plusieurs statuts séparés par des virgules : pending, scheduled, confirmed, in_progress, completed, cancelled, no_show.
limitqueryinteger(défaut : 200)
offsetqueryinteger(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*cheminstringIdentifiant 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*corpsstringJour du rendez-vous, YYYY-MM-DD.
startTime*corpsstringHeure de début, HH:mm, fuseau du salon.
serviceId*corpsinteger
staffIdcorpsstringBarbier voulu. Absent : n'importe quel barbier disponible.
customerIdcorpsstringClient existant (voir list_customers). Sinon, renseignez customer.
customercorpsobjet { 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é.
customerNotescorpsstringDemande du client, visible par le barbier.
notifyCustomercorpsbooleanfalse 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*cheminstring
datecorpsstringNouveau jour, YYYY-MM-DD.
startTimecorpsstringNouvelle heure de début, HH:mm.
staffIdcorpsstringNouveau barbier.
durationMinutescorpsinteger
statuscorpsscheduled | confirmed | no_show | cancelled
notescorpsstring | nullNote 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*cheminstring
reasoncorpsstringMotif, 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
searchquerystring
limitqueryinteger(défaut : 50)
offsetqueryinteger(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*cheminstring
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*corpsstring
lastNamecorpsstring(défaut : "")
emailcorpsstring | null
phonecorpsstring | null
emailOptIncorpsboolean
smsOptIncorpsboolean
allowDuplicatecorpsboolean(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*cheminstring
firstNamecorpsstring
lastNamecorpsstring
emailcorpsstring | null
phonecorpsstring | null
emailOptIncorpsboolean
smsOptIncorpsboolean
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*querystring
to*querystring
staffIdquerystring
limitqueryinteger(défaut : 200)
offsetqueryinteger(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
fromquerystringPremier jour inclus (YYYY-MM-DD, jour du salon). Absent avec to : mois en cours.
toquerystringDernier jour inclus (YYYY-MM-DD, jour du salon). Absent avec from : mois en cours.
staffIdquerystringBarbier (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
fromquerystringPremier jour inclus (YYYY-MM-DD, jour du salon). Absent avec to : mois en cours.
toquerystringDernier jour inclus (YYYY-MM-DD, jour du salon). Absent avec from : mois en cours.
staffIdquerystringBarbier (voir list_staff) : seuls les SMS de ses rendez-vous. Un identifiant d'un autre salon ne renvoie rien.
statusquerybilled | unbilled | allbilled (défaut) : SMS facturés ; unbilled : tentatives non facturées ; all : tout.(défaut : "billed")
limitqueryinteger(défaut : 200)
offsetqueryinteger(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
searchquerystringCherche dans le nom, la référence (SKU), le code-barres et la marque.
categoryIdqueryintegerCatégorie (voir list_product_categories).
kindqueryconsumable | reusable | retailretail : vente au comptoir ; consumable : produit entamé pendant les prestations ; reusable : linge, serviettes.
stockquerylow | outlow : au seuil minimum ou dessous (épuisés compris) ; out : épuisés seulement.
includeInactivequeryboolean,stringtrue pour inclure les produits archivés.
limitqueryinteger(défaut : 100)
offsetqueryinteger(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*chemininteger
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
productIdqueryintegerUn seul produit (voir list_products).
typequerypurchase | sale | adjustment | waste | service_use | transfer
fromquerystringPremier jour inclus, YYYY-MM-DD, fuseau du salon.
toquerystringDernier jour inclus, YYYY-MM-DD, fuseau du salon.
limitqueryinteger(défaut : 100)
offsetqueryinteger(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*chemininteger
type*corpspurchase | waste | adjustment
quantitycorpsintegerUnités. > 0 pour purchase et waste ; signée pour adjustment.
countedStockcorpsintegerInventaire : le stock compté. Seulement avec type adjustment, à la place de quantity.
reasoncorpsstringMotif lisible au QG. Par défaut : Réception, Perte, Correction ou Inventaire.
referencecorpsstringN° de bon de livraison, de facture… Rend l'appel idempotent.
unitCostcorpsnumberPrix 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*corpsstring
sku*corpsstring
costPrice*corpsnumber
sellingPrice*corpsnumber
kindcorpsconsumable | reusable | retailretail : vente au comptoir ; consumable : entamé pendant les prestations ; reusable : linge.(défaut : "retail")
barcodecorpsstring | null
brandcorpsstring | null
descriptioncorpsstring | null
categoryIdcorpsinteger | null
taxRatecorpsnumberTVA en %, 20 par défaut.(défaut : 20)
minStockLevelcorpsintegerSeuil d'alerte : à ce stock ou dessous, le produit passe en « bas ».(défaut : 0)
maxStockLevelcorpsinteger | null
reorderPointcorpsinteger | null
reorderQuantitycorpsinteger | null
capacityPerUnitcorpsnumberConsommable : contenance d'une unité (ml, g, doses).
supplierSkucorpsstring | null
leadTimeDayscorpsinteger | null
initialStockcorpsinteger(défaut : 0)
allowDuplicateSkucorpsboolean(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*chemininteger
namecorpsstring
skucorpsstring
barcodecorpsstring | null
brandcorpsstring | null
descriptioncorpsstring | null
categoryIdcorpsinteger | null
costPricecorpsnumber
sellingPricecorpsnumber
taxRatecorpsnumber
minStockLevelcorpsinteger
maxStockLevelcorpsinteger | null
reorderPointcorpsinteger | null
reorderQuantitycorpsinteger | null
supplierSkucorpsstring | null
leadTimeDayscorpsinteger | null
isActivecorpsbooleanfalse 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ête Allow liste les bonnes.
  • invalid_request400Paramètres invalides. details liste 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. Attendre Retry-After secondes.
  • 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é.

Pour les machines