Chargement...

Documentation API

v1

Intégrez SoamPay dans votre application en quelques lignes de code. API RESTful complète pour les paiements mobiles et les liens de paiement en Guinée.

Base URL https://api.soamgroup.gn/v1

Introduction

L'API SoamPay est une API RESTful qui vous permet d'accepter des paiements mobiles (Orange Money, MTN MoMo) et par carte bancaire en Guinée. Toutes les requêtes et réponses sont en JSON.

Base URL

https://api.soamgroup.gn/api/v1

Requête rapide

curl
curl -X GET https://api.soamgroup.gn/api/v1/transactions \
  -H "Authorization: Bearer samp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Authentification

Tous les appels API s'authentifient avec une clé API (samp_...), créée dans la page Clés API du tableau de bord. Deux types de clés existent, chacune avec sa méthode d'authentification.

Ne jamais exposer vos clés API côté client

Une clé donne un accès complet à votre compte. Stockez-la dans une variable d'environnement et n'appelez l'API que depuis vos serveurs. La clé brute n'est affichée qu'une seule fois à la création.

Serveur X-API-Key

Pour vos serveurs (S2S). Envoyée dans l'en-tête X-API-Key. Réservée au back-end et scopée à une entreprise : elle ne peut que créer des liens et lire leurs transactions.

Dashboard Bearer

Pour une application externe ou un outil. Envoyée dans l'en-tête Authorization: Bearer samp_.... Accès équivalent à celui du tableau de bord.

curl -X GET https://api.soamgroup.gn/api/v1/api/transactions/TXN-8F2K9XPZ3MQ \
  -H "X-API-Key: samp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
const response = await fetch('https://api.soamgroup.gn/api/v1/api/transactions/TXN-8F2K9XPZ3MQ', {
  headers: {
    'X-API-Key': process.env.SOAMPAY_API_KEY
  }
});
const data = await response.json();
<?php

$ch = curl_init('https://api.soamgroup.gn/api/v1/api/transactions/TXN-8F2K9XPZ3MQ');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'X-API-Key: ' . getenv('SOAMPAY_API_KEY'),
]);
$response = curl_exec($ch);
POST

/api/v1/auth/login

Authentifie le marchand et retourne un jeton Bearer à transmettre dans Authorization: Bearer <token> pour toutes les routes de l'API marchand (dashboard, transactions, retraits, webhooks…).

Paramètres

email string Oui Adresse e-mail du compte marchand
password string Oui Mot de passe du compte marchand
Réponse 200
{
  "data": {
    "user": {
      "id": "01HZ...",
      "name": "Mamadou Diallo",
      "email": "mamadou@example.com",
      "role": "merchant"
    },
    "token": "1|abc123...",
    "token_type": "Bearer"
  }
}
GET

/api/v1/auth/me

Retourne le profil du marchand connecté. En-tête requis : Authorization: Bearer <token>.

{
  "data": {
    "id": "01HZ...",
    "name": "Mamadou Diallo",
    "email": "mamadou@example.com",
    "role": "merchant"
  }
}

Autres endpoints : POST /api/v1/auth/logout (révoque le jeton courant) et POST /api/v1/auth/register (crée un compte marchand).

POST

/api/v1/api/payment-links

Crée un lien de paiement depuis vos serveurs (S2S) et retourne l'URL de paiement hébergée data.url à laquelle rediriger votre client. Authentification : en-tête X-API-Key. L'en-tête Idempotency-Key est recommandé pour éviter les doublons.

Paramètres

name string Oui Nom du lien affiché au payeur (max 255 caractères)
amount integer Oui Montant en GNF (minimum 1000)
currency string Non Devise (par défaut "GNF")
allowed_methods array Non Moyens acceptés : orange_money, mtn_momo, card (défaut : tous)
description string Non Description du paiement (max 1000 caractères)
expires_at datetime Non Date d'expiration (ISO 8601, après aujourd'hui)
Requête
curl -X POST https://api.soamgroup.gn/api/v1/api/payment-links \
  -H "X-API-Key: samp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: cmd-1024-a1b2c3d4" \
  -d '{
    "name": "Commande #1024",
    "amount": 50000,
    "currency": "GNF",
    "allowed_methods": ["orange_money", "mtn_momo", "card"]
  }'
