API publique de collecte de paiement
Documentation d'intégration SOLIMI pour marchands, fintechs et banques
Ce guide explique comment connecter votre application à l'API publique SOLIMI pour initier des paiements directs, créer des sessions checkout hébergées, consulter leur statut, récupérer les moyens disponibles et recevoir les notifications webhook.
Environnements et prérequis
Avant l'intégration, l'équipe SOLIMI vous fournit un compte partenaire, une clé API, un secret API et configure les adresses IP autorisées. Le secret API est affiché une seule fois: conservez-le dans un coffre de secrets.
| Environnement | Base URL | Usage |
|---|---|---|
| Sandbox | https://sandbox-api.solimi.co |
Intégration partenaire avant mise en production. |
| Production | https://api.solimi.co |
Transactions réelles après validation SOLIMI. |
SUCCESS, DECLINED, FAILED et TIMEOUT. Le simulateur
s'utilise après la création d'un paiement, avec la référence SOLIMI retournée par l'API. Il met à jour le
statut du paiement et déclenche le webhook partenaire comme le ferait un callback provider réel. Cette
fonctionnalité est réservée à la sandbox et n'est pas disponible en production.
Authentification HMAC
Toutes les routes publiques sécurisées utilisent une signature HMAC SHA-256. SOLIMI vérifie votre clé API, l'adresse IP source, l'horodatage et la signature calculée à partir du corps exact de la requête.
Headers obligatoires
| Header | Description |
|---|---|
x-api-key |
Votre clé API publique, par exemple sk_test_... ou sk_live_.... |
x-timestamp |
Timestamp Unix en secondes. La tolérance est de 300 secondes. |
x-signature |
HMAC SHA-256 hexadécimal du message raw_body + timestamp. |
Idempotency-Key |
Obligatoire pour POST /v1/payments/request. Doit être unique par tentative logique. |
Algorithme
message = raw_request_body + x_timestamp
x_signature = HMAC_SHA256_HEX(api_secret, message)
Pour une requête GET, le corps est vide. Le message signé est donc uniquement le timestamp.
Protection contre les tentatives abusives
Si une clé API valide est utilisée avec de mauvaises signatures ou de mauvais timestamps à répétition, SOLIMI bloque temporairement l'authentification de cette clé afin de limiter les tentatives de force brute sur le secret API.
- Le blocage est temporaire et retourne
429 api_key_temporarily_locked. - La durée standard du blocage est de 15 minutes.
- Les appels depuis une IP non autorisée restent refusés en
403 authorization_failed.
Choisir son mode d'intégration
SOLIMI propose deux façons d'encaisser un paiement. Le choix dépend du niveau de contrôle que vous voulez garder sur l'expérience utilisateur.
1. API directe
Votre plateforme affiche ses propres formulaires de paiement, collecte le numéro de téléphone ou la carte virtuelle SOLIMI, puis appelle directement l'API SOLIMI.
- Endpoint principal:
POST /v1/payments/request. - Suivi:
GET /v1/payments/status/{reference}. - Idéal si vous maîtrisez déjà votre propre interface de paiement.
2. Page de paiement hébergée
Votre backend crée une session checkout. SOLIMI retourne un lien de paiement; le client est redirigé vers une page SOLIMI où il choisit Mixx, Moov Money, carte bancaire ou carte virtuelle SOLIMI.
- Création:
POST /v1/checkout/sessions. - Suivi:
GET /v1/checkout/sessions/{reference}. - Idéal pour intégrer vite sans développer l'interface de choix du moyen de paiement.
1. API directe
Ce mode est l'intégration où votre propre application pilote l'interface de paiement. Votre backend appelle
directement POST /v1/payments/request, puis suit le statut avec
GET /v1/payments/status/{reference} et les webhooks.
Une demande de paiement crée une intention de collecte. Selon le type de paiement, le client approuve le paiement sur mobile money, via une carte virtuelle SOLIMI ou sur une page bancaire sécurisée.
Mobile money
payment_type = mobile_money
Requiert provider: mixx, coris_money ou moov_money.
Carte virtuelle SOLIMI
payment_type = solimi_card
Requiert card_id sur 8 chiffres.
Carte bancaire
payment_type = bank_card
Retourne un provider_payment_url pour rediriger le client vers Visa/Mastercard.
Cycle de vie
| Statut | Signification |
|---|---|
INITIATED | La demande de paiement est créée. |
PENDING_APPROVAL | Le paiement attend l'approbation du client. |
APPROVED | Le client a approuvé le paiement. |
PROCESSING | Le traitement est en cours. |
SUCCESS | Le paiement est réussi. |
FAILED | Le paiement a échoué. |
DECLINED | Le client ou le système a refusé le paiement. |
EXPIRED | La demande a expiré. |
CANCELLED | La demande a été annulée. |
2. Page de paiement hébergée SOLIMI
Ce mode est l'intégration où SOLIMI héberge l'interface de choix du moyen de paiement. Le partenaire ne développe pas l'écran de paiement: il crée une session, reçoit un lien, puis redirige le client.
Le checkout hébergé permet au partenaire d'appeler une seule API pour créer une session de paiement.
SOLIMI retourne ensuite un payment_url à ouvrir côté client. Sur cette page, le client final
choisit son moyen de paiement: Mixx, Moov Money, carte virtuelle SOLIMI ou carte bancaire.
Quand utiliser le mode 2
- Vous souhaitez déléguer l'interface de choix du moyen de paiement à SOLIMI.
- Vous ne voulez pas intégrer séparément chaque provider dans votre application.
- Vous voulez un parcours web simple avec redirection vers votre site après paiement.
Redirections
Les URLs de succès, d'échec et d'annulation peuvent être configurées sur la fiche partenaire par SOLIMI. Le payload peut aussi les surcharger ponctuellement, mais ce n'est pas nécessaire dans le flux standard.
Endpoints à intégrer côté partenaire
POST /v1/checkout/sessions
Crée la session de paiement et retourne le lien à ouvrir côté client.
Payload standard
{
"merchant_reference": "CMD-20260729-001",
"amount": 12500,
"description": "Vente de chaussure",
"customer_phone": "22891390850",
"customer_first_name": "Magloire",
"customer_last_name": "ZOI"
}
Réponse 201
{
"checkout_reference": "CHK-20260729-8F2A91",
"merchant_reference": "CMD-20260729-001",
"payment_url": "https://pay.solimi.co/checkout/CHK-20260729-8F2A91",
"amount": 12500,
"currency": "XOF",
"description": "Vente de chaussure",
"status": "created",
"expires_at": "2026-07-29T12:30:00Z"
}
Erreurs possibles: 401 authentication_failed, 403 authorization_failed,
409 duplicate_merchant_reference, 422 validation_error.
GET /v1/checkout/sessions/{reference}
Consulte l'état d'une session checkout en secours du webhook.
Payload
Aucun body requis. La requête reste signée en HMAC avec un body vide.
Réponse 200
{
"checkout_reference": "CHK-20260729-8F2A91",
"merchant_reference": "CMD-20260729-001",
"payment_reference": "SOLPAY20260729881234",
"amount": 12500,
"currency": "XOF",
"description": "Vente de chaussure",
"status": "payment_initiated",
"selected_payment_type": "mobile_money",
"selected_provider": "mixx",
"provider_payment_url": null,
"expires_at": "2026-07-29T12:30:00Z",
"completed_at": null,
"cancelled_at": null
}
Erreurs possibles: 401 authentication_failed, 403 authorization_failed,
404 not_found.
Flux recommandé
- Votre backend crée une session avec
POST /v1/checkout/sessions. - Vous redirigez le client vers le
payment_urlretourné. - Le client choisit un moyen de paiement sur la page SOLIMI Checkout.
- SOLIMI exécute le paiement, met à jour le statut et appelle votre webhook.
- Votre backend peut consulter
GET /v1/checkout/sessions/{reference}en secours.
POST /v1/payments/request. Gardez le paiement direct si vous
maîtrisez déjà votre propre interface de paiement; utilisez le checkout si vous voulez un parcours SOLIMI prêt à l'emploi.
Référence des payloads et validations
Cette section précise le rôle de chaque champ, son type, son caractère obligatoire, sa taille et le format attendu. Les regex ci-dessous sont les validations recommandées côté intégrateur, afin de détecter les erreurs avant l'appel API.
provider pour un paiement solimi_card.
Headers de sécurité
| Champ | Rôle | Type | Obligatoire | Taille | Regex / Format | Exemple |
|---|---|---|---|---|---|---|
x-api-key |
Identifie la clé API du partenaire. | string | Oui | Variable | ^sk_(test|live)_[A-Za-z0-9]+$ |
sk_test_abcd... |
x-timestamp |
Protège contre le rejeu de requêtes. | string numeric | Oui | 10 chiffres en secondes | ^\d{10}$, Unix timestamp, tolérance 300s |
1781899200 |
x-signature |
Prouve que la requête vient du serveur partenaire. | string | Oui | 64 caractères | ^[a-f0-9]{64}$ |
7d9f...a31c |
Idempotency-Key |
Évite la création de doublons lors des retries. | string | Oui pour création paiement | Recommandé: 1 à 100 | ^[A-Za-z0-9._:-]{1,100}$ |
ORDER-2026-0001 |
PaymentRequestCreate - Création d'un paiement
| Champ | Rôle métier | Type | Obligatoire | Taille | Regex / Valeurs | Notes |
|---|---|---|---|---|---|---|
merchant_reference |
Référence unique de la transaction dans le système du marchand. | string | Oui | 1 à 100 caractères | ^[A-Za-z0-9._:-]{1,100}$ recommandé |
Utilisez la même valeur comme base de Idempotency-Key. |
payment_type |
Canal de paiement à utiliser. | enum string | Oui | Variable | mobile_money, bank_card, solimi_card |
Détermine les champs conditionnels requis. |
amount |
Montant à collecter. | integer | Oui | Nombre entier positif | ^[1-9]\d*$ |
Montant en XOF, sans décimales. |
currency |
Devise de la transaction. | literal string | Non | 3 caractères | ^XOF$ |
Facultatif. Si absent, le backend applique XOF. |
description |
Libellé visible pour réconciliation ou support. | string | Oui | Minimum 1 caractère | ^.{1,}$ |
Recommandé: inclure le numéro de commande. |
customer_phone |
Numéro du client payeur. | string | Oui | 8 à 20 caractères | ^\+?[0-9]{8,20}$ recommandé |
Envoyez le numéro au format international quand possible. |
customer_first_name |
Prénom du client final. | string | Non | Maximum 100 caractères | ^.{0,100}$ |
Utilisé pour l'historique, la réconciliation et le support. Non affiché sur le checkout. |
customer_last_name |
Nom du client final. | string | Non | Maximum 100 caractères | ^.{0,100}$ |
Utilisé pour l'historique, la réconciliation et le support. Non affiché sur le checkout. |
provider |
Opérateur mobile money à utiliser. | enum string | Oui si mobile_money |
Variable | mixx, coris_money, moov_money, bank_card |
Obligatoire pour mobile_money. Pour bank_card, le backend applique automatiquement bank_card. |
coris_country_code |
Code pays Coris Money fixé par SOLIMI. | string | Non | 1 à 10 caractères | Toujours 228 |
Le backend utilise automatiquement 228 pour construire l'appel Coris Money. |
coris_otp |
Code OTP saisi par le client Coris Money. | string | Oui si provider=coris_money |
1 à 20 caractères | Exemple: 123456 |
Transmis au provider Coris Money pour valider le débit. |
card_id |
Carte ID de la carte virtuelle SOLIMI client. | string | Oui si solimi_card |
Exactement 8 chiffres | ^\d{8}$ |
Visible dans l'application SOLIMI sur la carte virtuelle. Différent du numéro complet de carte à 16 chiffres. |
card_id correspond au Carte ID affiché sur la carte virtuelle dans l'application SOLIMI, par exemple 24924478.
Il ne faut pas envoyer le numéro complet de la carte bancaire virtuelle à 16 chiffres.
POST /v1/payments/request avec provider=coris_money, appelez d'abord
POST /v1/payments/coris-money/otp avec phone. SOLIMI vérifie
l'existence du compte Coris Money et déclenche l'envoi de l'OTP. Le client saisit ensuite cet OTP dans
coris_otp lors de la création du paiement.
Règles conditionnelles par type de paiement
payment_type |
Champ requis | Champs à ne pas envoyer | Exemple minimal |
|---|---|---|---|
mobile_money |
provider |
card_id |
{"payment_type":"mobile_money","provider":"mixx"} |
mobile_money + coris_money |
provider, coris_otp |
card_id |
{"payment_type":"mobile_money","provider":"coris_money","coris_otp":"123456"} |
bank_card |
Aucun champ conditionnel | card_id |
{"payment_type":"bank_card"} |
solimi_card |
card_id |
provider |
{"payment_type":"solimi_card","card_id":"12345678"} |
PaymentRequestResponse - Réponse de création
| Champ | Rôle | Type | Format / Valeurs |
|---|---|---|---|
reference | Référence SOLIMI du paiement. | string | PAY-..., à conserver pour le suivi. |
merchant_reference | Référence marchand transmise dans la requête. | string | 1 à 100 caractères. |
payment_type | Type de paiement retenu. | enum | mobile_money, bank_card, solimi_card. |
provider | Opérateur ou provider technique. | enum ou null | mixx, coris_money, moov_money, bank_card, ou null. |
amount | Montant demandé. | integer | Entier positif. |
currency | Devise. | string | XOF. |
description | Libellé de la demande. | string | Texte non vide. |
customer_phone | Numéro client. | string | 8 à 20 caractères. |
provider_payment_url | Lien de paiement externe à ouvrir pour la carte bancaire. | URL ou null | Renseigné principalement quand payment_type=bank_card. |
status | État initial ou courant. | enum | Voir la table des statuts. |
expires_at | Date d'expiration de la demande. | datetime | ISO 8601, UTC recommandé. |
created_at | Date de création. | datetime | ISO 8601. |
PaymentStatusResponse - Suivi de paiement
| Champ | Rôle | Type | Format / Valeurs |
|---|---|---|---|
reference | Référence SOLIMI à interroger. | string | PAY-.... |
merchant_reference | Référence du marchand. | string | 1 à 100 caractères. |
payment_type | Canal utilisé. | enum | Types de paiement supportés. |
provider | Provider mobile money. | enum ou null | Null hors mobile money. |
amount | Montant. | integer | Entier positif. |
currency | Devise. | string | XOF. |
status | État courant. | enum | INITIATED, PENDING_APPROVAL, APPROVED, PROCESSING, SUCCESS, FAILED, DECLINED, EXPIRED, CANCELLED. |
provider_payment_url | Lien de paiement bancaire si disponible. | URL ou null | À utiliser pour rediriger le client vers la page sécurisée Visa/Mastercard. |
failure_reason | Cause d'échec si disponible. | string ou null | Renseigne principalement les statuts non réussis. |
expires_at | Expiration. | datetime | ISO 8601. |
approved_at | Date d'approbation client. | datetime ou null | ISO 8601. |
completed_at | Date de succès final. | datetime ou null | ISO 8601. |
failed_at | Date d'échec. | datetime ou null | ISO 8601. |
declined_at | Date de refus. | datetime ou null | ISO 8601. |
Payloads webhook
| Champ | Rôle | Type | Obligatoire | Format / Regex |
|---|---|---|---|---|
url | Endpoint HTTPS du partenaire. | URL | Oui à la création | ^https://.+ recommandé en production. |
secret | Secret partagé avec SOLIMI pour authentifier les webhooks reçus. | string | Non | Minimum 16 caractères. Recommandé: 32+ caractères aléatoires. |
is_active | Active ou désactive la réception. | boolean | Non, uniquement update | true ou false. |
Endpoints publics par mode d'intégration
Les endpoints ci-dessous sont regroupés selon leur usage: mode 1 API directe pour piloter
votre propre interface de paiement, et mode 2 page hébergée pour rediriger le client vers
SOLIMI Checkout. Les endpoints partenaire sont accessibles sous le préfixe /v1.
GET/v1/health
PublicVérifie la disponibilité de l'API.
Headers
| Header | Obligatoire | Valeur |
|---|---|---|
content-type | Non | application/json |
Payload
Aucun body requis.
Réponses possibles
| HTTP | Cas | Corps |
|---|---|---|
200 | API disponible | {"status":"ok","service":"solimi-payment-api"} |
5xx | Service indisponible | Erreur serveur ou timeout infrastructure. |
Exemples d'appel
cURL
curl -X GET "{{base_url}}/v1/health"PHP
<?php
echo file_get_contents("{{base_url}}/v1/health");Node.js
const response = await fetch("{{base_url}}/v1/health");
console.log(await response.json());Python
import requests
response = requests.get("{{base_url}}/v1/health")
print(response.json())Exemple de réponse 200
{
"status": "ok",
"service": "solimi-payment-api"
}
POST/v1/payments/request
HMAC + Idempotency-KeyMode 1 - API directe. Crée une demande de paiement depuis votre propre interface.
Headers obligatoires
| Header | Rôle | Format / valeur |
|---|---|---|
content-type | Format du body. | application/json |
x-api-key | Identifie le partenaire. | Cle API fournie par SOLIMI. |
x-timestamp | Protection anti-rejeu. | Timestamp Unix en secondes, tolérance 300s. |
x-signature | Authentifie la requête. | HMAC SHA-256 hex de raw_body + timestamp. |
Idempotency-Key | Evite les doublons lors des retries. | Unique par tentative logique, ex: ORDER-2026-0001. |
Payload et validations
| Champ | Type | Obligatoire | Valeurs / regex | Rôle |
|---|---|---|---|---|
merchant_reference | string | Oui | 1-100, ^[A-Za-z0-9._:-]{1,100}$ | Référence unique côté marchand. |
payment_type | enum | Oui | mobile_money, bank_card, solimi_card | Canal de collecte. |
provider | enum/null | Oui si mobile money | mixx, moov_money, coris_money, bank_card | Opérateur mobile money. Pour bank_card, le backend le renseigne automatiquement. |
coris_country_code | string/null | Non | Toujours 228 | Code pays Coris fixé automatiquement par le backend. |
coris_otp | string/null | Oui si Coris Money | Max 20 caractères | OTP Coris Money saisi par le client. |
amount | integer | Oui | ^[1-9]\d*$ | Montant XOF sans décimales. |
currency | string | Non | XOF | Facultatif. Devise par defaut appliquee par le backend. |
description | string | Oui | Non vide | Libelle/réconciliation. |
customer_phone | string | Oui | ^\+?[0-9]{8,20}$ | Numéro du client payeur. |
customer_first_name | string/null | Non | Max 100 caractères | Prénom conservé pour l'historique et le support. |
customer_last_name | string/null | Non | Max 100 caractères | Nom conservé pour l'historique et le support. |
card_id | string/null | Oui si carte virtuelle SOLIMI | ^\d{8}$ | Carte ID de 8 chiffres visible sur la carte virtuelle dans l'application SOLIMI. Ne pas envoyer le numéro complet à 16 chiffres. |
payment_type = solimi_card, le partenaire doit envoyer le card_id de 8 chiffres affiché dans l'application SOLIMI, et non le numéro complet de la carte.
Exemple de payload
{
"merchant_reference": "ORDER-2026-0001",
"payment_type": "mobile_money",
"provider": "mixx",
"amount": 25000,
"description": "Commande ORDER-2026-0001",
"customer_phone": "22890112233",
"customer_first_name": "Magloire",
"customer_last_name": "ZOI"
}
Exemple carte bancaire
{
"merchant_reference": "ORDER-2026-0002",
"payment_type": "bank_card",
"amount": 25000,
"description": "Commande ORDER-2026-0002",
"customer_phone": "22890112233",
"customer_first_name": "Magloire",
"customer_last_name": "ZOI"
}
Réponses possibles
| HTTP | Code applicatif | Cas |
|---|---|---|
201 | - | Demande de paiement créée. |
400 | domain_error | Règle métier invalide. |
401 | authentication_failed | Headers HMAC manquants ou invalides. |
403 | authorization_failed | IP non autorisée, partenaire inactif ou credentials invalides. |
409 | idempotency_conflict / duplicate_merchant_reference | Clé idempotente réutilisée avec un payload différent ou référence marchand déjà utilisée. |
422 | validation_error | Champ manquant ou format invalide. |
500 | payment_core_sync_failed | Erreur de synchronisation interne avec le noyau SOLIMI. |
Exemples d'appel
cURL
BODY='{"merchant_reference":"ORDER-2026-0001","payment_type":"mobile_money","provider":"mixx","amount":25000,"description":"Commande ORDER-2026-0001","customer_phone":"22890112233"}'
TIMESTAMP=$(date +%s)
SIGNATURE=$(printf "%s%s" "$BODY" "$TIMESTAMP" | openssl dgst -sha256 -hmac "$SOLIMI_API_SECRET" -hex | sed 's/^.* //')
curl -X POST "{{base_url}}/v1/payments/request" \
-H "content-type: application/json" \
-H "x-api-key: $SOLIMI_API_KEY" \
-H "x-timestamp: $TIMESTAMP" \
-H "x-signature: $SIGNATURE" \
-H "Idempotency-Key: ORDER-2026-0001" \
-d "$BODY"PHP
<?php
$apiKey = getenv("SOLIMI_API_KEY");
$apiSecret = getenv("SOLIMI_API_SECRET");
$timestamp = (string) time();
$body = json_encode([
"merchant_reference" => "ORDER-2026-0001",
"payment_type" => "mobile_money",
"provider" => "mixx",
"amount" => 25000,
"description" => "Commande ORDER-2026-0001",
"customer_phone" => "22890112233"
], JSON_UNESCAPED_SLASHES);
$signature = hash_hmac("sha256", $body . $timestamp, $apiSecret);
$ch = curl_init("{{base_url}}/v1/payments/request");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POSTFIELDS => $body,
CURLOPT_HTTPHEADER => [
"content-type: application/json",
"x-api-key: $apiKey",
"x-timestamp: $timestamp",
"x-signature: $signature",
"Idempotency-Key: ORDER-2026-0001"
]
]);
echo curl_exec($ch);Node.js
import crypto from "node:crypto";
const body = JSON.stringify({
merchant_reference: "ORDER-2026-0001",
payment_type: "mobile_money",
provider: "mixx",
amount: 25000,
description: "Commande ORDER-2026-0001",
customer_phone: "22890112233"
});
const timestamp = Math.floor(Date.now() / 1000).toString();
const signature = crypto.createHmac("sha256", process.env.SOLIMI_API_SECRET).update(body + timestamp).digest("hex");
const response = await fetch("{{base_url}}/v1/payments/request", {
method: "POST",
headers: {
"content-type": "application/json",
"x-api-key": process.env.SOLIMI_API_KEY,
"x-timestamp": timestamp,
"x-signature": signature,
"Idempotency-Key": "ORDER-2026-0001"
},
body
});
console.log(await response.json());Python
import hashlib
import hmac
import json
import os
import time
import requests
payload = {
"merchant_reference": "ORDER-2026-0001",
"payment_type": "mobile_money",
"provider": "mixx",
"amount": 25000,
"description": "Commande ORDER-2026-0001",
"customer_phone": "22890112233",
}
body = json.dumps(payload, separators=(",", ":"), ensure_ascii=False)
timestamp = str(int(time.time()))
signature = hmac.new(os.environ["SOLIMI_API_SECRET"].encode(), (body + timestamp).encode(), hashlib.sha256).hexdigest()
response = requests.post(
"{{base_url}}/v1/payments/request",
data=body.encode(),
headers={
"content-type": "application/json",
"x-api-key": os.environ["SOLIMI_API_KEY"],
"x-timestamp": timestamp,
"x-signature": signature,
"Idempotency-Key": "ORDER-2026-0001",
},
)
print(response.json())Exemple de réponse 201
{
"reference": "PAY-8C7F36A1B2",
"merchant_reference": "ORDER-2026-0001",
"payment_type": "mobile_money",
"provider": "mixx",
"amount": 25000,
"currency": "XOF",
"description": "Commande ORDER-2026-0001",
"customer_phone": "22890112233",
"status": "PENDING_APPROVAL",
"provider_payment_url": null,
"expires_at": "2026-06-19T21:00:00Z",
"created_at": "2026-06-19T20:45:00Z"
}
GET/v1/payments/status/{reference}
HMACMode 1 - API directe. Retourne l'état courant d'un paiement initié via l'API directe.
Headers obligatoires
| Header | Rôle | Format / valeur |
|---|---|---|
x-api-key | Identifie le partenaire. | Cle API fournie par SOLIMI. |
x-timestamp | Protection anti-rejeu. | Timestamp Unix en secondes. |
x-signature | Authentifie la requête GET. | HMAC SHA-256 hex du timestamp. |
Parametres
| Parametre | Type | Obligatoire | Format | Rôle |
|---|---|---|---|---|
reference | path string | Oui | PAY-... ou SOLPAY... | Référence SOLIMI retournée à la création. |
Réponses possibles
| HTTP | Code applicatif | Cas |
|---|---|---|
200 | - | Statut retourne. |
401 | authentication_failed | Signature invalide. |
403 | authorization_failed | Partenaire non autorise. |
404 | not_found | Référence inconnue pour ce partenaire. |
Exemples d'appel
cURL
TIMESTAMP=$(date +%s)
SIGNATURE=$(printf "%s" "$TIMESTAMP" | openssl dgst -sha256 -hmac "$SOLIMI_API_SECRET" -hex | sed 's/^.* //')
curl -X GET "{{base_url}}/v1/payments/status/PAY-8C7F36A1B2" \
-H "x-api-key: $SOLIMI_API_KEY" \
-H "x-timestamp: $TIMESTAMP" \
-H "x-signature: $SIGNATURE"PHP
<?php
$timestamp = (string) time();
$signature = hash_hmac("sha256", $timestamp, getenv("SOLIMI_API_SECRET"));
$opts = ["http" => ["header" => "x-api-key: ".getenv("SOLIMI_API_KEY")."\r\nx-timestamp: $timestamp\r\nx-signature: $signature\r\n"]];
echo file_get_contents("{{base_url}}/v1/payments/status/PAY-8C7F36A1B2", false, stream_context_create($opts));Node.js
import crypto from "node:crypto";
const timestamp = Math.floor(Date.now() / 1000).toString();
const signature = crypto.createHmac("sha256", process.env.SOLIMI_API_SECRET).update(timestamp).digest("hex");
const response = await fetch("{{base_url}}/v1/payments/status/PAY-8C7F36A1B2", {
headers: {"x-api-key": process.env.SOLIMI_API_KEY, "x-timestamp": timestamp, "x-signature": signature}
});
console.log(await response.json());Python
import hashlib, hmac, os, time, requests
timestamp = str(int(time.time()))
signature = hmac.new(os.environ["SOLIMI_API_SECRET"].encode(), timestamp.encode(), hashlib.sha256).hexdigest()
response = requests.get(
"{{base_url}}/v1/payments/status/PAY-8C7F36A1B2",
headers={"x-api-key": os.environ["SOLIMI_API_KEY"], "x-timestamp": timestamp, "x-signature": signature},
)
print(response.json())Exemple de réponse 200
{
"reference": "PAY-8C7F36A1B2",
"merchant_reference": "ORDER-2026-0001",
"payment_type": "mobile_money",
"provider": "mixx",
"amount": 25000,
"currency": "XOF",
"status": "SUCCESS",
"provider_payment_url": null,
"failure_reason": null,
"expires_at": "2026-06-19T21:00:00Z",
"approved_at": "2026-06-19T20:46:11Z",
"completed_at": "2026-06-19T20:46:18Z",
"failed_at": null,
"declined_at": null
}
GET/v1/payment-methods
HMACListe les moyens de paiement actifs.
Headers obligatoires
| Header | Rôle | Format / valeur |
|---|---|---|
x-api-key | Identifie le partenaire. | Cle API fournie par SOLIMI. |
x-timestamp | Protection anti-rejeu. | Timestamp Unix en secondes. |
x-signature | Authentifie la requête GET. | HMAC SHA-256 hex du timestamp. |
Payload
Aucun body requis.
Champs de réponse
| Champ | Type | Valeurs possibles | Rôle |
|---|---|---|---|
code | string | mixx, coris_money, moov_money, bank_card, solimi_card | Code technique à envoyer dans provider si applicable. |
name | string | Libellé humain | Nom affichable. |
provider | string/null | Provider mobile money ou null | Operateur associe. |
is_active | boolean | true/false | Disponibilite du moyen. |
Réponses possibles
| HTTP | Code applicatif | Cas |
|---|---|---|
200 | - | Liste retournée. |
401 | authentication_failed | Signature invalide. |
403 | authorization_failed | Partenaire non autorise. |
Exemples d'appel
cURL
TIMESTAMP=$(date +%s)
SIGNATURE=$(printf "%s" "$TIMESTAMP" | openssl dgst -sha256 -hmac "$SOLIMI_API_SECRET" -hex | sed 's/^.* //')
curl -X GET "{{base_url}}/v1/payment-methods" \
-H "x-api-key: $SOLIMI_API_KEY" \
-H "x-timestamp: $TIMESTAMP" \
-H "x-signature: $SIGNATURE"PHP
<?php
$timestamp = (string) time();
$signature = hash_hmac("sha256", $timestamp, getenv("SOLIMI_API_SECRET"));
$opts = ["http" => ["header" => "x-api-key: ".getenv("SOLIMI_API_KEY")."\r\nx-timestamp: $timestamp\r\nx-signature: $signature\r\n"]];
echo file_get_contents("{{base_url}}/v1/payment-methods", false, stream_context_create($opts));Node.js
import crypto from "node:crypto";
const timestamp = Math.floor(Date.now() / 1000).toString();
const signature = crypto.createHmac("sha256", process.env.SOLIMI_API_SECRET).update(timestamp).digest("hex");
const response = await fetch("{{base_url}}/v1/payment-methods", {
headers: {"x-api-key": process.env.SOLIMI_API_KEY, "x-timestamp": timestamp, "x-signature": signature}
});
console.log(await response.json());Python
import hashlib, hmac, os, time, requests
timestamp = str(int(time.time()))
signature = hmac.new(os.environ["SOLIMI_API_SECRET"].encode(), timestamp.encode(), hashlib.sha256).hexdigest()
response = requests.get(
"{{base_url}}/v1/payment-methods",
headers={"x-api-key": os.environ["SOLIMI_API_KEY"], "x-timestamp": timestamp, "x-signature": signature},
)
print(response.json())Exemple de réponse 200
[
{
"code": "mixx",
"name": "Mixx by Yas",
"provider": "mixx",
"is_active": true
},
{
"code": "mobile_money",
"name": "Coris Money",
"provider": "coris_money",
"is_active": true
},
{
"code": "moov_money",
"name": "Moov Money",
"provider": "moov_money",
"is_active": true
},
{
"code": "bank_card",
"name": "Carte bancaire",
"provider": "bank_card",
"is_active": true
},
{
"code": "solimi_card",
"name": "Carte virtuelle SOLIMI",
"provider": null,
"is_active": true
}
]
POST/v1/checkout/sessions
HMAC + Idempotency-KeyMode 2 - Page de paiement hébergée. Crée une session checkout et retourne le lien de paiement à afficher au client.
Headers obligatoires
| Header | Rôle | Format / valeur |
|---|---|---|
content-type | Format du body. | application/json |
x-api-key | Identifie le partenaire. | Clé API fournie par SOLIMI. |
x-timestamp | Protection anti-rejeu. | Timestamp Unix en secondes, tolérance 300s. |
x-signature | Authentifie la requête. | HMAC SHA-256 hex de raw_body + timestamp. |
Idempotency-Key | Évite les doublons lors des retries. | Unique par tentative logique. |
Payload et validations
| Champ | Type | Obligatoire | Valeurs / regex | Rôle |
|---|---|---|---|---|
merchant_reference | string | Oui | 1-100, ^[A-Za-z0-9._:-]{1,100}$ | Référence unique côté marchand. |
amount | integer | Oui | ^[1-9]\d*$ | Montant à collecter en XOF. |
description | string | Oui | Non vide | Libellé affiché au client. |
customer_email | string/null | Non | Email valide, max 255 | Facultatif, utilisé uniquement pour l'historique/support. Aucun email automatique n'est envoyé au payeur. |
customer_phone | string/null | Non | ^\+?[0-9]{8,20}$ | Pré-remplissage du numéro client. |
customer_first_name | string/null | Non | Max 100 caractères | Prénom conservé pour l'historique. Non affiché sur la page checkout. |
customer_last_name | string/null | Non | Max 100 caractères | Nom conservé pour l'historique. Non affiché sur la page checkout. |
currency | string | Non | XOF | Facultatif. Par défaut le backend applique XOF. |
success_url, failure_url, cancel_url | URL/null | Non | URL HTTPS recommandée | Surcharge ponctuelle des URLs configurées sur le partenaire. |
metadata | object/null | Non | Objet JSON libre | Données de rapprochement interne du partenaire. |
Exemple de payload standard
{
"merchant_reference": "CMD-20260729-001",
"amount": 12500,
"description": "Vente de chaussure",
"customer_phone": "22891390850",
"customer_first_name": "Magloire",
"customer_last_name": "ZOI"
}
Réponses possibles
| HTTP | Code applicatif | Cas |
|---|---|---|
201 | - | Session créée. |
401 | authentication_failed | Signature invalide. |
403 | authorization_failed | IP ou partenaire non autorisé. |
409 | duplicate_merchant_reference | Référence marchand déjà utilisée. |
422 | validation_error | Champ manquant ou invalide. |
Exemple de réponse 201
{
"checkout_reference": "CHK-20260729-8F2A91",
"merchant_reference": "CMD-20260729-001",
"payment_url": "https://pay.solimi.co/checkout/CHK-20260729-8F2A91",
"amount": 12500,
"currency": "XOF",
"description": "Vente de chaussure",
"status": "OPEN",
"expires_at": "2026-07-29T12:30:00Z"
}
GET/v1/checkout/sessions/{reference}
HMACMode 2 - Page de paiement hébergée. Consulte le statut d'une session checkout créée par le partenaire.
Headers obligatoires
| Header | Rôle | Format / valeur |
|---|---|---|
x-api-key | Identifie le partenaire. | Clé API fournie par SOLIMI. |
x-timestamp | Protection anti-rejeu. | Timestamp Unix en secondes, tolérance 300s. |
x-signature | Authentifie la requête. | HMAC SHA-256 hex de timestamp, car le body est vide. |
Payload
Aucun body requis.
Réponses possibles
| HTTP | Code applicatif | Cas |
|---|---|---|
200 | - | Statut de la session retourné. |
401 | authentication_failed | Signature invalide ou headers absents. |
403 | authorization_failed | IP ou partenaire non autorisé. |
404 | not_found | Session introuvable pour ce partenaire. |
Exemple de réponse 200
{
"checkout_reference": "CHK-20260729-8F2A91",
"merchant_reference": "CMD-20260729-001",
"payment_reference": "SOLPAY20260729881234",
"amount": 12500,
"currency": "XOF",
"description": "Vente de chaussure",
"status": "payment_initiated",
"selected_payment_type": "mobile_money",
"selected_provider": "mixx",
"provider_payment_url": null,
"expires_at": "2026-07-29T12:30:00Z",
"completed_at": null,
"cancelled_at": null
}
POST/checkout/v1/sessions/{reference}/pay
Checkout publicRoute interne de la page hébergée. Déclenche le paiement choisi par le client sur la page checkout SOLIMI.
Headers
content-type: application/json. Cette route est appelée par la page checkout, elle ne demande pas de signature HMAC partenaire.
Payload et validations
| Champ | Type | Obligatoire | Valeurs / regex | Rôle |
|---|---|---|---|---|
payment_type | enum | Oui | mobile_money, bank_card, solimi_card | Moyen choisi par le client. |
provider | enum/null | Oui si mobile money | mixx, moov_money, bank_card | Provider technique. |
customer_phone | string/null | Oui sauf carte bancaire | ^\+?[0-9]{8,20}$ | Numéro client ou support d'identification. |
card_id | string/null | Oui si carte virtuelle SOLIMI | ^\d{8}$ | Carte ID de 8 chiffres visible sur la carte virtuelle SOLIMI. Différent du numéro complet à 16 chiffres. |
card_id dans l'application SOLIMI, sur sa carte virtuelle, au niveau du libellé Carte ID.
Cette valeur sert uniquement à identifier la carte virtuelle SOLIMI à débiter après validation.
Exemples de payload
{
"payment_type": "bank_card",
"provider": "bank_card"
}
{
"payment_type": "mobile_money",
"provider": "mixx",
"customer_phone": "22891390850"
}
Exemple de réponse 200
{
"checkout_reference": "CHK-20260729-8F2A91",
"merchant_reference": "CMD-20260729-001",
"payment_reference": "SOLPAY20260729881234",
"amount": 12500,
"currency": "XOF",
"description": "Vente de chaussure",
"status": "PROCESSING",
"selected_payment_type": "bank_card",
"selected_provider": "bank_card",
"provider_payment_url": "https://secure-gateway.example/pay/abc123",
"expires_at": "2026-07-29T12:30:00Z",
"completed_at": null,
"cancelled_at": null
}
Webhooks
SOLIMI appelle votre endpoint webhook lorsqu'un paiement change d'état. Votre serveur doit répondre avec
un statut HTTP 2xx. En cas d'échec, SOLIMI relance selon les délais: 30s, 60s, 300s, 900s.
| Header SOLIMI | Description |
|---|---|
x-solimi-signature | Secret webhook partage avec SOLIMI. Comparez cette valeur au secret configuré. |
x-solimi-timestamp | Timestamp Unix en secondes, utile pour refuser les notifications trop anciennes. |
x-solimi-event | Nom de l'événement, par exemple payment.success. |
Événements
payment.initiated, payment.pending_approval, payment.success,
payment.failed, payment.declined, payment.expired.
Vérification webhook FastAPI
import time
from fastapi import APIRouter, Header, HTTPException, Request
router = APIRouter()
SOLIMI_WEBHOOK_SECRET = "secret_fourni_par_solimi"
SIGNATURE_TOLERANCE_SECONDS = 300
@router.post("/webhooks/solimi/payments")
async def solimi_payment_webhook(
request: Request,
x_solimi_signature: str = Header(...),
x_solimi_timestamp: str = Header(...),
x_solimi_event: str = Header(...),
):
if x_solimi_signature != SOLIMI_WEBHOOK_SECRET:
raise HTTPException(status_code=401, detail="Invalid webhook signature")
try:
timestamp = int(x_solimi_timestamp)
except ValueError:
raise HTTPException(status_code=400, detail="Invalid timestamp")
if abs(int(time.time()) - timestamp) > SIGNATURE_TOLERANCE_SECONDS:
raise HTTPException(status_code=400, detail="Expired webhook timestamp")
payload = await request.json()
payment = payload.get("payment", {})
# Mettre à jour la commande/facture du partenaire ici.
# Exemple: payment.success => commande payée.
return {
"received": True,
"event": x_solimi_event,
"merchant_reference": payment.get("merchant_reference"),
"solimi_reference": payment.get("reference"),
"status": payment.get("status"),
}
x-solimi-signature contient directement
le secret webhook. Gardez ce secret côté serveur uniquement.
Erreurs
Les erreurs sont retournées au format JSON suivant.
{
"code": "authentication_failed",
"message": "Missing authentication headers",
"details": null
}
| HTTP | Code | Action recommandée |
|---|---|---|
| 401 | authentication_failed | Vérifier les headers HMAC, le timestamp et la signature. |
| 403 | authorization_failed | Vérifier l'IP autorisée, l'état de la clé API et du partenaire. |
| 404 | not_found | Vérifier la référence de paiement ou la route appelée. |
| 409 | idempotency_conflict | Réutiliser une meme clé uniquement pour la meme requête logique. |
| 429 | api_key_temporarily_locked | Attendre la fin du blocage temporaire, puis vérifier le secret API et le calcul HMAC avant de relancer les appels. |
| 422 | validation_error | Corriger les champs invalides dans le payload. |
Collection Postman
La collection Postman SOLIMI regroupe les requêtes prêtes à tester pour les endpoints publics: création de paiement, création de session checkout, consultation de statut et moyens de paiement disponibles. Elle aide les équipes techniques à démarrer rapidement sans reconstruire les headers et payloads depuis zéro.
Comment l'utiliser
- Téléchargez le fichier JSON de collection.
- Dans Postman, cliquez sur
Import, puis sélectionnez le fichier téléchargé. - Renseignez les variables
base_url,api_key,api_secretet les valeurs de test. - Lancez les requêtes de la section
03 - Paymentspour valider l'intégration. - Utilisez la section
05 - Sandbox Simulatorpour simuler les retours succès, refus, échec ou expiration.
Fichier disponible
Format JSON compatible avec Postman. Le fichier contient les scripts nécessaires pour calculer les headers HMAC, ajouter automatiquement l'idempotency key sur les paiements et tester le simulateur sandbox pendant la recette.
Télécharger la collection PostmanPOST/v1/payments/coris-money/otp
HMACMode 1 - API directe. Vérifie le numéro Coris Money et déclenche l'envoi du code OTP avant l'initiation du paiement.
Payload
| Champ | Type | Obligatoire | Format | Rôle |
|---|---|---|---|---|
phone | string | Oui | ^\+?[0-9]{8,20}$ | Numéro du client Coris Money. |
Réponses possibles
| HTTP | Code | Cas | Exemple |
|---|---|---|---|
200 | 200 | OTP envoyé. | {"code":"200","message":"OTP envoyé"} |
404 | 404 | Aucun compte Coris Money associé au numéro. | {"code":"404","message":"Aucun compte associé à ce numéro."} |
502 | 500 | Erreur provider Coris Money. | {"code":"500","message":"Une erreur s'est produite. Veuillez réessayer plus tard."} |
Exemple
{
"phone": "22891390850"
}
Checklist de mise en production
- Stocker la clé API et le secret API dans un coffre de secrets côté serveur.
- Signer toutes les requêtes avec le corps exact envoyé a SOLIMI.
- Utiliser une cle d'idempotence unique pour chaque paiement marchand.
- Vérifier les webhooks en comparant
x-solimi-signatureau secret webhook configuré. - Prevoir le polling de statut en secours si un webhook est indisponible.
- Fournir à SOLIMI les adresses IP publiques de vos serveurs.
- Tester les cas succès, échec, refus, expiration et retry webhook en sandbox.