Référence
Documentation API
Intégrez GnakryPay dans votre application (REST, clé API en Bearer). Cette page est publique : vous pouvez la partager à votre développeur sans qu'il ait de compte.
https://api.gnakrypay.com/v11Authentification
Chaque requête porte votre clé API dans l'en-tête Authorization, sous la forme Bearer sk_live_…. Une clé sk_test_ encaisse par le simulateur et crédite votre portefeuille de test ; une clé sk_live_engage de l'argent réel.
Nous ne conservons de votre clé qu'une empreinte : elle n'est affichée qu'une seule fois, à sa création, et nous ne pouvons pas vous la redonner. Créer une nouvelle clé ne révoque pas les anciennes — vous pouvez donc les faire tourner sans coupure.
2Consulter votre solde
/v1/balanceavailableest le seul chiffre sur lequel vous pouvez vous engager : le solde moins ce qu'immobilisent les reversements en cours. balance inclut ces fonds réservés.
Tous les montants sont des entiers de GNF sérialisés en chaînes: le GNF n'a pas de subdivision, et un grand entier passé en nombre JavaScript perdrait de la précision.
Le solde renvoyé est celui du portefeuille de votre clé : une clé sk_test_ lit le portefeuille de test, une clé sk_live_l'argent réel. Les deux ne se mélangent jamais.
3Créer un encaissement
/v1/paymentsIdempotency-Key est obligatoire. Sans elle, l'appel est refusé avec le code IDEMPOTENCY_KEY_REQUIRED. Utilisez une valeur unique par tentative de paiement, et rejouez la même si vous devez réessayer : la réponse d'origine vous est alors renvoyée au lieu de débiter deux fois votre client.| Champ | Type | Requis | Description |
|---|---|---|---|
| amount | Entier ou chaîne | Oui | Montant en GNF entiers, sans décimale. Les bornes dépendent de votre grille et du canal : hors bornes, l'appel est refusé (INVALID_AMOUNT) avec le minimum ou le maximum applicable. |
| currency | Chaîne | Oui | Doit valoir exactement "GNF". |
| operator | Énumération | Oui | ORANGE_GN, MTN_GN, PAYCARD_GN, KULU_GN, SOUTRA_GN, WAVE_GN, VISA, MASTERCARD, CRYPTO. Seuls les canaux ouverts sur votre compte aboutissent. |
| phone | Chaîne | Oui | Numéro du payeur, de 8 à 20 caractères. |
| reference | Chaîne | Oui | Votre référence, unique chez vous (100 caractères max). Un doublon est refusé (DUPLICATE_REFERENCE). |
| description | Chaîne | Non | Motif de l'achat (500 caractères max). |
| Chaîne | Non | Courriel du payeur, pour le reçu. | |
| callback_url | URL | Non | Conservée avec le paiement, pour votre propre réconciliation. Les notifications ne partent pas vers cette adresse : déclarez un récepteur de webhook (section 5). |
La réponse revient avec payment_status à PENDING : le client doit encore valider sur son téléphone. Ne livrez rien à ce stade — attendez le webhook payment.success, ou interrogez le paiement. Sans confirmation, il expire au bout de 15 minutes.
4Consulter un paiement
/v1/payments/{payment_id}Source de vérité sur l'état d'un paiement, à interroger si vous avez manqué un webhook. L'identifiant est celui renvoyé à la création, de la forme GNK-PAY-K7M2P9XQR.
Statuts possibles : PENDING, PROCESSING, SUCCESS, FAILED, EXPIRED, REFUNDED, PARTIALLY_REFUNDED.
5Webhooks et vérification de signature
whsec_…) y est affiché une seule fois, à la déclaration : il est chiffré au repos et ne peut plus être relu.À chaque changement d'état, nous envoyons une requête POST en JSON vers les récepteurs abonnés à l'événement, avec trois en-têtes :
| En-tête | Contenu |
|---|---|
| X-GnakryPay-Signature | HMAC-SHA256 du corps brut, préfixé : sha256=<hexadécimal>. Le préfixe fait partie de la valeur à comparer. |
| X-GnakryPay-Event | Nom de l'événement, par exemple payment.success. |
| X-GnakryPay-Delivery-Attempt | Numéro de tentative, à partir de 1. |
La signature se calcule avec votre secret sur le corps brutde la requête, tel qu'il est arrivé. Analyser le JSON puis le re-sérialiser produit une autre chaîne, donc une autre signature : c'est la cause habituelle d'une vérification qui échoue alors que le secret est bon.
Répondez 2xxen moins de 10 secondes. Au-delà, ou sur une autre réponse, la livraison est réessayée jusqu'à 6 fois avec un délai croissant : le même événement peut donc vous parvenir plusieurs fois, et votre traitement doit être idempotent sur payment_id. Après 20 échecs consécutifs, le récepteur est désactivé et vous devez le réactiver depuis votre espace.
Le journal des livraisons — code de réponse, durée, numéro de tentative, prochaine échéance de réessai — est consultable dans Paramètres > Développeurs. Il répond à « pourquoi n'ai-je pas reçu ce webhook ? » avec des faits.
payment.successpayment.failedpayment.expiredrefund.successrefund.failedpayout.paidpayout.failed{
"payment_id": "GNK-PAY-K7M2P9XQR",
"reference": "CMD-2026-00042",
"amount": "25000",
"fee": "475",
"net_amount": "24525",
"currency": "GNF",
"channel": "ORANGE_MONEY",
"aggregator": "NOTCHPAY",
"phone": "621000000",
"payment_status": "SUCCESS",
"timestamp": "2026-10-29T18:00:00.000Z"
}L'état se lit dans payment_status. Un événement de remboursement porte en plus refund_id.
6Erreurs
Toute erreur revient sous la même enveloppe : un code stable à tester dans votre code, un messageen français destiné à l'affichage, et un requestId à nous communiquer en cas de litige.
{
"status": 400,
"code": "IDEMPOTENCY_KEY_REQUIRED",
"message": "L'en-tête Idempotency-Key est obligatoire sur la création de paiement.",
"requestId": "01JB2P9XQR7K8M"
}curl https://api.gnakrypay.com/v1/balance \
-H "Authorization: Bearer sk_live_votre_cle_secrete"curl -X POST https://api.gnakrypay.com/v1/payments \
-H "Authorization: Bearer sk_live_votre_cle_secrete" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"amount": 25000,
"currency": "GNF",
"operator": "ORANGE_GN",
"phone": "621000000",
"reference": "CMD-2026-00042",
"description": "Achat panier 9876"
}'curl https://api.gnakrypay.com/v1/payments/GNK-PAY-K7M2P9XQR \
-H "Authorization: Bearer sk_live_votre_cle_secrete"# Vérification d'une signature déjà reçue, depuis un shell.
# CORPS = corps brut de la requête, exactement tel qu'il est arrivé.
SECRET="whsec_votre_secret_de_webhook"
RECUE="sha256=..." # en-tête X-GnakryPay-Signature
ATTENDUE="sha256=$(printf '%s' "$CORPS" \
| openssl dgst -sha256 -hmac "$SECRET" -hex \
| awk '{ print $NF }')"
if [ "$RECUE" = "$ATTENDUE" ]; then
echo "Signature valide"
else
echo "Signature invalide : rejetez la requête"
fi