INOPAS
Fondamentaux

Authentification

Chaque requête se signe elle-même en HMAC-SHA256 : aucun jeton à obtenir, à stocker ni à renouveler. Le secret ne quitte jamais votre serveur, seule la signature voyage.

Vos clés

Une clé est une paire : un identifiant (ipk_) qu’on envoie, et un secret (isk_) qui ne sert qu’à signer. Le secret s’affiche une seule fois, à la création de la clé dans votre espace marchand : rangez-le aussitôt dans votre gestionnaire de secrets.

Les deux jeux de clés
UsageIdentifiantHôteDisponible
Sandbox publicak_sandboxsandbox.inopas.netTout de suite, sans compte. Partagées par tous.
Vos testsipk_sandbox_…sandbox.inopas.netDès votre inscription, avant même la vérification du dossier. Vos données de test sont à vous seul.
Productionipk_live_…api.inopas.netUne fois votre dossier vérifié.

Les en-têtes

En-têtes d’authentification
En-têteValeurQuand
X-Inopas-KeyL’identifiant de votre clé.Toujours
X-Inopas-TimestampL’heure de l’envoi, en secondes depuis le 1er janvier 1970 (UTC).Toujours
X-Inopas-Signaturesha256= suivi de la signature en hexadécimal.Toujours
Idempotency-KeyUne valeur unique par opération, un UUID par exemple.Écritures (POST)

La chaîne à signer

Cinq parties, séparées par un point, dans cet ordre :

{horodatage}.{MÉTHODE}.{chemin}.{Idempotency-Key}.{corps}
Les cinq parties de la chaîne à signer
PartieExempleRègle
horodatage1790000000La valeur exacte de X-Inopas-Timestamp.
MÉTHODEPOSTEn majuscules.
chemin/v1/chargesSans l’hôte ni la query string : /v1/charges, pas /v1/charges?limit=5.
Idempotency-Keycmd-1042-essai-1La valeur exacte de l’en-tête. Vide pour une lecture.
corps{"amount_minor":…}Les octets exacts envoyés. Vide pour une lecture.

Une lecture n’a ni clé d’idempotence ni corps : ses deux dernières parties sont vides et la chaîne se termine par deux points consécutifs, comme 1790000000.GET./v1/merchant..

La signature est le HMAC-SHA256 de cette chaîne avec votre secret, en hexadécimal minuscule, précédé de sha256=.

L’Idempotency-Key fait partie de la signature : une requête interceptée ne peut pas être rejouée sous une autre clé, et l’horodatage limite toute tentative à une fenêtre de 5 minutes.

Une fonction à copier

Elle renvoie les en-têtes à ajouter à la requête. Passez-lui le corps déjà sérialisé, puis envoyez exactement ce corps-là.

Aucune dépendance : le module crypto de Node et hmac de Python suffisent. En Bash, la fonction lit le secret dans la variable SECRET.

Fonction de signature
# signer METHODE CHEMIN IDEMPOTENCY_KEY CORPS
signer() {
  local ts; ts=$(date +%s)
  local sig; sig=$(printf '%s' "$ts.$1.$2.$3.$4" \
    | openssl dgst -sha256 -hmac "$SECRET" | sed 's/^.*= //')
  echo "X-Inopas-Timestamp: $ts"
  echo "X-Inopas-Signature: sha256=$sig"
}

Vérifier votre implémentation

Avant tout appel réseau, faites signer ces valeurs fixes par votre code. Il doit produire exactement la signature attendue. Sinon, l’écart est dans la construction de la chaîne, pas dans nos serveurs : comparez-la caractère par caractère.

Gardez ce vecteur dans vos tests unitaires : il vous prévient si une évolution de votre code casse la signature.

Vecteur de test
secret           sk_sandbox_demo
horodatage       1790000000
méthode          POST
chemin           /v1/charges
Idempotency-Key  cmd-1042-essai-1
corps            {"amount_minor":2500000,"currency":"CDF","customer_ref":"+243810000000"}

chaîne signée
1790000000.POST./v1/charges.cmd-1042-essai-1.{"amount_minor":2500000,"currency":"CDF","customer_ref":"+243810000000"}

X-Inopas-Signature attendue
sha256=a2ae9d112027090cbfd88990f6ed97e78142c3b7520724eba98ddb441976ec74

Diagnostiquer un 401

Un refus d’authentification répond toujours 401 avec le code unauthorized. Le message, lui, dit laquelle des vérifications a échoué :

Messages d’erreur 401 et leurs causes
MessageCauses à vérifier
Authentification requise (clé API + signature).Un des trois en-têtes X-Inopas-* manque ou est vide.
Authentification refusée : horodatage invalide.X-Inopas-Timestamp n’est pas un nombre entier.
Authentification refusée : horodatage hors fenêtre (rejeu).Plus de 5 minutes d’écart avec notre horloge. Le plus souvent : un horodatage en millisecondes (Date.now() sans division par 1000), ou un serveur sans synchronisation NTP.
Authentification refusée : clé inconnue ou inactive.Clé révoquée, mal copiée, ou compte suspendu.
Cette clé de test ne fonctionne pas ici.Une clé de test (ak_sandbox ou ipk_sandbox_…) a été envoyée à https://api.inopas.net. Tout le test vit sur https://sandbox.inopas.net : le message donne l’adresse. Avec le SDK, ne renseignez pas baseUrl, il choisit l’hôte d’après la clé.
Cette clé d’argent réel ne fonctionne pas sur l’environnement de test.Une clé ipk_live_… a été envoyée à https://sandbox.inopas.net. Les clés réelles ne fonctionnent que sur https://api.inopas.net.
Authentification refusée : signature invalide.La chaîne signée diffère de la requête reçue : corps re-sérialisé après la signature, query string incluse dans le chemin, Idempotency-Key signée différente de celle envoyée, préfixe sha256= absent, ou secret d’un autre environnement.

Un seul branchement, tous les paiements.