Aller au contenu

DYNORS PAIEMENT — Hub PSP

Application plateforme — Orchestration de tous les paiements de l'écosystème DYNORS via un point d'entrée unique (/paiement/**)


🎯 Objectif

DYNORS PAIEMENT est le hub central d'encaissement de l'écosystème DYNORS. Il orchestre les PSP (Wave, Orange Money, PayTech, PayDunya, Intouch, virement bancaire, paiement international) pour le compte de toutes les applications satellite.

Règle absolue : aucune application métier DYNORS n'intègre directement un SDK PSP. Tout encaissement passe par SLY → /paiement/** → DYNORS PAIEMENT.

Distinction avec dynors-billing

Composant Rôle Nature
DYNORS PAIEMENT Orchestre les PSP (Wave, OM, PayTech…), gère les callbacks, les remboursements et les virements Application autonome (dynors-projects)
dynors-billing Gère les plans d'abonnement SaaS (FREE_TRIAL / SUBSCRIPTION) d'une application Module extension (dynors-extensions) — s'appuie sur DYNORS PAIEMENT pour l'encaissement

📋 Informations générales

Propriété Valeur
Nom DYNORS PAIEMENT
Code app paiement
Type Application plateforme transverse
Repository dynors-projects/dynors-paiement
Route SLY /paiement/**
Port dev 8089
Status 📋 Spécifié — développement à lancer
Spec complète docs/projet-nouveau/DynorsPaiement/DYNORS_PAIEMENT_SYNTHESE_PDF_v1_0.md

🏗️ Architecture

App satellite (SuperGest, Mediconnect, DAWALALE…)
         │
         │ InterAppCallService
         ▼
  SLY — /paiement/**
         │
         ▼
  DYNORS PAIEMENT (port 8089)
         │
   ┌─────┼──────────────────┐
   ▼     ▼                  ▼
 Wave  Orange Money      PayTech / PayDunya
        (OM)              Intouch / Virement

💳 PSP supportés

PSP Pays Type Status
Wave SN, CI, ML, SN Mobile Money ✅ v1
Orange Money SN, CI, CM Mobile Money ✅ v1
PayTech SN Agrégateur ✅ v1
PayDunya SN, CI, GH, BF Agrégateur ✅ v1
Intouch SN, CM Mobile Money ⏳ v2
Virement bancaire Multi-pays Bancaire ⏳ v2
International Monde Stripe-like ⏳ v3

🔌 Intégration depuis une application satellite

Utiliser InterAppCallService (jamais un SDK PSP directement) :

@Service
@RequiredArgsConstructor
public class PaiementClient {

    private final InterAppCallService interApp;

    /** Initier un paiement Wave pour un tenant. */
    public PaiementInitResponse initWave(String tenantCode, PaiementInitRequest req) {
        return interApp.post(
                "/paiement/api/v1/payments/initiate",
                req,
                PaiementInitResponse.class,
                tenantCode
        );
    }

    /** Vérifier le statut d'une transaction. */
    public PaiementStatusResponse status(String tenantCode, String txId) {
        return interApp.get(
                "/paiement/api/v1/payments/" + txId + "/status",
                PaiementStatusResponse.class,
                tenantCode
        );
    }
}

Configuration application.yml (côté app satellite)

dynors:
  interapp:
    source-app: supergest          # code de l'app appelante
    gateway-url: ${SLY_BASE_URL:https://sly.dynors.com}
    sly-forward-secret: ${SLY_FORWARD_SECRET}

Corps d'une requête d'initiation

{
  "provider": "WAVE",
  "amount": 5000,
  "currency": "XOF",
  "customerPhone": "+221771234567",
  "description": "Abonnement SuperGest — Janvier 2026",
  "returnUrl": "https://sly.dynors.com/supergest/callbacks/paiement",
  "metadata": {
    "orderId": "ORD-2026-001",
    "tenantCode": "supergest-dakar"
  }
}

🔄 Flux callback asynchrone

App satellite → POST /paiement/api/v1/payments/initiate
                                │
                     DYNORS PAIEMENT appelle PSP
                                │
                     PSP répond en asynchrone
                                │
                     DYNORS PAIEMENT reçoit callback PSP
                                │
                     DYNORS PAIEMENT notifie l'app via SLY
                     POST /supergest/callbacks/paiement/{txId}

Le returnUrl doit toujours pointer vers https://sly.dynors.com/<code-app>/callbacks/paiement pour que SLY route correctement le callback.


📡 Endpoints principaux

Méthode Path Description
POST /paiement/api/v1/payments/initiate Initier un paiement
GET /paiement/api/v1/payments/{txId}/status Statut d'une transaction
POST /paiement/api/v1/payments/{txId}/refund Remboursement
GET /paiement/api/v1/payments Historique (paginé, filtré par tenant)
POST /paiement/api/v1/bulk Masse salariale (JARAAF — bulk paiement)
GET /paiement/api/v1/providers PSP disponibles par pays

🔐 Sécurité

  • Accès interne : X-Source-App + HMAC SLY uniquement — aucune app externe ne peut appeler /paiement/** directement.
  • Multi-tenant : chaque transaction est isolée par tenantCode issu du JWT/X-Tenant-Id.
  • Idempotence : clé d'idempotence obligatoire sur initiate pour éviter les doublons.
  • Webhook PSP entrant : validé par signature HMAC (secret par PSP, stocké dans Vault).

🗄️ Données

Tables principales (dynors_paiement schema) :

Table Description
dp_transactions Transactions (id, provider, amount, status, tenant, metadata)
dp_callbacks Callbacks PSP reçus (raw + parsed)
dp_providers_config Config par PSP × tenant (clés API chiffrées via Vault)
dp_bulk_payments Paiements en masse (JARAAF masse salariale)

⚙️ Variables d'environnement

# Inter-app SLY
SLY_BASE_URL=https://sly.dynors.com
SLY_FORWARD_SECRET=<secret-partagé>

# PSP (via Vault / ESO)
WAVE_API_KEY=<...>
WAVE_WEBHOOK_SECRET=<...>
OM_API_KEY=<...>
PAYTECH_API_KEY=<...>
PAYDUNYA_MASTER_KEY=<...>

# DB
DATABASE_URL=jdbc:postgresql://pg:5432/dynors_paiement
DATABASE_USERNAME=<...>
DATABASE_PASSWORD=<...>

📚 Références


Dernière mise à jour : 2026-04-30