const res = await fetch('https://api.soamgroup.gn/api/v1/api/payment-links', {
  method: 'POST',
  headers: {
    'X-API-Key': process.env.SOAMPAY_API_KEY,
    'Content-Type': 'application/json',
    'Idempotency-Key': 'cmd-1024-a1b2c3d4'
  },
  body: JSON.stringify({
    name: 'Commande #1024',
    amount: 50000,
    currency: 'GNF',
    allowed_methods: ['orange_money', 'mtn_momo', 'card']
  })
});
const data = await res.json();
<?php

$data = json_encode([
    'name' => 'Commande #1024',
    'amount' => 50000,
    'currency' => 'GNF',
    'allowed_methods' => ['orange_money', 'mtn_momo', 'card'],
]);

$ch = curl_init('https://api.soamgroup.gn/api/v1/api/payment-links');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => $data,
    CURLOPT_HTTPHEADER => [
        'X-API-Key: ' . getenv('SOAMPAY_API_KEY'),
        'Idempotency-Key: cmd-1024-a1b2c3d4',
        'Content-Type: application/json',
    ],
]);
$response = curl_exec($ch);

Réponse 200

JSON
{
  "data": {
    "id": 17,
    "token": "lnk_8f2k9xpz3m",
    "name": "Commande #1024",
    "description": null,
    "amount": 50000,
    "amount_formatted": "50 000 GNF",
    "currency": "GNF",
    "allowed_methods": ["orange_money", "mtn_momo", "card"],
    "status": "active",
    "usage_count": 0,
    "conversion_count": 0,
    "collected_amount": 0,
    "expires_at": null,
    "url": "https://pay.soamgroup.gn/pay/lnk_8f2k9xpz3m",
    "qr_code": "data:image/svg+xml;base64,...",
    "created_at": "2026-08-10T09:12:00+00:00"
  }
}

Réponse 422 — Erreur de validation

Erreur
{
  "message": "The name field is required. (and 2 more errors)",
  "errors": {
    "name": ["The name field is required."],
    "amount": ["The amount field is required."]
  }
}
GET

/api/v1/api/transactions/{reference}

Récupère le détail et le statut actuel d'une transaction (pending, success, failed, refunded) à partir de sa référence. Authentification : en-tête X-API-Key. 404 si la transaction est hors du scope de la clé.

Paramètres

reference — Référence de la transaction dans l'URL (ex: TXN-8F2K9XPZ3MQ)

Réponse 200

JSON
{
  "data": {
    "id": 204,
    "reference": "TXN-8F2K9XPZ3MQ",
    "payment_link_id": 17,
    "payment_link_token": "lnk_8f2k9xpz3m",
    "payer_name": null,
    "payer_phone": "+224620000000",
    "payer_email": null,
    "amount": 50000,
    "amount_formatted": "50 000 GNF",
    "currency": "GNF",
    "payment_method": "orange_money",
    "status": "success",
    "provider_reference": null,
    "description": "Commande #1024",
    "fee": 500,
    "fee_formatted": "500 GNF",
    "net_amount": 49500,
    "net_amount_formatted": "49 500 GNF",
    "paid_at": "2026-08-10T09:14:32+00:00",
    "created_at": "2026-08-10T09:12:00+00:00"
  }
}
GET

/api/v1/transactions

Liste toutes vos transactions (API marchand) avec filtres et pagination, triées par date décroissante. Authentification : Authorization: Bearer samp_... (clé Dashboard).

Paramètres de requête

status string — Filtrer : pending, success, failed, refunded
method string — Filtrer par moyen : orange_money, mtn_momo, card
search string — Recherche par référence, nom ou téléphone du payeur
from date — Date de début (Y-m-d)
to date — Date de fin (Y-m-d)
per_page integer 15 Résultats par page (défaut 15)

