Backend·9 min de lecture·1,626 mots

Contrats API backend

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éthodeRouteBody / ParamsRé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éthodeRouteDescription
GET/api/mobile/healthHealthcheck container
GET/api/mobile/homeAgrège vitrines[6] + produits[8] + prestations[6] + categories[] (Accueil mobile)
GET/api/mobile/vitrinesLIST 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/catalogueLIST produits — tenantId, categorie, q (search), paginé
GET/api/mobile/produit/[id]DETAIL produit (variantes + specs + médias + tenant)
GET/api/mobile/prestationsLIST prestations
GET/api/mobile/prestation/[id]DETAIL prestation
GET/api/mobile/[slug]/paiementModes paiement acceptés par tenant (templates USSD avec {MONTANT})
GET/api/mobile/[slug]/disponibilitesCréneaux disponibles RDV (date row 14j + slots)
GET/api/mobile/categories-vitrinesListe CategorieWari (12 + sous-cat)
GET/api/mobile/marketsListe markets internationaux
GET/api/mobile/searchRecherche texte + image (Anthropic Vision V1, Typesense V2)
POST/api/mobile/restaurant/table/[qrToken]Lookup table → tenant + table + config
POST/api/mobile/restaurant/commandesCré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-commandesHistorique 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éthodeRouteDescription
GET/api/mobile/commandesHistorique commandes (?enCours=1&page=N)
POST/api/mobile/commandesCréation commande (transaction Prisma, decrement stock, push gérant, email)
POST/api/mobile/reservationsCréation RDV (transaction overlap-check, email iCal best-effort, push tenant)
GET/api/mobile/reservationsMes RDV (liste + tenant + prestation)
DELETE/api/mobile/reservations/[id]Annulation (422 si délai dépassé)
GET/api/mobile/abonnements/vitrinesVitrines suivies
POST/DELETE/api/mobile/abonnements/vitrines/[tenantId]Follow / unfollow
GET/api/mobile/feed-vitrines-suiviesTop 20 produits récents vitrines suivies (1 req)
GET/api/mobile/acces/mes-demandesListe demandes accès vitrine du client
POST/api/mobile/acces/demanderDemande accès (idempotent : EN_ATTENTE → update contexte)
DELETE/api/mobile/acces/[id]Annuler demande EN_ATTENTE
POST/api/mobile/push-tokens/registerEnregistrer token push (discrimination role)
DELETE/api/mobile/push-tokens/deleteLogout
GET/api/mobile/conversationsMessagerie : threads
POST/api/mobile/conversations/[id]/messagesEnvoyer message
GET/api/mobile/reviews/...CRUD avis
GET/api/mobile/wishlistFavoris backend

Bearer TENANT_ADMIN requis

MéthodeRouteDescription
POST/api/mobile/vitrine/loginEmail + password → Bearer JWT TENANT_ADMIN
GET/api/mobile/vitrine/dashboardKPIs + sparkline + top produits + alertes stock + demandesEnAttente
GET/api/mobile/vitrine/parametresLecture full tenant + configAcces + configPaiement + configRestaurant
PATCH/api/mobile/vitrine/parametresUpdate tenant (15+ champs + categoriesWariIds + configAcces)
POST/api/mobile/vitrine/parametres/paiementPATCH ConfigPaiementGerant (validation toggles + numéros requis)
POST/api/mobile/vitrine/parametres/icalGénère / régénère icalToken tenant
GET/api/mobile/vitrine/commandesListe 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]/statutTransition rapide
GET/api/mobile/vitrine/catalogueListe produits gérant (statut/dispo/tri/stockFaible)
POST/api/mobile/vitrine/produitsCré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]/variantesUpsert variantes (delete missing, préserve ids)
PATCH/api/mobile/vitrine/catalogue/[id]/stockAjustement stock
GET/api/mobile/vitrine/servicesListe prestations gérant
POST/api/mobile/vitrine/servicesCréation prestation
GET/PATCH/api/mobile/vitrine/services/[id]CRUD prestation
PATCH/api/mobile/vitrine/services/[id]/configUpsert 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/reservationsListe RDV gérant
PATCH/api/mobile/vitrine/reservations/[id]Transition statut RDV + push client
GET/api/mobile/vitrine/clientesListe clients (filtre originTenantId strict S1)
POST/api/mobile/vitrine/clientes/inviterMagic link wrapper + WhatsApp
GET/api/mobile/vitrine/accesDemandes accès EN_ATTENTE + INVITE
POST/api/mobile/vitrine/acces/statutTransition EN_ATTENTE → APPROUVE/REFUSE (déclenche email + push client)
POST/api/mobile/vitrine/acces/inviterInvitation magic link + AccesVitrine APPROUVE/INVITE
GET/api/mobile/vitrine/mediasMédiathèque tenant
POST/api/mobile/vitrine/medias/uploadUpload média (orphelin avant attach)
GET/POST/PATCH/DELETE/api/mobile/vitrine/restaurant/configConfig 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-qrRegen QR token table
GET/api/mobile/vitrine/restaurant/commandesListe commandes repas
PATCH/api/mobile/vitrine/restaurant/commandes/[id]/statutTransition (mode-aware EN_LIVRAISON réservée LIVRAISON)
GET/POST/PATCH/DELETE/api/mobile/storiesCRUD stories vitrines (5 routes)
POST/api/mobile/notifier/broadcastBroadcast gérant aux abonnés

Webhooks / Cron

MéthodeRouteDescription
POST/api/paydunya/webhookWebhook PayDunya (signature à valider V2)
GET/api/paydunya/redirectRedirect retour paiement
POST/api/cron/rappels-rdvTrigger rappels J-1/H-2 (auth CRON_SECRET)
POST/api/cron/stories-expirationCleanup stories expirées

Routes web admin (/api/admin/*)

Cookie superapp_session requis. ~50 routes — équivalent web des routes mobile gérant.

FamillesSous-routes
/api/admin/catalogueCRUD produits + variantes + modèles + catégories
/api/admin/servicesCRUD prestations
/api/admin/commandesGestion commandes
/api/admin/clientesGestion clients
/api/admin/mediasMédiathèque + upload
/api/admin/parametresRéglages
/api/admin/vitrine/builderSnapshots, sections, blocs, pages, templates
/api/admin/accesDemandes accès
/api/admin/setupOnboarding wizard 7 étapes

Routes superadmin (/api/superadmin/*)

Cookie superapp_session + role === "SUPER_ADMIN". ~20 routes — gestion globale plateforme.

FamillesRoutes
/api/superadmin/tenantsCRUD tenants, filtres statut/modules/période
/api/superadmin/usersCRUD users
/api/superadmin/categoriesGestion CategorieWari (12 + 67 sous-cat)
/api/superadmin/logsAudit log + recherche
/api/superadmin/healthHealthcheck global

Routes panier (web cookie)

MéthodeRouteDescription
GET/api/panierLecture panier
POST/api/panierAjouter ligne
PATCH/api/panier/[ligneId]Update quantité
DELETE/api/panier/[ligneId]Suppression
POST/api/panier/convertirConversion panier → Commande(s) (1 par vitrine) + decrement stock + push gérants + emails

Routes diverses

RouteDescription
/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 sendPushToX sont 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).