Documentation API
v1Inté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.
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
Requête rapide
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.
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.
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);
/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
{
"data": {
"user": {
"id": "01HZ...",
"name": "Mamadou Diallo",
"email": "mamadou@example.com",
"role": "merchant"
},
"token": "1|abc123...",
"token_type": "Bearer"
}
}
/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).
/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)
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
{
"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
{
"message": "The name field is required. (and 2 more errors)",
"errors": {
"name": ["The name field is required."],
"amount": ["The amount field is required."]
}
}
/api/v1/api/payment-links
Liste les liens de paiement du marchand (du plus récent au plus ancien), dans l'environnement de la clé API utilisée. Authentification : en-tête X-API-Key. Aucun paramètre requis.
Réponse 200
{
"data": [
{
"id": 17,
"token": "lnk_8f2k9xpz3m",
"name": "Commande #1024",
"amount": 50000,
"amount_formatted": "50 000 GNF",
"currency": "GNF",
"status": "active",
"url": "https://pay.soamgroup.gn/pay/lnk_8f2k9xpz3m",
"created_at": "2026-08-10T09:12:00+00:00"
}
]
}
La liste n'est pas paginée côté S2S. Pour une recherche avancée et de la pagination, utilisez GET /api/v1/transactions du dashboard.
/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
{
"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"
}
}
/api/v1/api/payment-links/{token}
Récupère le détail d'un lien de paiement : statut, montant encaissé, URL et QR code. Authentification : en-tête X-API-Key. 404 si le lien est hors du scope de la clé.
Paramètres
token
— Token du lien dans l'URL (ex: lnk_8f2k9xpz3m)
Réponse 200
{
"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": 3,
"conversion_count": 2,
"collected_amount": 100000,
"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"
}
}
/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
{
"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
}
}
/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
{
"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).
/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
{
"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
/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
/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
{
"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 :
/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.
/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.
/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)
{
"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.
/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.
{
"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
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
{
"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).
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 :
- 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_failedest 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_....
/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)
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"]
}'
{
"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"
}
}
/api/v1/webhooks
Liste vos webhooks avec leurs statistiques de livraison (success_rate, last_triggered_at).
Autres endpoints
/api/v1/webhooks/{id} — modifie url, events et is_active (champs optionnels).
/api/v1/webhooks/{id} — supprime le webhook (réponse 204).
/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.
/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)
{
"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."
}
/api/v1/api-keys
Liste vos clés API (jamais la clé en clair, uniquement key_masked).
Révoquer une clé
/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
{
"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.
20 req/min
Création de liens de paiement
60 req/min
Lecture de liens et de transactions
60 req/min
Toutes les routes du tableau de bord
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_)