Réponse 200

JSON
{
  "data": [
    {
      "id": 204,
      "reference": "TXN-8F2K9XPZ3MQ",
      "payer_name": "Mamadou Diallo",
      "payer_phone": "+224620000000",
      "amount": 50000,
      "amount_formatted": "50 000 GNF",
      "currency": "GNF",
      "payment_method": "orange_money",
      "status": "success",
      "description": "Commande #1024",
      "paid_at": "2026-08-10T09:14:32+00:00",
      "created_at": "2026-08-10T09:12:00+00:00"
    }
  ],
  "meta": {
    "current_page": 1,
    "per_page": 15,
    "total": 142
  },
  "status_counts": {
    "total": 142,
    "pending": 4,
    "success": 136,
    "failed": 1,
    "refunded": 1
  }
}
GET

/api/v1/transactions/{reference}

Retourne le détail complet d'une transaction, incluant les frais prélevés (fee), le montant net crédité (net_amount) et le lien de paiement associé. Authentification : Authorization: Bearer samp_....

Réponse 200

JSON
{
  "data": {
    "id": 204,
    "reference": "TXN-8F2K9XPZ3MQ",
    "payment_link_id": 17,
    "payment_link_token": "lnk_8f2k9xpz3m",
    "payer_name": "Mamadou Diallo",
    "payer_phone": "+224620000000",
    "amount": 50000,
    "amount_formatted": "50 000 GNF",
    "currency": "GNF",
    "payment_method": "orange_money",
    "status": "success",
    "environment": "live",
    "provider_reference": "OM-GN-20260810-00042",
    "description": "Commande #1024",
    "fee": 750,
    "fee_formatted": "750 GNF",
    "net_amount": 49250,
    "net_amount_formatted": "49 250 GNF",
    "paid_at": "2026-08-10T09:14:32+00:00",
    "created_at": "2026-08-10T09:12:00+00:00"
  }
}

Ce endpoint existe aussi en version S2S : GET /api/v1/api/transactions/{reference} (même réponse, authentification X-API-Key).

POST

/api/v1/transactions/{reference}/refund

Rembourse une transaction success en débitant le solde du marchand du montant net encaissé. Les transactions en mode test ne sont pas remboursables. Authentification : Authorization: Bearer samp_.... Header Idempotency-Key recommandé.

Paramètres

reason string Non Motif du remboursement (max 1000 caractères)
pin string Oui PIN de transaction (4 à 6 chiffres), défini via POST /auth/transaction-pin
Réponse 200
{
  "data": {
    "reference": "TXN-8F2K9XPZ3MQ",
    "status": "refunded",
    "refunded_at": "2026-08-11T10:02:11+00:00"
  },
  "message": "Transaction remboursée."
}

Erreurs

refund.ineligible 409 Transaction non remboursable (mauvais statut, mode test)
refund.already_refunded 409 La transaction a déjà été remboursée
payout.insufficient_balance 422 Solde du marchand insuffisant
transaction_pin.not_set 422 Aucun PIN configuré (POST /auth/transaction-pin)
transaction_pin.invalid 422 PIN incorrect
transaction_pin.throttled 429 Trop de tentatives, réessayez dans 5 minutes
transaction.not_found 404 Transaction introuvable
GET

/api/v1/transactions/export

Télécharge toutes vos transactions au format CSV (UTF-8, séparateur virgule), pour vos exports comptables. Fichier nommé transactions_AAAA-MM-JJ.csv. Authentification : Authorization: Bearer samp_....

Structure du fichier

Référence,Payeur,Montant,Devise,Méthode,Statut,Date
TXN-8F2K9XPZ3MQ,Mamadou Diallo,50000,GNF,orange_money,success,10/08/2026 09:14
TXN-9A3L0YQZ4NR,Aminata Soumah,25000,GNF,mtn_momo,refunded,10/08/2026 11:02
POST

/api/v1/payouts

