Skip to content
StableAudienceDevOwner@partners-teamDernière revue2026-05-24

Référence API

Annexe technique : endpoints publics, headers conventions, codes erreur, catalogue events webhook. Pour les guides narratifs, voir Connecter un marchand et Encaisser pour un marchand.

Base URL

EnvironnementBase URL
Productionhttps://prod.paywithnex.com/api
Test (staging)https://dev.paywithnex.com/api

Tous les endpoints partner publics sont préfixés /partners-public/.

Authentification

Toutes les requêtes doivent porter le header :

http
Authorization: Bearer nex_sk_live_xxxxxxxxxxxxxxxxxxxxxxxx

Sans ce header, ou avec une clé invalide / révoquée, vous recevez 401.

Endpoints

Connexions

MéthodePathScope requisDescription
POST/partners-public/connections/requestaucunDemande une connexion à un marchand par téléphone E.164. Anti-énumération : renvoie 200 même si marchand inconnu.
GET/partners-public/connections/:idaucunLit le statut courant d'une connexion. Renvoie 404 si elle ne vous appartient pas.
POST/partners-public/connections/:id/revokeaucunRévoque une connexion active de votre côté (status → revoked, revoked_by=integration).

Commandes

MéthodePathScope requisDescription
POST/partners-public/ordersorders.writeCrée un QR de paiement temporaire au nom d'un marchand connecté.

Schémas de payload

POST /connections/request

jsonc
// Request
{
  "merchantPhone": "+242069887766",  // E.164 obligatoire
  "scopes": ["orders.write"],         // au moins 1, valeurs autorisées ci-dessous
  "requestedReason": "Terminal MaishaPay déployé chez la boulangerie"  // optionnel
}

// Response 200
{
  "connectionId": "0f165ba2-ec79-4b1a-b5e3-072e6a44a229",
  "status": "pending",
  "expiresAt": "2026-05-30T16:44:07.768Z",
  "alreadyExisted": false
}

GET /connections/:id

jsonc
// Response 200 (ou 404 si la connexion n'est pas à vous)
{
  "id": "0f165ba2-...",
  "integrationId": "4dd5e991-...",
  "merchantId": "0d85d7a4-...",
  "status": "active",  // pending | active | rejected | revoked | expired
  "scopes": ["orders.write"],
  "requestedReason": "...",
  "pendingExpiresAt": "2026-05-30T16:44:07.768Z",
  "activatedAt": "2026-05-24T08:15:23.000Z",  // null si pas active
  "revokedAt": null,
  "revokedBy": null,  // merchant | integration | admin | system | null
  "createdAt": "...",
  "updatedAt": "..."
}

POST /orders

jsonc
// Request
{
  "merchantId": "0d85d7a4-...",        // UUID obligatoire (issu de la connexion active)
  "amount": 2500,                       // int > 0, plus petite unité de la devise
  "currencyCode": "XAF",                // ISO 4217, optionnel (défaut XAF)
  "ttlSeconds": 300,                    // optionnel, 60..900, défaut 300
  "description": "Baguettes × 3",       // optionnel, 0-280 chars
  "externalReference": "MAISHA-ORDER-42" // optionnel, 0-128 chars, renvoyé dans le webhook
}

// Response 201
{
  "orderId": "cdefc6f6-...",
  "qrToken": "T_bfB1miJXZISq2_21ixG2D",
  "status": "pending",
  "amount": 2500,
  "currencyCode": "XAF",
  "expiresAt": "2026-05-24T12:05:00.000Z",
  "merchantId": "0d85d7a4-...",
  "integrationId": "4dd5e991-..."
}

Catalogue scopes

ScopePermet
orders.writeCréer des commandes (QR de paiement) au nom du marchand via POST /orders.
orders.readLire le statut des commandes créées (endpoint à venir V2).

Au moment de demander une connexion, vous précisez les scopes nécessaires. Le marchand voit la liste en clair lors de l'arbitrage.

Codes erreur

Authentification (401)

