Démarrer
Toutes les adresses partent de la même base :
https://api.planevia.ca/api/publicChaque appel nomme l’entreprise par l’identifiant de sa page de réservation, celui qu’on lit dans son adresse planevia.ca/mon-spa : ?org=mon-spa en lecture, "organizationSlug": "mon-spa" dans le corps d’une création. Chaque réponse a la même forme :
{ "success": true, "data": { … } }
{ "success": false, "message": "Texte à montrer au client" }Une réservation se fait en trois temps :
- lire les soins et les professionnelles qui les donnent ;
- lire les heures libres ;
- créer le rendez-vous.
Accès et limites
Le propriétaire de l’entreprise crée ses clés dans Réglages, Intégrations, Clés API. Une clé s’envoie dans l’en-tête x-api-key, depuis votre serveur seulement : elle ne doit jamais apparaître dans une page web. Elle est conservée sous forme d’empreinte et se révoque à tout moment.
Les routes de réservation sont publiques
Limites d’appels, par heure
| Appel | Sans clé | Avec clé |
|---|---|---|
| Création de rendez-vous (solo, duo, groupe) | 20 par adresse IP | 20 par adresse IP |
| Heures libres duo et groupe, lien du client | 150 par adresse IP | 150 par adresse IP |
| Vérification d’une carte-cadeau | 20 par adresse IP | 300 par clé |
| Options de paiement | 150 par adresse IP | 3 000 par clé |
Au-delà, la réponse est 429 et les en-têtes RateLimit-* indiquent quand réessayer. Si votre intégration crée plus de 20 rendez-vous à l’heure depuis un même serveur, écrivez-nous avant la mise en service.
Soins et disponibilités
| Appel | Paramètres | Renvoie |
|---|---|---|
GET /services | org | Catégories et soins réservables en ligne : id, nom, durée, prix, déclinaisons |
GET /services/:slug | org | Le détail d’un soin |
GET /packages | org | Les forfaits vendus en ligne |
GET /professionals/by-service | org serviceId | Les professionnelles qui donnent ce soin, avec leur prix si elles en ont un |
GET /available-slots | org therapistId date duration serviceId | Les heures libres de la professionnelle ce jour-là, ou la raison s’il n’y en a pas |
GET /month-availability | org therapistId month duration serviceId | Les jours du mois qui ont au moins une heure libre |
GET /next-availability | org therapistId duration serviceId | Le premier jour libre dans les 90 prochains jours |
GET /branches | org | Les succursales d’une entreprise à plusieurs adresses |
GET /available-slots?org=mon-spa&therapistId=usr_1&date=2026-10-20&duration=60&serviceId=svc_1
{
"success": true,
"data": {
"date": "2026-10-20",
"isBlocked": false,
"slots": ["09:00", "09:15", "10:30"]
}
}Les heures tiennent compte de l’horaire de chaque professionnelle, de ses congés, des rendez-vous déjà pris et des règles de réservation de l’entreprise. Un jour sans horaire répond isBlocked: true avec la raison.
Créer un rendez-vous
{
"organizationSlug": "mon-spa",
"serviceId": "svc_1",
"serviceVariationId": "var_60",
"therapistId": "usr_1",
"date": "2026-10-20",
"startTime": "09:00",
"firstName": "Camille",
"lastName": "Tremblay",
"email": "camille@exemple.com",
"phone": "418-555-0142",
"clientNotes": "Première visite",
"emailReminder": true,
"smsReminder": true
}Facultatifs : branchId (succursale), promoCode, giftCardCode (carte-cadeau à appliquer), packageId (forfait). Le client est retrouvé par son courriel ou son téléphone, ou créé s’il est nouveau. Il reçoit sa confirmation et ses rappels selon les réglages de l’entreprise.
La réponse 201 contient le rendez-vous dans data.booking, confirmé d’office ou en attente de confirmation par l’équipe, selon les réglages de l’entreprise.
Acompte et paiement
Si l’entreprise exige un paiement à la réservation, la réponse porte paymentRequired: true, le montant (paymentAmount, isDeposit), le lien de paiement Stripe paymentUrl et son délai paymentExpiresInMinutes. Le lien part aussi au client par courriel ou par texto. Le rendez-vous se confirme tout seul au paiement et s’annule à l’expiration du délai.
Refus
| Code | Signifie | À faire |
|---|---|---|
400 | Champ manquant ou mal formé | Corriger la demande |
404 | Entreprise, soin ou professionnelle introuvable | Relire les soins et les professionnelles |
409 | L’heure vient d’être prise | Relire les heures libres et proposer une autre heure |
429 | Trop de demandes | Attendre le délai indiqué |
Le champ message est écrit pour être montré tel quel au client.
Duo et groupe
POST /bookings/duo réserve deux personnes à la même heure, avec deux professionnelles et une salle. Ses heures libres se lisent avec GET /duo/slots et GET /duo/month-availability.
POST /bookings/groupe pose plusieurs rendez-vous en une seule opération, à la même heure ou non, avec un soin différent par personne si besoin. Le nombre maximal suit le nombre de professionnelles réservables en ligne, jusqu’à 20.
{
"organizationSlug": "mon-spa",
"contact": {
"firstName": "Camille", "lastName": "Tremblay",
"email": "camille@exemple.com", "phone": "418-555-0142"
},
"items": [
{ "serviceId": "svc_massage", "serviceVariationId": "var_50",
"date": "2026-10-20", "startTime": "09:00" },
{ "serviceId": "svc_soin_visage", "date": "2026-10-20", "startTime": "09:00",
"therapistId": "usr_2",
"participant": { "firstName": "Olivier", "lastName": "Gagnon" } }
]
}Avant d’appeler, GET /groupe/slots donne pour un soin et une date les heures libres et qui est libre à chacune ; GET /groupe/month-availability donne les jours possibles. L’acompte se compte par rendez-vous et se paie en un seul lien. Les cartes-cadeaux ne s’appliquent pas au duo ni au groupe.
Déplacer ou annuler
Avec sa confirmation, le client reçoit un lien signé qui lui donne la main sur son rendez-vous, sans compte. Ces appels prennent le jeton de ce lien et appliquent les règles d’annulation de l’entreprise.
| Appel | Fait |
|---|---|
GET /bookings/:token | Le rendez-vous et ce qui est permis |
GET /bookings/:token/services | Les soins vers lesquels il peut être changé |
GET /bookings/:token/slots | Les heures libres pour le déplacer |
POST /bookings/:token/reschedule | Déplace le rendez-vous |
POST /bookings/:token/cancel | Annule le rendez-vous |
POST /bookings/retrouver | Renvoie son lien au client qui l’a perdu |
Un système externe ne peut pas encore déplacer ou annuler seul
Cartes-cadeaux
{ "organizationSlug": "mon-spa", "code": "XXXX-XXXX" }La réponse dit si le code existe et ce qu’il couvre : un solde, ou un soin d’un forfait. Le code s’applique ensuite à un rendez-vous solo par giftCardCode. La vente et la gestion des cartes-cadeaux se font dans Planevia.
Webhooks
Planevia prévient votre système à chaque étape d’un rendez-vous, quelle qu’en soit l’origine : en ligne, au comptoir, au téléphone ou par la réceptionniste IA. Le propriétaire déclare l’adresse à appeler et les événements voulus dans Réglages, Intégrations, Webhooks, avec un bouton pour tester et le journal de chaque envoi.
| Événement | Quand |
|---|---|
booking.created | Rendez-vous créé, en attente de confirmation |
booking.confirmed | Rendez-vous confirmé |
booking.rescheduled | Rendez-vous déplacé |
booking.cancelled | Rendez-vous annulé |
booking.completed | Rendez-vous terminé |
booking.no_show | Client absent |
booking.reminder_due | Moment d’envoyer le rappel |
booking.review_due | Moment de demander un avis |
{
"event": "booking.confirmed",
"sentAt": "2026-10-15T14:02:11.000Z",
"data": {
"booking": {
"id": "…", "number": "BK…", "status": "CONFIRMED", "source": "ONLINE",
"date": "2026-10-20", "startTime": "09:00", "endTime": "10:00",
"duration": 60, "total": 118.42, "notes": "Première visite"
},
"client": {
"id": "…", "firstName": "Camille", "lastName": "Tremblay",
"email": "camille@exemple.com", "phone": "+14185550142"
},
"service": { "id": "svc_1", "name": "Massage suédois 60 min" },
"professional": { "id": "usr_1", "firstName": "Marie", "lastName": "Dubois" }
}
}Signature
Chaque envoi porte l’en-tête X-Planevia-Event et l’en-tête X-Planevia-Signature : le HMAC SHA-256 du corps brut, en hexadécimal, calculé avec le secret du webhook. Ce secret commence par whsec_ et n’est affiché qu’une fois, à la création. Vérifiez la signature sur le corps tel que reçu, avant de le lire.
import crypto from 'node:crypto';
import express from 'express';
const app = express();
app.post('/planevia', express.raw({ type: 'application/json' }), (req, res) => {
const attendue = crypto
.createHmac('sha256', process.env.PLANEVIA_WEBHOOK_SECRET)
.update(req.body)
.digest('hex');
const recue = req.get('X-Planevia-Signature') || '';
const valide = recue.length === attendue.length &&
crypto.timingSafeEqual(Buffer.from(recue), Buffer.from(attendue));
if (!valide) return res.sendStatus(401);
const { event, data } = JSON.parse(req.body.toString('utf8'));
// … traiter l'événement
res.sendStatus(200);
});Livraison
Toute réponse 2xx dans les 10 secondes vaut réception. Sinon, Planevia réessaie deux fois, après 2 puis 10 secondes. Répondez vite et traitez ensuite : un même événement peut arriver deux fois si votre réponse se perd, alors servez-vous de data.booking.id et de event pour ignorer un doublon.
Messagerie externe
Si votre CRM, GoHighLevel par exemple, écrit lui-même aux clients, le propriétaire passe Planevia en mode « messagerie externe ». Planevia n’envoie plus ses confirmations, modifications, annulations, rappels ni demandes d’avis : votre CRM les envoie à la réception des événements correspondants.
Filet de sécurité : si votre webhook échoue plusieurs fois de suite, Planevia reprend lui-même l’envoi, pour qu’aucun client ne reste sans message.
Ce qui n’existe pas encore
Ces besoins se font aujourd’hui dans Planevia, pas par l’API. Dites-nous lesquels comptent pour vous.
- Lire, créer ou modifier une fiche client.
- Déplacer ou annuler un rendez-vous sans le lien du client.
- Lire les paiements, les factures et les reçus.
- Vendre ou gérer une carte-cadeau.
- Recevoir un webhook de paiement, de client ou de carte-cadeau.
- Envoyer des changements d’un CRM vers Planevia.
Tester
Il n’y a pas d’environnement de test séparé : l’essai gratuit de 14 jours en tient lieu. Créez-y des soins, des professionnelles et des clients fictifs, une clé API et un webhook, puis appelez l’API avec l’identifiant de ce compte. Tant que le compte Stripe de l’essai n’est pas branché, aucun paiement en ligne n’est demandé.
Une question technique : support@planevia.ca. Ce que deviennent les données que vous recevez et envoyez : politique de confidentialité.