Crée une demande de décaissement vers un compte mobile money ou une carte. Le montant est débité de votre solde disponible. Authentification : Authorization: Bearer samp_.... Header Idempotency-Key recommandé.

Paramètres

amount integer Oui Montant en GNF (minimum 1000)
method string Oui Moyen de sortie : orange_money, mtn_momo, card
destination string Oui Numéro de téléphone ou identifiant du compte (max 255)
company_id ulid Non Rattacher le décaissement à une société (multi-sociétés)
pin string Oui PIN de transaction (4 à 6 chiffres), défini via POST /auth/transaction-pin
Réponse 201
{
  "data": {
    "id": 42,
    "reference": "PYO-4HZQ2MTX8K9",
    "amount": 20000,
    "amount_formatted": "20 000 GNF",
    "currency": "GNF",
    "status": "pending",
    "method": "orange_money",
    "destination": "+224620000000",
    "provider_reference": null,
    "processed_at": null,
    "created_at": "2026-08-11T11:30:00+00:00"
  },
  "message": "Demande de décaissement créée."
}

Statuts d'un retrait

Les statuts évoluent selon le traitement par le fournisseur :

pending
En attente
processing
En traitement
success
Décaissé
failed
Échoué
cancelled
Annulé
GET

/api/v1/payouts

Liste vos décaissements (tri décroissant) et retourne un tableau data d'objets Payout avec la même structure que ci-dessus. Suivez un décaissement précis avec GET /api/v1/payouts/{reference}.

Flux de paiement hébergé

Utilisez l'URL de paiement hébergée retournée par POST /api/v1/api/payment-links (data.url, ex. https://pay.soamgroup.gn/pay/lnk_...) : redirigez simplement votre client dessus, SoamPay affiche la page de paiement et notifie votre serveur par webhook. Ces endpoints publics ne requièrent aucune authentification.

GET

/api/v1/pay/{token}

Retourne les informations publiques du lien : nom, montant, devise, méthodes acceptées et nom du marchand. Utile pour pré-afficher le paiement dans votre propre interface.

POST

/api/v1/pay/{token}

Initie un paiement sur le lien. Sans authentification ni clé API — idéal pour intégrer SoamPay dans votre propre formulaire de paiement. Le header Idempotency-Key n'est pas appliqué sur cette route (protection par payment.duplicate_pending).

Paramètres

payer_name string Oui Nom du payeur (max 255 caractères)
payer_phone string Oui Téléphone du payeur — requis si mobile money, ignoré pour carte
payer_email email Non E-mail du payeur
payment_method string Oui orange_money, mtn_momo ou card
description string Non Description libre (max 500 caractères)
Réponse 201
{
  "data": {
    "reference": "TXN-8F2K9XPZ3MQ",
    "status": "pending",
    "amount": 50000,
    "amount_formatted": "50 000 GNF",
    "payment_method": "orange_money",
    "message": "Paiement en cours de traitement"
  }
}

Simulation en environnement de test

Sur un lien de mode test, le suffixe du numéro de téléphone détermine l'issue : …123456 → succès, …654321 → échec, …999999 → pending.

GET

/api/v1/pay/{token}/status/{reference}

Interroge le statut d'un paiement initié (polling). Les statuts possibles sont pending, success, failed et refunded. Route limitée en débit — privilégiez les webhooks pour la confirmation finale.

Réponse 200
{
  "data": {
    "reference": "TXN-8F2K9XPZ3MQ",
    "status": "success",
    "amount": 50000,
    "amount_formatted": "50 000 GNF",
    "payment_method": "orange_money",
    "paid_at": "2026-08-10T09:14:32+00:00"
  }
}

Idempotence

Les routes qui créent une ressource (liens de paiement, retraits, remboursements, webhooks, clés API) acceptent un header Idempotency-Key pour éviter les doublons lors d'un envoi retenté (réseau instable, timeout, double-clic).

Idempotency-Key string Identifiant unique de l'opération (max 128 caractères)

Comportement

