Introduction
L'API SwissLivraisonPro permet d'integrer votre systeme de commandes (site web, application, plateforme tierce) avec notre service de livraison. Vous pouvez :
- Envoyer automatiquement des commandes via webhooks
- Suivre les statuts de livraison en temps reel
- Gerer les livreurs et les courses via l'API REST
- Recevoir des callbacks de statut sur votre serveur
Base URL : https://hub.swisslivraisonpro.ch
Authentification
Tokens Webhook
Chaque integration possede un token unique genere automatiquement. Ce token identifie votre restaurant et sa configuration. Il est inclus directement dans l'URL du webhook :
POST /webhook/{votre_token}
Le token est genere lors de la creation de l'integration dans le dashboard, section Integrations.
Cle API (Bearer Token)
Pour les endpoints d'administration, l'authentification se fait via une session admin ou un Bearer token :
Authorization: Bearer {api_key}
Authentification Livreur
Les livreurs s'authentifient via Firebase Auth (email + mot de passe). Deux flows :
- PWA Web :
firebase.auth().signInWithEmailAndPassword(email, pwd)cote client, puisPOST /api/driver/firebase-loginavec{idToken}qui retourne un cookie de session Firebase (HTTP-only, 14j). - APK Android native : Firebase SDK natif, puis
Authorization: Bearer <Firebase idToken>sur chaque appel API.
Les anciens endpoints /api/driver/login (phone/password), /api/driver/forgot-password et /api/driver/reset-password ont ete retires en Phase 3 de la migration. Le reset password est desormais natif Firebase via sendPasswordResetEmail().
Webhook - Reception de commandes
POST /webhook/{token}
Point d'entree universel pour recevoir des commandes depuis n'importe quelle plateforme (Just Eat, Uber Eats, WooCommerce, Shopify, ou systeme personnalise).
Fonctionnement
- Creez une integration dans le dashboard pour obtenir un token
- Configurez le mapping des champs si necessaire
- Envoyez vos commandes en POST JSON vers
/webhook/{token} - La commande est normalisee, creee et automatiquement dispatchee aux livreurs
Reponse succes
{
"ok": true,
"order_id": 42,
"source_order_id": "ORD-12345",
"fleet_id": null,
"dispatch_result": "internal"
}
Valeurs principales de dispatch_result : internal (dispatch automatique lance), manual (attribution manuelle — aucune flotte liee, mode manuel, ou aucun livreur trouve apres cascade), waiting_for_ready / waiting_for_prep (en attente que la commande soit prete en cuisine), scheduled (pre-commande : heure souhaitee eloignee — dispatch differe automatiquement a l'approche), paused (restaurant en pause : commande enregistree et mise en attente, dispatchee automatiquement a la reprise). Une commande deja recue renvoie {"ok": true, "status": "duplicate"} avec l'id existant (pas de dispatch_result).
Plateformes supportees
| Plateforme | Mapping | Statut callback |
|---|---|---|
| Just Eat | Automatique | Oui |
| Uber Eats | Automatique | Oui |
| WooCommerce | Automatique | Oui |
| Shopify | Automatique | Oui |
| Shipday | Automatique | Sync natif Shipday (sortant) |
| ZipZest | Automatique | Oui (statut interne brut) |
| Chataigne (chatbot WhatsApp) | Automatique | Oui (statut interne brut) |
| Wix (snippet Velo ou Automation no-code) | Automatique | Non (suivi client SLP) |
| Personnalise | Configurable | Configurable |
Format du payload de commande
Pour les integrations personnalisees, le mapping des champs est configure a la creation de l'integration (aucun mapping n'est implicite). Le format canonique recommande — celui configure par defaut — est le suivant :
{
"id": "ORD-12345",
"restaurantName": "Pizza Roma",
"restaurantAddress": "Rue du Marche 12, 1204 Geneve",
"customerName": "Jean Dupont",
"customerPhoneNumber": "+41 79 123 45 67",
"customerEmail": "jean@example.com",
"deliveryAddress": "Avenue de la Gare 5, 1003 Lausanne",
"deliveryLatitude": 46.5197,
"deliveryLongitude": 6.6323,
"comments": "3e etage, sonner interphone",
"total": 42.50,
"itemsDescription": "1x Pizza Margherita, 2x Coca 33cl",
"expectedTime": "2026-08-09T18:30:00Z"
}
Champs
| Champ | Type | Requis | Description |
|---|---|---|---|
id | string | Oui | Identifiant unique de la commande (seul champ obligatoire — 400 no_order_id sinon) |
restaurantName | string | Recommande | Nom du restaurant — sans lui, le point de collecte s'affiche sans nom pour le livreur |
restaurantAddress | string | Non | Adresse de collecte (defaut : adresse du commercant) |
customerName | string | Recommande | Nom du client |
customerPhoneNumber | string | Recommande | Telephone du client (contact livreur + suivi SMS) |
customerEmail | string | Non | Email du client (suivi de commande) |
deliveryAddress | string | Fortement recommande | Adresse de livraison — sans adresse ni coordonnees, la course ne peut pas etre attribuee |
deliveryLatitude | float | Non | Latitude de livraison (sinon geocodage serveur de l'adresse) |
deliveryLongitude | float | Non | Longitude de livraison (sinon geocodage serveur de l'adresse) |
comments | string | Non | Instructions de livraison (etage, code d'entree...) — affichees au livreur |
total | float | Non | Montant de la commande (CHF) |
itemsDescription | string | Non | Resume des articles (max 1000 caracteres) |
requestedTime | string | Non | Heure de livraison demandee par le client, ISO 8601 avec fuseau (ex. 2026-08-20T20:00:00+02:00 ou ...18:00:00Z) — declaration explicite, prise telle quelle. Proche (< 4 h, meme jour, ex. commande a 17 h pour 20 h) : la commande est creee immediatement et la course est calee sur cette heure (livraison visee = heure demandee, pas de livreur mobilise en avance). Eloignee (>= 4 h ou un autre jour) : cree une pre-commande programmee (dispatch_result = "scheduled", dispatch differe a l'approche de l'heure). Absente = livraison au plus vite (ASAP). Sans fuseau ou illisible : ignoree. Recommande des que votre systeme connait l'heure voulue par le client |
expectedTime | string | Non | Heure de livraison estimee/annoncee par votre plateforme, ISO 8601 avec fuseau. Si elle porte la signature d'un vrai creneau choisi par le client (minutes rondes, >= 75 min dans le futur), elle est traitee comme requestedTime ci-dessus ; sinon elle est informative. Preferez requestedTime quand vous connaissez la demande du client. Valeur illisible ignoree |
Mapping personnalise
Si votre payload utilise des noms de champs differents, configurez un field_mapping lors de la creation de l'integration :
{
"field_mapping": {
"order_id": "order_number",
"restaurant_name": "shop.name",
"customer_name": "client.fullName",
"delivery_address": "client.address.street",
"delivery_lat": "client.address.lat",
"delivery_lng": "client.address.lng"
}
}
Les chemins supportent la notation pointee pour les objets imbriques (ex: client.address.street) et les index de liste (ex: items.0.name).
Cles de mapping disponibles : order_id, restaurant_name, restaurant_address, customer_name, customer_name_last (nom de famille, concatene au prenom), customer_phone, customer_email, delivery_address, delivery_lat, delivery_lng, delivery_instructions, total, items_description, expected_time, pickup_lat, pickup_lng, order_number (numero de ticket AFFICHE au livreur/restaurant quand il differe de order_id — order_id reste l'identifiant unique qui deduplique).
Statuts de livraison
Chaque commande passe par les statuts suivants :
| Statut | Description | Declencheur |
|---|---|---|
| received | Commande recue, preparation en cuisine | Systeme / Resto |
| pending | Prete, en attente d'un livreur (dispatch) | Systeme |
| accepted | Livreur a accepte la course | Livreur |
| to_restaurant | En route vers le restaurant | Livreur |
| at_restaurant | Arrive au restaurant | Livreur |
| collected | Commande recuperee | Livreur |
| to_customer | En route vers le client | Livreur |
| delivered | Commande livree | Livreur |
| Statuts non nominaux | ||
| on_hold | En attente (cuisine pas prete ou aucun livreur dispo) | Systeme |
| rejected | Course refusee par le livreur (re-dispatch) | Livreur |
| cancelled | Commande annulee | Resto / Systeme |
| returned | Colis retourne au restaurant | Livreur |
| failed | Echec de livraison | Systeme |
Callbacks de statut
Si vous configurez un status_push_url sur votre integration, SwissLivraisonPro enverra un POST a cette URL a chaque changement de statut :
POST {votre_status_push_url}
Content-Type: application/json
Authorization: Bearer {votre_api_key}
{
"order_id": "ORD-12345",
"status": "InDelivery",
"internal_status": "collected"
}
Le champ status est traduit selon le mapping de votre plateforme. Le champ internal_status contient toujours le statut interne SwissLivraisonPro.
Rejeu en cas d'echec
Si votre endpoint ne repond pas (timeout 10 s) ou repond en erreur (HTTP ≥ 400), le callback est rejoue automatiquement : jusqu'a 4 nouvelles tentatives espacees de 1, 5, 15 puis 60 minutes (~1 h 20 de couverture), puis abandon. Seul le dernier statut de chaque commande est rejoue — vous ne recevrez jamais un statut plus ancien apres un plus recent ; des etapes intermediaires peuvent etre sautees. Prevoyez un traitement idempotent (le meme statut peut arriver deux fois en cas de timeout).
Environnement de test (sandbox)
Un compte de test isole est disponible sur demande pour developper votre integration sans toucher a l'operationnel :
- Isolement total : le commercant de test n'est rattache a aucune flotte — aucun livreur reel n'est jamais sollicite, aucune notification operationnelle.
- Livraison simulee : chaque commande envoyee au webhook progresse automatiquement dans le cycle de vie reel (
accepted→to_restaurant→at_restaurant→collected→to_customer→delivered, ~5 minutes bout-en-bout) — vos callbacksstatus_push_urlsont declenches a chaque etape, exactement comme en production — rejeu automatique compris (voir Rejeu en cas d'echec). Une heure demandee (requestedTime, ouexpectedTimedetectee comme creneau client) est respectee : la simulation se cale pour livrer a l'heure demandee (une commande « pour 20 h » reste silencieuse jusqu'a ~19 h 55). - Aucune communication client : les emails et SMS de suivi sont coupes pour le compte de test — vous pouvez utiliser des coordonnees fictives sans risque.
- Passage en production : meme format, meme mecanique — seul le token webhook change.
Demandez votre token sandbox a l'equipe SwissLivraisonPro, puis gerez tout en autonomie depuis l'Espace developpeur : configuration de vos callbacks (URL + Bearer), envoi de commandes de test et suivi de leur progression en direct.
API Livreur
Tous les endpoints livreur utilisent le prefixe /api/driver et l'authentification Firebase (ID token en Authorization: Bearer pour l'app native, ou cookie de session Firebase pour le web — cf. section Authentification). Ces endpoints sont internes aux apps livreur SwissLivraisonPro.
Commandes
| Methode | Endpoint | Description |
|---|---|---|
| GET | /api/driver/orders | Liste des commandes assignees |
| GET | /api/driver/orders/{id} | Detail d'une commande |
| POST | /api/driver/orders/{id}/accept | Accepter une course |
| POST | /api/driver/orders/{id}/reject | Refuser une course |
| POST | /api/driver/orders/{id}/to-restaurant | En route vers le restaurant |
| POST | /api/driver/orders/{id}/at-restaurant | Arrive au restaurant |
| POST | /api/driver/orders/{id}/collected | Commande recuperee |
| POST | /api/driver/orders/{id}/to-customer | En route vers le client |
| POST | /api/driver/orders/{id}/deliver | Commande livree |
| POST | /api/driver/orders/{id}/scan-qr | Valider le ramassage par scan QR |
| POST | /api/driver/orders/{id}/problem | Signaler un probleme |
| POST | /api/driver/orders/{id}/request-replacement | Demander un remplacant (panne / transfert sur place) |
| POST | /api/driver/orders/{id}/forgotten-items | Signaler un oubli d'article (cree une commande complement) |
Localisation & statut
| Methode | Endpoint | Description |
|---|---|---|
| POST | /api/driver/location | Mettre a jour la position GPS |
| PUT | /api/driver/status | Changer le statut (online/offline) |
| GET | /api/driver/stats | Statistiques du livreur |
| GET | /api/driver/history | Historique des courses |
| GET | /api/driver/optimized-route | Route optimisee multi-arrets |
| POST | /api/driver/dispatch-ready | Signaler la disponibilite au dispatch (retour en ligne / GPS frais) |
| GET | /api/driver/pending-returns | Colis a retourner au restaurant |
Chat & notifications
Le chat (livreur ↔ client ↔ restaurant, et chat de flotte) est temps reel via Firebase RTDB : l'endpoint d'autorisation pose l'ACL et renvoie le nom du canal, puis le client lit/ecrit directement dans RTDB (live). Les notifications push utilisent FCM (Firebase Cloud Messaging) cote app native. Le Web Push (VAPID) a ete retire.
| Methode | Endpoint | Description |
|---|---|---|
| GET | /api/driver/orders/{id}/chat | Autorise le canal de la commande + renvoie le nom du canal RTDB |
| POST | /api/driver/orders/{id}/chat | Envoyer un message (ecrit dans RTDB) |
| GET | /api/driver/chat/fleet | Autorise le canal de la flotte (chat livreurs) |
| POST | /api/driver/chat/fleet | Envoyer un message dans le chat flotte |
| POST | /api/driver/push/fcm-register | Enregistrer le token FCM (notifications push, app Android) |
API Integrations
Gestion des integrations (necessite authentification admin).
| Methode | Endpoint | Description |
|---|---|---|
| GET | /api/integrations | Lister les integrations |
| POST | /api/integrations | Creer une integration |
| PUT | /api/integrations/{id} | Modifier une integration |
| DELETE | /api/integrations/{id} | Supprimer une integration |
| POST | /api/integrations/{id}/regenerate-token | Regenerer le token |
Creer une integration
POST /api/integrations
Content-Type: application/json
{
"tenant_id": "rest_abc123",
"platform": "custom",
"name": "Mon Site Web",
"status_push_url": "https://monsite.ch/api/delivery-status",
"field_mapping": {
"order_id": "id",
"restaurant_name": "restaurant.name",
"customer_name": "customer.name",
"delivery_address": "customer.address"
}
}
Reponse
{
"ok": true,
"integration_id": 7,
"webhook_url": "/webhook/abc123def456",
"webhook_token": "abc123def456"
}Stock & Disponibilite
La disponibilite des articles suit le modele HubRise : un article se met en rupture temporaire (snooze) sans le retirer du catalogue. Le catalog est le catalogue synchronise (HubRise) ; les articles sont references par sku_ref.
| Methode | Endpoint | Description |
|---|---|---|
| GET | /api/tenant-admin/catalog | Catalogue synchronise (articles + variantes) |
| POST | /api/tenant-admin/catalog/items/{sku_ref}/snooze | Mettre un article en rupture (indispo temporaire) |
| POST | /api/tenant-admin/catalog/items/{sku_ref}/unsnooze | Remettre un article disponible |
| PUT | /api/tenant-admin/catalog/items/{sku_ref}/restrictions | Restrictions de l'article (par canal) |
| PUT | /api/tenant-admin/catalog/items/{sku_ref}/channel-price | Prix specifique par canal |
| DELETE | /api/tenant-admin/catalog/items/{sku_ref}/channel-price/{variant_ref} | Supprimer un prix par canal |
Clients
Base clients du restaurant, synchronisee avec HubRise (import depuis la liste clients HubRise). Authentifiee tenant-admin.
| Methode | Endpoint | Description |
|---|---|---|
| GET | /api/tenant-admin/customers | Liste des clients |
| POST | /api/tenant-admin/customers/pull | Importer / synchroniser les clients depuis HubRise |
| GET | /api/tenant-admin/customers/{id} | Detail d'un client |
| POST | /api/tenant-admin/customers/{id}/delete | Supprimer un client |
Exemples d'integration
Envoyer une commande (curl)
curl -X POST https://hub.swisslivraisonpro.ch/webhook/VOTRE_TOKEN \
-H "Content-Type: application/json" \
-d '{
"id": "CMD-001",
"restaurantName": "Pizzeria Bella",
"restaurantAddress": "Rue de Lausanne 42, 1201 Geneve",
"customerName": "Marie Martin",
"customerPhoneNumber": "+41 78 900 11 22",
"deliveryAddress": "Chemin des Fleurs 8, 1202 Geneve",
"deliveryLatitude": 46.2108,
"deliveryLongitude": 6.1467
}'
Creer une integration (curl)
curl -X POST https://hub.swisslivraisonpro.ch/api/integrations \
-H "Content-Type: application/json" \
-H "Cookie: session=VOTRE_SESSION" \
-d '{
"tenant_id": "rest_abc123",
"platform": "custom",
"name": "Mon Site Web"
}'
Webhook depuis WooCommerce
Dans WooCommerce, allez dans Reglages > Avance > Webhooks :
- Statut : Actif
- Sujet : Commande creee
- URL :
https://hub.swisslivraisonpro.ch/webhook/VOTRE_TOKEN - Version API : WP REST API v3
Webhook depuis Shopify
Dans Shopify, allez dans Parametres > Notifications > Webhooks :
- Evenement : Creation de commande
- URL :
https://hub.swisslivraisonpro.ch/webhook/VOTRE_TOKEN - Format : JSON
Codes d'erreur
| Code HTTP | Erreur | Description |
|---|---|---|
400 | invalid_json | Le corps de la requete n'est pas un JSON valide |
400 | no_order_id | Aucun identifiant de commande trouve |
400 | tenant_id required | Le champ tenant_id est requis |
401 | invalid_token | Token webhook invalide ou integration desactivee |
403 | tenant_disabled | Le commercant est desactive — nouvelles commandes refusees |
401 | unauthorized | Authentification requise |
200 | duplicate | La commande existe deja (retourne l'ID existant) |
Format de reponse d'erreur
{
"error": "invalid_token"
}
Format de reponse succes
{
"ok": true,
...
}
SwissLivraisonPro