Démarrer
Planevia offre deux API, avec la même clé :
| API | Adresse de base | Sert à | Clé |
|---|---|---|---|
| Réservation | https://api.planevia.ca/api/public | Lire les soins et les heures libres, créer un rendez-vous | Facultative |
| Gestion | https://api.planevia.ca/api/v1 | Lire et tenir à jour clients, rendez-vous, reçus, assignations, webhooks | Obligatoire, avec permissions |
Les sections qui suivent décrivent d’abord l’API de réservation, puis l’API de gestion. Dans l’API de réservation, chaque 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.
Clés API
Le propriétaire de l’entreprise crée ses clés dans Réglages, Intégrations, Clés API, et coche pour chacune ce qu’elle peut faire. À la création, une fenêtre affiche la clé complète, pk_live_ suivi de 32 caractères, avec un bouton pour la copier en entier.
La clé s’envoie depuis votre serveur seulement, jamais depuis une page web, dans l’un de ces deux en-têtes :
x-api-key: pk_live_0123456789abcdef0123456789abcdef
Authorization: Bearer pk_live_0123456789abcdef0123456789abcdefVérifier une clé
GET /v1/me répond avec l’entreprise et les permissions de la clé. C’est le premier appel à faire.
curl https://api.planevia.ca/api/v1/me \
-H "x-api-key: pk_live_0123456789abcdef0123456789abcdef"
{
"success": true,
"data": {
"organization": { "id": "org_1", "name": "Spa Exemple", "slug": "spa-exemple" },
"apiKey": {
"id": "key_1", "name": "CRM", "keyPrefix": "pk_live_01234567",
"permissions": ["clients:read", "bookings:read"],
"expiresAt": null, "createdAt": "2026-10-17T14:02:11.000Z"
}
}
}Permissions
Chaque permission ouvre des routes de l’API de gestion. Une clé sans permission sert seulement à l’API de réservation. Cochez le minimum dont votre outil a besoin.
| Permission | Ouvre |
|---|---|
clients:read | GET /v1/clients GET /v1/clients/:id |
clients:write | POST /v1/clients PATCH /v1/clients/:id |
bookings:read | GET /v1/bookings GET /v1/bookings/:id |
professionals:read | GET /v1/professionals |
receipts:read | GET /v1/receipts GET /v1/receipts/:id |
assignments:read | GET /v1/assignments |
assignments:write | POST /v1/assignments DELETE /v1/assignments/:id |
webhooks:manage | GET POST PATCH DELETE sur /v1/webhooks |
Les permissions d’une clé ne se modifient pas : pour en changer, créez une nouvelle clé et révoquez l’ancienne. Une clé révoquée est refusée immédiatement.
Limites d’appels
API de gestion : 120 appels par minute et par clé, toutes routes confondues.
API de réservation : ses routes sont les mêmes que celles de la page de réservation de l’entreprise et répondent aussi sans clé. La clé y relève certaines limites quand toutes les demandes partent d’un même serveur :
API de réservation, 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 |
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.
API de gestion
Base : https://api.planevia.ca/api/v1. La clé est obligatoire et chaque route exige sa permission. Toutes les réponses ont la même forme :
{ "success": true, "data": { … } }
{ "success": true, "data": [ … ], "pagination": { "page": 1, "limit": 50, "total": 132, "totalPages": 3 } }
{ "success": false, "error": { "code": "permission_manquante", "message": "…" } }Formats
- Dates sans heure (rendez-vous, naissance) :
AAAA-MM-JJ. - Moments précis (création, modification, paiement) : ISO 8601 en UTC, par exemple
2026-10-17T14:02:11.000Z. - Heures de rendez-vous :
HH:MM, heure locale de l’entreprise. - Montants : nombres en dollars canadiens, deux décimales, taxes à part (
taxTPS,taxTVQ). - Corps des requêtes : JSON, avec l’en-tête
Content-Type: application/json.
Pagination
Les listes prennent page (à partir de 1) et limit (50 par défaut, 100 au plus). Lisez les pages jusqu’à totalPages. Pour une synchronisation, gardez l’heure de votre dernier passage et demandez seulement ce qui a changé depuis avec updatedSince : les clients sont triés du plus ancien changement au plus récent.
Erreurs
| HTTP | code | Signifie |
|---|---|---|
401 | cle_manquante | Aucune clé dans la requête |
401 | cle_invalide | Clé inconnue, incomplète ou révoquée |
401 | cle_expiree | Clé arrivée à sa date d’expiration |
403 | permission_manquante | La clé n’a pas la permission de cette route |
403 | compte_inactif | Abonnement de l’entreprise terminé ou suspendu |
403 | limite_forfait | Plafond de clients du forfait atteint |
400 | parametre_invalide donnees_invalides | Paramètre ou corps mal formé ; le message nomme le champ |
404 | introuvable route_inconnue | Fiche absente de cette entreprise, ou adresse inconnue |
409 | doublon | Un client a déjà ce courriel |
429 | trop_de_requetes | Plus de 120 appels dans la minute |
500 | erreur_interne | Panne de notre côté : réessayez |
Lisez error.code dans votre programme ; error.message est écrit pour le développeur, en français.
Clients
| Appel | Paramètres | Fait |
|---|---|---|
GET /v1/clients | updatedSince email externalId isActive page limit | Liste les clients |
GET /v1/clients/:id | Lit un client | |
POST /v1/clients | Corps JSON | Crée un client |
PATCH /v1/clients/:id | Corps JSON | Modifie seulement les champs envoyés |
{
"id": "cli_1",
"firstName": "Camille",
"lastName": "Tremblay",
"email": "camille@exemple.com",
"phone": "418-555-0142",
"phoneSecondary": null,
"address": "12 rue des Érables", "city": "Québec", "province": "QC", "postalCode": "G1R 1A1",
"dateOfBirth": "1990-01-02",
"gender": "FEMME",
"preferredLanguage": "FR",
"smsOptIn": true,
"acceptsMarketing": false,
"tags": ["vip"],
"isActive": true,
"isVip": false,
"externalId": "crm-42",
"branchId": null,
"totalVisits": 7,
"lastVisitAt": "2026-10-02T15:00:00.000Z",
"createdAt": "2025-03-11T13:20:00.000Z",
"updatedAt": "2026-10-02T16:04:51.000Z"
}Créer et modifier
Obligatoires à la création : firstName, lastName, phone. Modifiables : firstName lastName email phone phoneSecondary address city province postalCode dateOfBirth gender (HOMME, FEMME, AUTRE, NON_SPECIFIE) preferredLanguage (FR, EN) smsOptIn acceptsMarketing tags externalId. Envoyez null pour vider un champ facultatif.
{
"firstName": "Camille",
"lastName": "Tremblay",
"phone": "418-555-0142",
"email": "camille@exemple.com",
"dateOfBirth": "1990-01-02",
"externalId": "crm-42"
}La réponse 201 contient le client créé. Le courriel est unique dans l’entreprise : s’il existe déjà, la réponse est 409 doublon avec l’identifiant de la fiche existante dans error.existingId, à modifier avec PATCH. Gardez votre propre identifiant dans externalId : GET /v1/clients?externalId=crm-42 retrouve la fiche.
Un champ inconnu ou protégé est refusé et nommé dans le message, jamais ignoré en silence. Les champs en lecture seule d’une réponse (id, createdAt, totalVisits…) sont tolérés : vous pouvez renvoyer un client tel que lu, après l’avoir modifié. La suppression d’un client se fait dans Planevia.
Rendez-vous et professionnelles
| Appel | Paramètres | Fait |
|---|---|---|
GET /v1/bookings | from to status professionalId clientId updatedSince page limit | Liste les rendez-vous, du plus tôt au plus tard |
GET /v1/bookings/:id | Lit un rendez-vous | |
GET /v1/professionals | Liste les professionnelles actives |
from et to sont des dates AAAA-MM-JJ, bornes comprises. status accepte une ou plusieurs valeurs séparées par des virgules : PENDING, CONFIRMED, CHECKED_IN, IN_PROGRESS, COMPLETED, NO_SHOW, CANCELLED, RESCHEDULED.
{
"success": true,
"data": [
{
"id": "bk_1", "bookingNumber": "BK1790694045669",
"clientId": "cli_1", "professionalId": "usr_1",
"serviceId": "svc_1", "serviceVariantId": "var_60", "serviceName": "Massage suédois 60 min",
"date": "2026-10-20", "startTime": "09:00", "endTime": "10:00", "duration": 60,
"status": "CONFIRMED", "source": "ONLINE", "branchId": null,
"subtotal": 103.00, "discountAmount": 0, "taxTPS": 5.15, "taxTVQ": 10.27,
"total": 118.42, "depositAmount": 0,
"createdAt": "2026-10-15T14:02:11.000Z", "updatedAt": "2026-10-15T14:02:11.000Z"
}
],
"pagination": { "page": 1, "limit": 50, "total": 1, "totalPages": 1 }
}{ "id": "usr_1", "firstName": "Marie", "lastName": "Dubois", "email": "marie@exemple.com",
"title": "Massothérapeute", "specialties": ["Deep tissue"], "photoUrl": null, "branchId": null }Pour créer un rendez-vous, utilisez POST /bookings de l’API de réservation : il applique les horaires, les règles et l’acompte de l’entreprise.
Reçus
| Appel | Paramètres | Fait |
|---|---|---|
GET /v1/receipts | from to status clientId updatedSince page limit | Liste les reçus émis, par date de facture |
GET /v1/receipts/:id | Lit un reçu avec ses lignes |
from et to portent sur la date de facture, bornes comprises. Statuts : PENDING, PAID, PARTIAL, OVERDUE, VOID, REVERSED, REFUNDED. Les brouillons ne sont jamais exposés. Un renversement est un reçu à montants négatifs qui nomme celui qu’il annule dans reversalOfInvoiceId.
{
"id": "inv_1", "invoiceNumber": "INV-2026-0020", "clientId": "cli_1",
"bookingIds": ["bk_1"], "type": "SERVICE", "status": "PAID",
"invoiceDate": "2026-10-20T13:05:00.000Z", "paidAt": "2026-10-20T13:06:12.000Z",
"subtotal": 103.00, "discountAmount": 0, "taxTPS": 5.15, "taxTVQ": 10.27,
"total": 118.42, "amountPaid": 118.42, "amountDue": 0,
"branchId": null, "reversalOfInvoiceId": null,
"items": [
{ "description": "Massage suédois 60 min", "quantity": 1, "unitPrice": 103.00,
"discountAmount": 0, "total": 103.00, "serviceId": "svc_1", "productId": null, "isTaxExempt": false }
],
"createdAt": "2026-10-20T13:05:00.000Z", "updatedAt": "2026-10-20T13:06:12.000Z"
}Assignations
Une assignation relie un client à la professionnelle qui le suit. isPrimary désigne la professionnelle attitrée ; autoAssigned vaut true quand Planevia l’a créée lui-même à la confirmation d’un rendez-vous.
| Appel | Paramètres | Fait |
|---|---|---|
GET /v1/assignments | clientId professionalId page limit | Liste les assignations |
POST /v1/assignments | clientId professionalId isPrimary | Assigne une professionnelle à un client |
DELETE /v1/assignments/:id | Retire l’assignation |
POST se rejoue sans risque : si l’assignation existe déjà, elle est renvoyée telle quelle (200), ou mise à jour si isPrimary change. Une nouvelle professionnelle attitrée retire ce titre à l’ancienne.
Santé et journal
Aucun renseignement de santé ne sort par l’API. Ni notes de séance, ni dossier de massothérapie ou d’esthétique, ni zones de douleur, ni formulaires d’accueil, ni allergies, conditions médicales ou assurances. Les notes libres de la fiche client et les notes internes ne sortent pas non plus : on ne peut pas garantir qu’elles n’en contiennent pas.
Exception à connaître : les webhooks de rendez-vous transmettent booking.notes, la note que le client a lui-même écrite en réservant. La synchronisation externe est un cas à part : le propriétaire la branche sur sa propre plateforme et choisit ce qu’elle échange.
Journal des appels
Chaque appel fait avec une clé, sur l’une ou l’autre API, est inscrit au journal : le moment, la méthode, l’adresse appelée, le code de réponse, la durée, l’adresse IP et la clé qui l’a fait. Le propriétaire le consulte dans Réglages, Intégrations, Journaux API.
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. Avec la permission webhooks:manage, votre outil peut aussi les gérer lui-même par l’API de gestion.
| É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 : dans une fenêtre à copier, ou dans la réponse de POST /v1/webhooks. 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);
});Toute autre technologie convient de la même façon (Java, Ruby, Go…) : calculez le HMAC SHA-256 du corps brut avec le secret, en hexadécimal minuscule, et comparez-le à l’en-tête avec une comparaison à temps constant. Lisez le corps tel quel, avant tout décodage JSON : un corps re-sérialisé ne donne plus la même signature.
Gérer par l’API
| Appel | Corps | Fait |
|---|---|---|
GET /v1/webhooks | Liste les webhooks | |
POST /v1/webhooks | url events | Crée un webhook ; la réponse porte son secret, une seule fois |
PATCH /v1/webhooks/:id | url events isActive | Modifie, met en pause ou réactive |
DELETE /v1/webhooks/:id | Supprime le webhook et son journal |
url doit être une adresse publique en https://. events est une liste prise dans le tableau des événements ci-dessus.
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.
Synchronisation externe
Ici, c’est Planevia qui appelle votre API. Le propriétaire la branche dans Réglages, Intégration externe : adresse de base, authentification (Bearer, Basic, en-tête X-API-Key ou OAuth 2) et chemins. Elle tient les fiches clients alignées dans un sens ou dans les deux.
{
"listClients": "/clients",
"createClient": "/clients",
"updateClient": "/clients/:id",
"listProfessionals": "/staff",
"listBranches": "/branches",
"getClientNotes": "/clients/:clientId/notes",
"createNote": "/clients/:clientId/notes",
"listDossiers": "/clients/:clientId/records",
"healthCheck": "/health",
"webhookSecret": "un-long-secret-aleatoire"
}Seuls les chemins présents sont utilisés. :id et :clientId sont remplacés par l’identifiant de la fiche chez vous. Facultatifs aussi : createBooking, createReceipt et updateReceipt, pour recevoir les rendez-vous et les reçus.
Ce que Planevia lit chez vous
GET listClients?page=1&limit=50, page après page. Pour les clients modifiés, Planevia ajoute updated_since (ISO 8601) : renvoyez seulement les fiches modifiées depuis ce moment. La réponse peut être une liste, ou un objet qui la contient :
{
"data": [
{
"id": "42",
"firstName": "Camille",
"lastName": "Tremblay",
"email": "camille@exemple.com",
"phone": "418-555-0142",
"dateOfBirth": "1990-01-02"
}
],
"pagination": { "totalPages": 3 }
}Sont acceptés aussi une liste seule, { "results": [ … ] } et { "data": { "clients": [ … ] } }. Planevia s’arrête à pagination.totalPages, ou à la première page de moins de 50 fiches. L’identifiant est lu dans id, _id ou externalId.
Champs échangés
firstName lastName email phone phoneSecondary address city province postalCode dateOfBirth gender occupation notes. Si vos noms diffèrent, le propriétaire les relie dans l’onglet Mapping de champs, y compris pour un champ imbriqué (contact.courriel). La date de naissance s’accepte en AAAA-MM-JJ ou en ISO 8601. Un champ absent de votre réponse n’est jamais effacé dans Planevia.
Ce que Planevia vous envoie
À chaque création ou modification d’une fiche dans Planevia : PUT updateClient si la fiche a déjà un identifiant chez vous, sinon POST createClient. Le corps contient les champs reliés, sous vos noms ; sans mapping, les champs de contact (tous ceux ci-dessus sauf occupation et notes) sous leurs noms Planevia. Une fiche créée ou modifiée par l’API de gestion part de la même façon. Répondez à POST avec l’identifiant créé, dans id ou data.id : sans lui, Planevia consigne une erreur plutôt que de recréer la fiche à chaque modification.
Les notes partent vers createNote si ce chemin existe, sauf les notes privées d’une professionnelle. Les dossiers ne vont que de votre plateforme vers Planevia.
Conflits
Planevia garde la dernière version reçue de chaque fiche et compare champ par champ. Si seul votre côté a changé un champ, Planevia le prend. Si seul Planevia l’a changé, il le garde et vous l’envoie. Si les deux l’ont changé différemment :
- en bidirectionnel, le champ n’est pas touché ; le propriétaire voit les deux valeurs et choisit. « Garder Planevia » vous renvoie la fiche, « Garder la plateforme » applique votre valeur ;
- en import seulement, votre plateforme fait foi et sa valeur l’emporte.
Rythme et webhook
Les clients modifiés sont relus selon l’intervalle choisi par le propriétaire, de 5 à 1 440 minutes, depuis la dernière lecture réussie : une panne ne fait rien perdre. Pour une mise à jour immédiate, appelez :
POST https://api.planevia.ca/api/external-integration/webhook/{organizationId}/client-created
x-webhook-secret: un-long-secret-aleatoireLe secret est celui de webhookSecret ; sans lui, l’appel est refusé. Planevia relit alors les clients modifiés depuis sa dernière synchronisation. Le corps de la requête n’est pas lu.
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.
- Déplacer ou annuler un rendez-vous sans le lien du client.
- Supprimer ou fusionner une fiche client.
- Vendre ou gérer une carte-cadeau.
- Recevoir un webhook de paiement, de client ou de carte-cadeau. Pour suivre les clients, interrogez
GET /v1/clients?updatedSince=…à intervalle régulier.
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é.