Même clé + même corps Réponse rejouée La réponse de la première requête est renvoyée telle quelle (aucun doublon créé)
Même clé + corps différent Erreur 409 code idempotency.conflict — la clé est déjà associée à un autre corps
Clé différente Opération normale Une nouvelle ressource est créée pour chaque clé

Les réponses idempotentes sont conservées 24 heures. En cas d'échec réseau sans réponse, réutilisez la même clé lors de la nouvelle tentative. La route publique POST /api/v1/pay/{token} n'utilise pas ce mécanisme — elle protège des doublons via payment.duplicate_pending.

Webhooks

Les webhooks vous permettent de recevoir des notifications en temps réel lorsqu'un événement se produit sur votre compte. Configurez vos endpoints dans la section Webhooks du dashboard.

Événements disponibles

transaction.succeeded Un paiement a été complété avec succès
transaction.failed Un paiement a échoué
refund.created Un remboursement a été créé
refund.completed Un remboursement a été complété

Payload

JSON
{
  "event": "transaction.succeeded",
  "data": {
    "reference": "TXN-8F2K9XPZ3MQ",
    "amount": 50000,
    "currency": "GNF",
    "method": "orange_money",
    "status": "success",
    "created_at": "2025-06-14T09:12:00Z"
  }
}

Vérification de signature

Chaque webhook inclut un header X-SoamPay-Signature au format t=<timestamp>,v1=<signature>. La signature est un HMAC-SHA256 du corps préfixé du timestamp : hash_hmac('sha256', timestamp.'.'.rawBody, secret). Vérifiez toujours v1 et rejetez les en-têtes trop anciens (tolérance d'horloge de 5 minutes).

Vérification
const parts = Object.fromEntries(
  header.split(',').map(p => p.trim().split('='))
);
const expected = crypto.createHmac('sha256', webhookSecret)
  .update(`${parts.t}.` + rawBody)
  .digest('hex');

if (parts.v1 !== expected || Math.abs(Date.now()/1000 - Number(parts.t)) > 300) {
  res.status(401).send('Signature invalide');
}

Livraison et réessais

Les webhooks sont livrés via une file dédiée. Si votre endpoint répond autre chose que 2xx, SoamPay réessaie jusqu'à 5 fois avec un intervalle croissant :

1er essai
immédiat
2e essai
1 min
3e essai
5 min
4e essai
15 min
5e essai
1 h
  • Les réponses 400 et 404 sont considérées comme définitives : aucun réessai.
  • Après 5 échecs, le webhook est désactivé automatiquement et une alerte webhook.delivery_failed est déclenchée.
  • L'URL de destination doit être accessible publiquement (pas de localhost, pas de réseau privé).
  • Un délai de 10 secondes est accordé à votre endpoint pour répondre.

Gestion des webhooks (API marchand)

Créez et pilotez vos endpoints de webhook par API (équivalent de la section Webhooks du dashboard). Authentification : Authorization: Bearer samp_....

POST

/api/v1/webhooks

Paramètres

url string Oui URL accessible publiquement (HTTPS recommandé, max 255)
events array Oui Événements souscrits (au moins 1, cf. liste plus haut)
Requête
curl -X POST https://api.soamgroup.gn/api/v1/webhooks \
  -H "Authorization: Bearer samp_1|abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/hook",
    "events": ["transaction.succeeded", "transaction.failed"]
  }'
Réponse 201 — objet Webhook
{
  "data": {
    "id": "01J5C...",
    "url": "https://example.com/hook",
    "events": ["transaction.succeeded", "transaction.failed"],
    "is_active": true,
    "success_count": 0,
    "failure_count": 0,
    "success_rate": null,
    "last_triggered_at": null,
    "created_at": "2026-08-11T10:00:00+00:00"
  }
}
GET

/api/v1/webhooks

Liste vos webhooks avec leurs statistiques de livraison (success_rate, last_triggered_at).

Autres endpoints

PUT

/api/v1/webhooks/{id} — modifie url, events et is_active (champs optionnels).

DEL

/api/v1/webhooks/{id} — supprime le webhook (réponse 204).

