Skip to content

Migration depuis un autre agrégateur ​

Vous utilisez aujourd'hui un autre agrégateur et vous voulez passer à SOAMTAR. Voici la procédure recommandée pour ne perdre aucune transaction et garder l'historique.

Phase 1 — Préparation (J-30) ​

  1. Audit interne : combien de transactions par mois, quels moyens de paiement, quels webhooks consommés ?
  2. Inscription SOAMTAR sandbox : créer un compte et valider en sandbox que toutes vos fonctionnalités marchent.
  3. Mapping des références : préparer un script qui mappe vos merchant_ref ancienne → nouvelle si elles diffèrent.
  4. Test exhaustif en sandbox : traiter au moins 100 transactions sandbox sur les chemins critiques.

Phase 2 — Coexistence (J-7 à J0) ​

Activer les deux agrégateurs en parallèle quelques jours :

php
class PaymentRouter
{
    public function route(Order $order)
    {
        // Bascule progressive
        $useSoamtar = $order->user_id % 100 < $this->soamtarRolloutPercent();

        return $useSoamtar
            ? app(SoamtarClient::class)->payments()->create(...)
            : app(LegacyClient::class)->initPayment(...);
    }

    private function soamtarRolloutPercent(): int
    {
        return (int) Cache::get('soamtar.rollout', 0);   // 0 → 100 progressivement
    }
}

Augmenter le pourcentage jour après jour : 1 % → 5 % → 25 % → 50 % → 100 %.

Phase 3 — Bascule complète (J0) ​

  1. Mettre soamtar.rollout à 100.
  2. Garder le code legacy actif encore 30 jours pour les webhooks tardifs des anciennes transactions.
  3. Prévenir vos marchands B2B (si vous êtes une plateforme) que les frais et les cycles de règlement changent.

Phase 4 — Décommissionnement (J+30) ​

  1. Vérifier qu'aucun webhook n'arrive plus sur l'ancien endpoint depuis 7 jours.
  2. Désactiver les webhooks legacy dans le dashboard de l'ancien agrégateur.
  3. Garder la lecture legacy active pour l'historique (audits, support).
  4. Retirer le code de routage 30 jours plus tard.

Mapping des concepts ​

ConceptChez les autresSOAMTAR
Référence marchandref_command, transaction_id, external_refmerchant_ref
Référence agrégateurtoken, transaction_idid (UUID) + reference (TXN-…)
URL de webhookipn_url, notify_urlConfigurée dans Dashboard → Webhooks (par endpoint) ou callback_url par transaction (reçoit tous les événements de la transaction, même signature)
Vérification serveur/check, /verifyPOST/v1/payments/{id}/verify
Moyen de paiementpayment_method, target_paymentprovider (orange_money_sl)
Montantentier en unités mineures ou décimalchaîne décimale en leones, 2 décimales ("150.00")
Devisecurrencycurrency (SLE)
Téléphone du payeurformats locaux variésE.164 : +232 suivi de 8 chiffres
Métadonnées librescustom_field, metadatametadata (objet JSON libre)

Mapping des statuts ​

Autre agrégateurSOAMTAR
created, pendinginitiated (avant soumission) ou pending (après soumission)
complete, succeeded, paidsuccess
failed, errorfailed
canceled, cancelledcancelled
expired, timeoutexpired
refundedrefunded (ou partially_refunded pour un remboursement partiel)

Mapping des webhooks ​

php
// Adaptateur : webhook legacy → format SOAMTAR interne
class LegacyWebhookAdapter
{
    public function toSoamtarFormat(array $legacyPayload): array
    {
        return [
            'event' => match ($legacyPayload['type_event'] ?? '') {
                'sale_complete' => 'payment.success',
                'sale_canceled' => 'payment.cancelled',
                'sale_failed' => 'payment.failed',
                default => null,   // événement legacy intermédiaire : pas d'équivalent SOAMTAR, à ignorer
            },
            'created' => $legacyPayload['timestamp'] ?? now()->toIso8601String(),
            'data' => [
                'id' => $legacyPayload['ref_command'] ?? null,
                'reference' => $legacyPayload['token'] ?? null,
                'amount' => number_format((float) ($legacyPayload['item_price'] ?? 0), 2, '.', ''),
                'currency' => $legacyPayload['currency'] ?? 'SLE',
                'status' => $this->mapStatus($legacyPayload['status'] ?? ''),   // voir le tableau des statuts
                'metadata' => json_decode($legacyPayload['custom_field'] ?? '{}', true),
            ],
        ];
    }
}

Conserver l'historique ​

Gardez une table de correspondance entre les anciennes références et les nouvelles :

php
Schema::create('migration_refs', function (Blueprint $table) {
    $table->uuid('id')->primary();
    $table->string('legacy_ref')->index();
    $table->string('soamtar_ref')->nullable()->index();
    $table->string('legacy_provider');
    $table->date('migrated_at');
});

Votre support peut ainsi retrouver une ancienne transaction avec l'une ou l'autre des deux références.

Risques courants ​

RisqueParade
Double encaissement pendant la coexistenceIdempotency-Key déterministe basée sur votre ID interne (jamais sur la référence de l'agrégateur)
Webhooks legacy après la basculeGarder le handler legacy 30 jours : journaliser puis ignorer
Remboursement d'une transaction legacyLe faire chez l'ancien agrégateur (la transaction n'existe pas chez SOAMTAR)
Écart de frais → décalage comptableComparer 7 jours avant et 7 jours après, l'expliquer aux marchands
Échec massif à la basculeDéploiement progressif (1 % d'abord), feature flag pour revenir en arrière en 5 min

Aide à la migration ​

Migration critique (volume > 10 000 transactions/mois) ? support@so-amtar.com met en place :

  • un accompagnement technique individuel ;
  • une revue de votre adaptateur de webhook ;
  • un suivi en temps réel pendant la bascule ;
  • un rapport post-migration.

SOAMTAR Payment API Documentation.