ADR-0005 — Patron API B2B « façon Stripe » comme standard DYNORS¶
Date : 2026-05-07 (rédigée rétroactivement 2026-06-30 — backfill ; implémentation FISCAL livrée 2026-04-29)
Catégorie : A (convention d'exposition B2B transverse)
Décideur : Lead architecte DYNORS
Statut : Acceptée (référence FISCAL opérationnelle ; à reproduire pour BOOKS, TRACIUM…)
S'appuie sur : [[0004-perimetre-fige-fiscal-books-paiement]] (FISCAL pilier B2B), [[0018-exposition-hors-prod-sly-edge-chemin]] (exposition par chemin SLY)
Source de vérité : docs/INTEGRATIONS_FACON_STRIPE.md §6 ; fiscal-architecture-cible-vs-existant.md §7 (Décision 5)
Contexte¶
DYNORS veut exposer ses services (FISCAL d'abord, puis BOOKS, TRACIUM…) comme des produits
intégrables par des tiers : un intégrateur s'authentifie avec une clé, appelle l'API, reçoit des
webhooks — sans déployer DYNORS. Si chaque app réinvente son propre schéma d'API publique (format de
clé, route, filtre d'auth, webhooks), on obtient une surface incohérente, difficile à documenter et
à sécuriser. FISCAL a déjà implémenté un patron complet et opérationnel (clés fsk_*, route SLY
/v1/fiscal/**, webhooks whsec_*). Il faut le figer comme standard plutôt que de le laisser
diverger.
Décision¶
Le patron implémenté dans FISCAL est la règle standard pour toute app DYNORS exposant un accès développeur externe. FISCAL est la référence ; les nouvelles surfaces B2B le reproduisent sans le réinventer.
-
Contrat SLY (gateway) pour chaque app
<app>: routePath=/v1/<app>/**+RewritePath=/v1/<app>/(?<s>.*), /api/v1/<app>/external/${s};SlyIdentificationFilterreconnaîtBearer <prefix>_live_*/<prefix>_test_*→ marqueB2B_API_KEYet forwarde sans valider (validation déléguée au backend). L'architecture interne reste opaque pour l'intégrateur. -
Contrat backend pour chaque app : tables
<app>_api_keys(hash SHA-256, prefix, scopes CSV, modelive/test, statut) +<app>_webhook_registrations; filtre<App>ApiKeyAuthFilter@Order(1)sur/api/v1/<app>/external/**;<App>ExternalApiController;<App>ApiKeyController(admin) ;<App>WebhookService(dispatch signé viadynors-webhooksaprès chaque event bus, auto-disable après N échecs). -
Format de clé invariant :
<prefix>_live_<32hex>/<prefix>_test_<32hex>(fsk_FISCAL,bsk_BOOKS,tsk_TRACIUM…). Clé en clair retournée une seule fois, hash stocké. -
Vue développeur invariante :
POST https://api.dynors.com/v1/<app>/<resource>+Authorization: Bearer <prefix>_live_<32hex>. Versioning par préfixe/v1/. Réponses et erreurs homogènes (code,message,request_id). Idempotence viaIdempotency-Key.
Conséquences¶
Positif : expérience développeur homogène sur tout l'écosystème ; sécurité éprouvée réutilisée (pas de filtre d'auth réécrit par app) ; doc et SDK factorisables ; SLY masque les détails internes ; onboarding d'une nouvelle app B2B = appliquer une checklist, pas concevoir.
Coût : chaque app B2B doit créer ses tables, son filtre, son controller externe (boilerplate, mais cadré) ; le préfixe de clé doit être réservé sans collision ; discipline de revue pour refuser toute variante maison.
Composants impactés : dynors-platform/selebeyone (routes), apps exposant du B2B (FISCAL livré ;
BOOKS, TRACIUM candidats), dynors-webhooks, doc developers.dynors.com.
Alternatives écartées¶
- Chaque app invente son API publique : surface incohérente, sécurité hétérogène, doc multipliée. Écartée.
- Un unique service passerelle d'API qui absorbe toutes les apps : recrée un point de couplage et contredit l'autonomie des domaines ([[0004-perimetre-fige-fiscal-books-paiement]]). Écartée au profit du patron répliqué + SLY comme front commun.
Références¶
docs/INTEGRATIONS_FACON_STRIPE.md§6 (règle globale, contrats SLY et backend)dynors-docs/docs/05-architecture-si/fiscal-architecture-cible-vs-existant.md§2.1, §7 (Décision 5)- ADR-0004 (périmètre figé), ADR-0018 (exposition SLY par chemin)