POST

/api/v1/webhooks/{id}/test — envoie un événement de test sur l'URL pour vérifier sa configuration.

Gestion des clés API (API marchand)

Créez et révoquez vos clés API (équivalent de la section Clés API du dashboard). Authentification : Authorization: Bearer samp_.... La clé en clair n'est affichée qu'une seule fois à la création — conservez-la dans un gestionnaire de secrets.

POST

/api/v1/api-keys

Paramètres

name string Oui Libellé de la clé (max 255)
type string Non dashboard (défaut) ou server
company_id ulid Oui Requis si type=server — rattache la clé à une société
expires_at datetime Non Date d'expiration (postérieure à aujourd'hui)
Réponse 201 — clé générée
{
  "data": {
    "id": "01J5C...",
    "name": "Production",
    "type": "server",
    "company_id": "01J5B...",
    "key_prefix": "samp_live_",
    "key_masked": "samp_live_••••••••••••••••••••••",
    "environment": "live",
    "is_active": true,
    "expires_at": null,
    "created_at": "2026-08-11T10:05:00+00:00"
  },
  "key": "samp_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "message": "Clé API créée. Conservez-la précieusement : elle ne sera plus affichée."
}
GET

/api/v1/api-keys

Liste vos clés API (jamais la clé en clair, uniquement key_masked).

Révoquer une clé

DEL

/api/v1/api-keys/{id} — révoque définitivement la clé (réponse 204). Les requêtes utilisant cette clé seront rejetées avec api_key.revoked (401).

Frais

SoamPay prélève une commission sur chaque paiement réussi. La commission est calculée au moment de la transaction : fee = round(amount × fee_percent / 100). Votre solde est crédité du montant net (montant encaissé − frais).

Taux par moyen de paiement

orange_money 1,5 % Frais 750 GNF → net 49 250 GNF
mtn_momo 1,5 % Frais 750 GNF → net 49 250 GNF
card 2,5 % Frais 1 250 GNF → net 48 750 GNF

Le taux appliqué est figé au moment du paiement (les transactions passées ne sont pas affectées par un changement de tarif ultérieur). Les frais et le net apparaissent sur les détails de transaction (fee, net_amount) et sur l'affiche de vos revenus. Un remboursement débite votre solde du montant net initialement encaissé.

Retraits

Les décaissements (payouts) sont débités de votre solde disponible en GNF. Le solde disponible est le cumul des montants nets encaissés, minoré des retraits en cours et des remboursements. Si le solde est insuffisant, la requête est rejetée avec payout.insufficient_balance (422).

Codes d'erreur

L'API utilise des codes HTTP standard pour indiquer le succès ou l'échec d'une requête. Les erreurs retournent toujours un objet JSON avec un champ message (et errors pour les erreurs de validation).

200 Succès Requête traitée avec succès
201 Créé Ressource créée avec succès
400 Requête invalide Le format de la requête est incorrect
401 Non autorisé Clé API manquante ou invalide
403 Accès refusé Pas de permission pour cette action
404 Non trouvé La ressource demandée n'existe pas
422 Validation échouée Les paramètres sont invalides
429 Trop de requêtes Limite de débit atteinte
500 Erreur serveur Erreur interne du serveur SoamPay

Erreurs métier

En plus du statut HTTP, certaines erreurs portent un code métier interne et un message localisé en français. Exemple de réponse :

{
  "message": "Cette transaction a déjà été remboursée."
}
payment.link_expired 422 Le lien de paiement a expiré
payment.link_inactive 422 Le lien de paiement est désactivé
payment.invalid_method 422 La méthode de paiement n'est pas acceptée pour ce lien
payment.duplicate_pending 409 Un paiement en attente existe déjà pour ce lien et ce payeur
refund.ineligible 422 La transaction ne peut pas être remboursée
refund.already_refunded 409 La transaction a déjà été remboursée
payout.insufficient_balance 422 Solde insuffisant pour ce décaissement
payout.not_found 404 Décaissement introuvable
api_key.invalid 401 Clé API invalide ou expirée
api_key.revoked 401 La clé API a été révoquée
api_key.company_mismatch 403 La clé n'a pas accès à cette entreprise
idempotency.conflict 409 La clé d'idempotence a déjà été utilisée avec un corps différent
webhook.invalid_signature 401 Signature de webhook invalide
webhook.disabled 403 Webhook désactivé après échecs répétés

