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)
- Audit interne : combien de transactions par mois, quels moyens de paiement, quels webhooks consommés ?
- Inscription SOAMTAR sandbox : créer un compte et valider en sandbox que toutes vos fonctionnalités marchent.
- Mapping des références : préparer un script qui mappe vos
merchant_refancienne → nouvelle si elles diffèrent. - 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)
- Mettre
soamtar.rolloutà 100. - Garder le code legacy actif encore 30 jours pour les webhooks tardifs des anciennes transactions.
- 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)
- Vérifier qu'aucun webhook n'arrive plus sur l'ancien endpoint depuis 7 jours.
- Désactiver les webhooks legacy dans le dashboard de l'ancien agrégateur.
- Garder la lecture legacy active pour l'historique (audits, support).
- Retirer le code de routage 30 jours plus tard.
Mapping des concepts
| Concept | Chez les autres | SOAMTAR |
|---|---|---|
| Référence marchand | ref_command, transaction_id, external_ref | merchant_ref |
| Référence agrégateur | token, transaction_id | id (UUID) + reference (TXN-…) |
| URL de webhook | ipn_url, notify_url | Configuré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, /verify | POST/v1/payments/{id}/verify |
| Moyen de paiement | payment_method, target_payment | provider (orange_money_sl) |
| Montant | entier en unités mineures ou décimal | chaîne décimale en leones, 2 décimales ("150.00") |
| Devise | currency | currency (SLE) |
| Téléphone du payeur | formats locaux variés | E.164 : +232 suivi de 8 chiffres |
| Métadonnées libres | custom_field, metadata | metadata (objet JSON libre) |
Mapping des statuts
| Autre agrégateur | SOAMTAR |
|---|---|
created, pending | initiated (avant soumission) ou pending (après soumission) |
complete, succeeded, paid | success |
failed, error | failed |
canceled, cancelled | cancelled |
expired, timeout | expired |
refunded | refunded (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
| Risque | Parade |
|---|---|
| Double encaissement pendant la coexistence | Idempotency-Key déterministe basée sur votre ID interne (jamais sur la référence de l'agrégateur) |
| Webhooks legacy après la bascule | Garder le handler legacy 30 jours : journaliser puis ignorer |
| Remboursement d'une transaction legacy | Le faire chez l'ancien agrégateur (la transaction n'existe pas chez SOAMTAR) |
| Écart de frais → décalage comptable | Comparer 7 jours avant et 7 jours après, l'expliquer aux marchands |
| Échec massif à la bascule | Dé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.