API Contracts — Backend
280 routes au total. 186 sous /api/mobile/*. App Router Route Handlers
(src/app/api/<path>/route.ts).
Conventions communes
- Auth :
getSessionFromRequest(req)(lib/auth/session.ts) lit cookie OU Bearer. - Body validation : Zod systématique sur POST/PATCH.
- Status codes : 200/201/204 succès, 400/422 validation, 401/403 auth, 404 not found, 409 conflit, 500 serveur.
- Format réponse : JSON. Erreurs
{ error: string, code?, details? }. Succès = body data direct (pas d'enveloppe{ok:true,...}systématique). - Tenant resolution : prod via host header
*.wari.pro; dev via?tenant=<slug>. - Pagination :
?page=N&pageSize=20; réponse{ items, total, page, pageSize, totalPages }.
Authentification
Public
| Méthode | Route | Body / Params | Réponse |
|---|---|---|---|
| POST | /api/auth/client/magic-link | { identifier (email|phone), canal? } | { magicLink, expiresIn: 900, otp: "******" } (OTP envoyé Resend/Vonage) |
| POST | /api/auth/client/verifier | { identifier } | { exists, hasPassword } |
| POST | /api/auth/client/profil | { nom, prenom, dateNaissance?, ... } | { ok, clientAccount } |
| POST | /api/auth/login | { email, password } | Set-Cookie + { user, tenant? } — TENANT_ADMIN web |
| POST | /api/mobile/auth | { identifier, otp } ou { identifier, token } | { bearerToken, user, tenant, isNewClient } |
| GET | /api/mobile/session | (Bearer) | { connected, user, tenant } |
Helpers
lib/auth/session.ts.getSessionFromRequest(req)— source de vérité unique.- Payload JWT :
{ userId, role: "CLIENT"|"TENANT_ADMIN"|"SUPER_ADMIN", tenantId: string|null }. - Secret
NEXTAUTH_SECRET— partagé cookie + Bearer.
Routes mobile (/api/mobile/* — 186)
Public (sans Bearer)
| Méthode | Route | Description |
|---|---|---|
| GET | /api/mobile/health | Healthcheck container |
| GET | /api/mobile/home | Agrège vitrines[6] + produits[8] + prestations[6] + categories[] (Accueil mobile) |
| GET | /api/mobile/vitrines | LIST tenants — filtres categorieId, type (boutique/prestataire/mixte), ville, pays. Filtre niveauAcces (Bearer optionnel pour élargir aux CONNEXION+SUR_DEMANDE) |
| GET | /api/mobile/vitrines/[subdomain] | DETAIL tenant (teaser 200 si INVITATION sans accès) |
| GET | /api/mobile/catalogue | LIST produits — tenantId, categorie, q (search), paginé |
| GET | /api/mobile/produit/[id] | DETAIL produit (variantes + specs + médias + tenant) |
| GET | /api/mobile/prestations | LIST prestations |
| GET | /api/mobile/prestation/[id] | DETAIL prestation |
| GET | /api/mobile/[slug]/paiement | Modes paiement acceptés par tenant (templates USSD avec {MONTANT}) |
| GET | /api/mobile/[slug]/disponibilites | Créneaux disponibles RDV (date row 14j + slots) |
| GET | /api/mobile/categories-vitrines | Liste CategorieWari (12 + sous-cat) |
| GET | /api/mobile/markets | Liste markets internationaux |
| GET | /api/mobile/search | Recherche texte + image (Anthropic Vision V1, Typesense V2) |
| POST | /api/mobile/restaurant/table/[qrToken] | Lookup table → tenant + table + config |
| POST | /api/mobile/restaurant/commandes | Création commande repas (validation mode, plat dispo, options, total serveur) |
| GET | /api/mobile/restaurant/commandes/[id] | Détail commande repas (ownership ID-only si non-auth) |
| GET | /api/mobile/restaurant/mes-commandes | Historique commandes repas du Bearer |
| GET | /api/ical/[token] | Feed iCal tenant (RFC 5545, Cache 300s) |
| GET | /api/ical/reservation/[token] | Single-event ICS par réservation |
Bearer CLIENT requis
| Méthode | Route | Description |
|---|---|---|
| GET | /api/mobile/commandes | Historique commandes (?enCours=1&page=N) |
| POST | /api/mobile/commandes | Création commande (transaction Prisma, decrement stock, push gérant, email) |
| POST | /api/mobile/reservations | Création RDV (transaction overlap-check, email iCal best-effort, push tenant) |
| GET | /api/mobile/reservations | Mes RDV (liste + tenant + prestation) |
| DELETE | /api/mobile/reservations/[id] | Annulation (422 si délai dépassé) |
| GET | /api/mobile/abonnements/vitrines | Vitrines suivies |
| POST/DELETE | /api/mobile/abonnements/vitrines/[tenantId] | Follow / unfollow |
| GET | /api/mobile/feed-vitrines-suivies | Top 20 produits récents vitrines suivies (1 req) |
| GET | /api/mobile/acces/mes-demandes | Liste demandes accès vitrine du client |
| POST | /api/mobile/acces/demander | Demande accès (idempotent : EN_ATTENTE → update contexte) |
| DELETE | /api/mobile/acces/[id] | Annuler demande EN_ATTENTE |
| POST | /api/mobile/push-tokens/register | Enregistrer token push (discrimination role) |
| DELETE | /api/mobile/push-tokens/delete | Logout |
| GET | /api/mobile/conversations | Messagerie : threads |
| POST | /api/mobile/conversations/[id]/messages | Envoyer message |
| GET | /api/mobile/reviews/... | CRUD avis |
| GET | /api/mobile/wishlist | Favoris backend |
Bearer TENANT_ADMIN requis
| Méthode | Route | Description |
|---|---|---|
| POST | /api/mobile/vitrine/login | Email + password → Bearer JWT TENANT_ADMIN |
| GET | /api/mobile/vitrine/dashboard | KPIs + sparkline + top produits + alertes stock + demandesEnAttente |
| GET | /api/mobile/vitrine/parametres | Lecture full tenant + configAcces + configPaiement + configRestaurant |
| PATCH | /api/mobile/vitrine/parametres | Update tenant (15+ champs + categoriesWariIds + configAcces) |
| POST | /api/mobile/vitrine/parametres/paiement | PATCH ConfigPaiementGerant (validation toggles + numéros requis) |
| POST | /api/mobile/vitrine/parametres/ical | Génère / régénère icalToken tenant |
| GET | /api/mobile/vitrine/commandes | Liste paginée + filtre statut |
| GET | /api/mobile/vitrine/commandes/[id] | Détail + lignes |
| PATCH | /api/mobile/vitrine/commandes/[id] | Statut + statutPaiement + refPaiement (transitions validées) + push client + email |
| PATCH | /api/mobile/vitrine/commandes/[id]/statut | Transition rapide |
| GET | /api/mobile/vitrine/catalogue | Liste produits gérant (statut/dispo/tri/stockFaible) |
| POST | /api/mobile/vitrine/produits | Création produit |
| GET | /api/mobile/vitrine/produits/[id] | Détail produit gérant |
| PATCH | /api/mobile/vitrine/produits/[id] | Update produit |
| DELETE | /api/mobile/vitrine/produits/[id] | Archive (soft) ou delete |
| POST | /api/mobile/vitrine/produits/[id]/variantes | Upsert variantes (delete missing, préserve ids) |
| PATCH | /api/mobile/vitrine/catalogue/[id]/stock | Ajustement stock |
| GET | /api/mobile/vitrine/services | Liste prestations gérant |
| POST | /api/mobile/vitrine/services | Création prestation |
| GET/PATCH | /api/mobile/vitrine/services/[id] | CRUD prestation |
| PATCH | /api/mobile/vitrine/services/[id]/config | Upsert ConfigReservationPrestation |
| GET/POST/PATCH/DELETE | /api/mobile/vitrine/creneaux[/:id] | CRUD créneaux RDV |
| GET/POST/DELETE | /api/mobile/vitrine/indisponibilites[/:id] | CRUD plages indispo |
| GET | /api/mobile/vitrine/reservations | Liste RDV gérant |
| PATCH | /api/mobile/vitrine/reservations/[id] | Transition statut RDV + push client |
| GET | /api/mobile/vitrine/clientes | Liste clients (filtre originTenantId strict S1) |
| POST | /api/mobile/vitrine/clientes/inviter | Magic link wrapper + WhatsApp |
| GET | /api/mobile/vitrine/acces | Demandes accès EN_ATTENTE + INVITE |
| POST | /api/mobile/vitrine/acces/statut | Transition EN_ATTENTE → APPROUVE/REFUSE (déclenche email + push client) |
| POST | /api/mobile/vitrine/acces/inviter | Invitation magic link + AccesVitrine APPROUVE/INVITE |
| GET | /api/mobile/vitrine/medias | Médiathèque tenant |
| POST | /api/mobile/vitrine/medias/upload | Upload média (orphelin avant attach) |
| GET/POST/PATCH/DELETE | /api/mobile/vitrine/restaurant/config | Config restau |
| GET/POST/PATCH/DELETE | /api/mobile/vitrine/restaurant/sections[/:id] | Sections menu |
| GET/POST/PATCH/DELETE | /api/mobile/vitrine/restaurant/plats[/:id] | Plats |
| GET/POST/PATCH/DELETE | /api/mobile/vitrine/restaurant/options[/:id] | Options plats |
| GET/POST/DELETE | /api/mobile/vitrine/restaurant/tables[/:id] | Tables |
| POST | /api/mobile/vitrine/restaurant/tables/[id]/regen-qr | Regen QR token table |
| GET | /api/mobile/vitrine/restaurant/commandes | Liste commandes repas |
| PATCH | /api/mobile/vitrine/restaurant/commandes/[id]/statut | Transition (mode-aware EN_LIVRAISON réservée LIVRAISON) |
| GET/POST/PATCH/DELETE | /api/mobile/stories | CRUD stories vitrines (5 routes) |
| POST | /api/mobile/notifier/broadcast | Broadcast gérant aux abonnés |
Webhooks / Cron
| Méthode | Route | Description |
|---|---|---|
| POST | /api/paydunya/webhook | Webhook PayDunya (signature à valider V2) |
| GET | /api/paydunya/redirect | Redirect retour paiement |
| POST | /api/cron/rappels-rdv | Trigger rappels J-1/H-2 (auth CRON_SECRET) |
| POST | /api/cron/stories-expiration | Cleanup stories expirées |
Routes web admin (/api/admin/*)
Cookie superapp_session requis. ~50 routes — équivalent web des routes mobile gérant.
| Familles | Sous-routes |
|---|---|
/api/admin/catalogue | CRUD produits + variantes + modèles + catégories |
/api/admin/services | CRUD prestations |
/api/admin/commandes | Gestion commandes |
/api/admin/clientes | Gestion clients |
/api/admin/medias | Médiathèque + upload |
/api/admin/parametres | Réglages |
/api/admin/vitrine/builder | Snapshots, sections, blocs, pages, templates |
/api/admin/acces | Demandes accès |
/api/admin/setup | Onboarding wizard 7 étapes |
Routes superadmin (/api/superadmin/*)
Cookie superapp_session + role === "SUPER_ADMIN". ~20 routes — gestion globale plateforme.
| Familles | Routes |
|---|---|
/api/superadmin/tenants | CRUD tenants, filtres statut/modules/période |
/api/superadmin/users | CRUD users |
/api/superadmin/categories | Gestion CategorieWari (12 + 67 sous-cat) |
/api/superadmin/logs | Audit log + recherche |
/api/superadmin/health | Healthcheck global |
Routes panier (web cookie)
| Méthode | Route | Description |
|---|---|---|
| GET | /api/panier | Lecture panier |
| POST | /api/panier | Ajouter ligne |
| PATCH | /api/panier/[ligneId] | Update quantité |
| DELETE | /api/panier/[ligneId] | Suppression |
| POST | /api/panier/convertir | Conversion panier → Commande(s) (1 par vitrine) + decrement stock + push gérants + emails |
Routes diverses
| Route | Description |
|---|---|
/api/og/[...] | Génération OpenGraph dynamique (preview images vitrines + produits) |
/api/realtime/* | SSE endpoints messagerie + notifs |
/api/preview-token/* | Génération tokens preview vitrine |
/api/invitation/... | Acceptation invitation magic link |
/api/cf-stream/* | Cloudflare Stream (vidéos vitrines/prestations) |
/api/search/* | Search marketplace global (Typesense) |
Patterns récurrents
- Push best-effort : tous les hooks
sendPushToXsont try/catch, ne bloquent jamais la réponse. - Email best-effort : pareil — pas de 500 si Resend down.
- Transactions Prisma : utilisées pour les opérations qui mutent plusieurs tables (création commande, réservation, decrement stock, FK update).
- Snapshot d'instructions (
Commande.instructionsPaiement,LigneCommandeRepas.snapshot) : figés au POST pour que le client garde la version vue au moment de la commande même si le tenant change ses settings. - Idempotence : POST acces/demander réutilise EN_ATTENTE existant ; POST push-tokens/register upsert sur token unique.
- Teaser pattern (DETAIL routes INVITATION) : 200 avec
{accessible: false, niveauAcces, nom, logoUrl, description, ...}au lieu de 404, pour permettre au mobile d'afficher AccesRequis avec metadata. - iCal token routes publiques :
GET /api/ical/[token]→ pas d'auth, le token est non-guessable (UUID v4 entropie 122 bits).