codeCauseAction
INVALID_INTEGRATION_CREDENTIALSBearer manquant, mal formé, ou clé révoquée.Vérifier le header Authorization, recharger la clé depuis le secret manager.
INTEGRATION_REVOKEDVotre intégration entière a été révoquée par Nex.Contacter partners@paywithnex.com.

Autorisation (403)

codeCauseAction
NO_ACTIVE_CONNECTIONPas de connexion active pour ce merchantId avec votre intégration.Vérifier que le marchand a accepté ; refaire GET /connections/:id.
MISSING_SCOPELa connexion existe mais ne porte pas le scope requis (ex: orders.write absent).Re-demander une connexion avec les bons scopes.

Validation (400)

codeCauseAction
VALIDATION_ERRORBody mal formé : amount ≤ 0, ttlSeconds < 60 ou > 900, merchantId pas UUID, scope inconnu…Lire errors[] pour le détail champ par champ.
INVALID_PHONE_FORMATmerchantPhone n'est pas E.164 valide.Format obligatoire +<countryCode><number>, sans espaces.
INVALID_AMOUNTamount non entier ou ≤ 0.Convertir en plus petite unité (XAF/XOF = unités).
INVALID_TTLttlSeconds < 60.Minimum 60 secondes.
TTL_TOO_LONGttlSeconds > 900.Max 15 min.

Conflit (409)

codeCauseAction
CONFLICTÉtat incohérent : ex. essayer d'accepter une connexion déjà active, révoquer une connexion expired.Lire le message pour le détail.

Not found (404)

codeCause
CONNECTION_NOT_FOUNDconnectionId inconnu, ou n'appartient pas à votre intégration (anti-leak).

Headers réponse standard

Toutes les réponses Nex portent :

http
Content-Type: application/json; charset=utf-8
X-Request-Id: <uuid>          // ID unique de la requête — à inclure dans tout report bug
Server-Timing: total;dur=247  // temps de traitement Nex en ms (utile pour debug latency)

Catalogue events webhook

order.paid

Émis quand un QR créé via POST /orders est payé par un client final (transaction completed côté ledger).

Payload data :

jsonc
{
  "orderId": "cdefc6f6-...",                   // = QR id
  "transactionId": "tx-uuid-...",              // référence interne Nex (pour support)
  "amount": 2500,
  "currencyCode": "XAF",
  "paidAt": "2026-05-24T12:02:34.000Z",        // commit ledger
  "externalReference": "MAISHA-ORDER-42",      // votre référence (echo), absent si non fourni
  "description": "Baguettes × 3"               // echo, absent si non fourni
}

Quand : entre 100 ms et quelques secondes après le commit ledger (latence enqueue BullMQ + worker pickup).

Garanties : at-least-once (jusqu'à 7 retries × 30s × 2^n = ~1h cumulé). Voir Recevoir les webhooks.

Format Nex-Signature (HMAC SHA256)

text
Nex-Signature: t=1716553354,v1=5e7c1a3f4b8d2c9e6f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3
ComposantDescription
tUnix timestamp en secondes au moment de la signature (côté Nex).
v1hex_lower(HMAC_SHA256(webhook_secret, "${t}.${rawBody}"))

Code de vérification : voir Guide implémentation receiver.

Convention de versioning

  • Préfixe public : /api/... (le versioning v1 est géré côté serveur, transparent pour vous). Une montée de version majeure ne serait introduite qu'en cas de breaking change (sur un horizon de 12+ mois) et annoncée à l'avance.
  • Additions de champs dans les payloads existants : non-breaking, déployées sans préavis. Votre receiver doit tolérer des champs inconnus (ignorer plutôt que crasher).
  • Retraits de champs : passent par un cycle de deprecation 6 mois avec annonce email aux contacts techniques.
  • Nouveaux events webhook : votre receiver doit retourner 200 quand il reçoit un event qu'il ne sait pas traiter (ne pas crasher).

Voir aussi

Nex — Plateforme fintech CEMAC