Format d'erreur

Erreur
{
  "message": "The amount field must be at least 1000.",
  "errors": {
    "amount": ["The amount field must be at least 1000."]
  }
}

Limites de débit

L'API impose des limites de débit pour garantir la stabilité du service. Les limites sont appliquées par clé API et par groupe d'endpoints.

S2S (X-API-Key)

20 req/min

Création de liens de paiement

S2S (X-API-Key)

60 req/min

Lecture de liens et de transactions

API marchand (Bearer)

60 req/min

Toutes les routes du tableau de bord

Page de paiement

10 req/min

Soumission d'un paiement sur /pay/{token}

Headers de réponse

X-RateLimit-Limit Nombre maximum de requêtes autorisées par minute
X-RateLimit-Remaining Nombre de requêtes restantes dans la fenêtre actuelle
Retry-After Sur un 429 : nombre de secondes à attendre avant de réessayer

En cas de dépassement (429)

Attendez le nombre de secondes indiqué par le header Retry-After avant de renvoyer la requête. Utilisez un mécanisme de retry avec backoff exponentiel en production.

Mode test

Le mode test vous permet de tester l'intégralité de votre parcours sans argent réel : clés API samp_test_..., liens de paiement Test et webhooks (champ environment: "test") — seul le paiement est simulé.

Comment l'activer

Allez dans Paramètres → Mode test dans le tableau de bord et activez l'interrupteur. Le réglage est par compte marchand : vos nouvelles clés API sont préfixées samp_test_ et vos nouveaux liens sont créés en environnement test. Désactivez-le pour revenir aux paiements réels.

Numéros de test

Le simulateur décide de l'issue selon la fin du numéro de téléphone du payeur (payer_phone) :

Se termine par 123456

Paiement réussi — transaction success, webhook transaction.succeeded avec environment: "test".

Se termine par 654321

Paiement refusé — transaction failed, webhook transaction.failed.

Se termine par 999999

Paiement en attente — transaction pending (statut interrogeable via /pay/{token}/status/{reference}).

Tout autre numéro : résultat aléatoire (80% succès / 20% échec).

Ce qui ne change pas en mode test

Toutes les règles restent identiques : authentification par clé API, idempotence (Idempotency-Key), limites de débit, format des réponses et des erreurs, signature des webhooks. Seul le débit du compte du payeur est simulé.

Différences : le wallet n'est jamais crédité et les transactions de test sont exclues des statistiques (tableaux de bord, revenus, exports) ; un badge Test les identifie dans les listes. Un lien créé via l'API S2S hérite de l'environnement de la clé API utilisée.

OpenAPI & versioning

L'API SoamPay est documentée selon la spécification OpenAPI 3.0. Une interface interactive (Swagger UI) permet d'explorer chaque endpoint et d'exécuter des requêtes de test : /docs. La spécification JSON brute est disponible sur /docs.json et peut alimenter vos outils (Postman, générateurs de clients).

Version de l'API

L'API est préfixée par un numéro de version majeur dans l'URL : /api/v1/.... La version actuelle est v1. Les nouvelles versions sont publiées avec un préfixe distinct ; l'ancienne version reste disponible jusqu'à l'échéance annoncée.

Compatibilité

Les champs d'un endpoint donné ne sont jamais retirés au sein d'une même version majeure : un ajout est toujours rétrocompatible. Les dates et montants sont exprimés en ISO 8601 (UTC) et en unités de la devise (entiers, jamais de décimale flottante).

Environnements

Production

https://api.soamgroup.gn

Sandbox (test)

https://api.soamgroup.gn (clés samp_test_)