Sous-marchands
Page générée depuis la spécification OpenAPI que la passerelle sert (
GET /v1/openapi.json). Ne la modifiez pas à la main : elle est réécrite à chaque build.
| Méthode | Chemin | Description |
|---|---|---|
GET |
/v1/sub-merchants |
Lister ses sous-marchands |
POST |
/v1/sub-merchants |
Créer un sous-marchand |
GET |
/v1/sub-merchants/{id} |
Lire un sous-marchand |
PATCH |
/v1/sub-merchants/{id}/capabilities |
Modifier les capacités d'un sous-marchand |
POST |
/v1/sub-merchants/{id}/status |
Suspendre ou réactiver un sous-marchand |
GET |
/v1/sub-merchants/{id}/kyb-file |
Lire le dossier KYB d'un sous-marchand |
POST |
/v1/sub-merchants/{id}/kyb/documents |
Téléverser une pièce KYB |
POST |
/v1/sub-merchants/{id}/kyb/persons |
Déclarer un bénéficiaire ou un représentant |
POST |
/v1/sub-merchants/{id}/kyb/verification |
Ouvrir la vérification d'identité d'une personne |
GET |
/v1/sub-merchants/{id}/api-keys |
Lister les clés API d'un sous-marchand |
POST |
/v1/sub-merchants/{id}/api-keys |
Émettre une clé API pour un sous-marchand |
DELETE |
/v1/sub-merchants/{id}/api-keys/{keyId} |
Révoquer une clé API d'un sous-marchand |
GET /v1/sub-merchants
Lister ses sous-marchands
Les marchands rattachés au compte appelant. ⚠️ Réservé aux comptes agrégateurs : un compte qui n'est pas agrégateur (is_aggregator) reçoit 403 sur toutes les routes de cette section.
Réponses
200— La liste des sous-marchands. (object[])
POST /v1/sub-merchants
Créer un sous-marchand
Crée un marchand rattaché au compte appelant. ⚠️ Réservé aux comptes agrégateurs : un compte qui n'est pas agrégateur (is_aggregator) reçoit 403 sur toutes les routes de cette section.
Le parent est l'APPELANT — il ne se déclare pas dans le corps : la règle de propriété est parent_client_id = appelant, et un parent fourni par le client serait un contrôle de cloisonnement choisi par celui qu'il contrôle.
La création n'accepte AUCUNE capacité : le sous-marchand naît avec toutes ses capacités désactivées (remboursements et TPE compris), et un corps qui porte encore capabilities est refusé (422 capabilities_not_accepted) — réglez-les ensuite avec PATCH /v1/sub-merchants/{id}/capabilities, le seul endroit où elles se gèrent. Rien n'est ignoré en silence.
Le palier tarifaire n'est pas au choix : l'enfant hérite du tarif du parent par la hiérarchie. merchant_kind est presque toujours absent — l'enfant hérite du genre du parent, et un genre différent de celui du parent est refusé (422). Le champ existe pour qu'un appelant puisse dire ce qu'il croit et se le voir corriger, jamais pour choisir.
Corps de la requête
| Champ | Type | Requis | Description |
|---|---|---|---|
business_name |
string | oui | |
trading_name |
string | non | |
email |
string | non | |
phone |
string | non | |
country |
string | non | ISO alpha-2 ; vide = celui du parent. |
business_type |
string | non | |
merchant_kind |
string | non | enterprise | sme ; doit valoir celui du parent. |
metadata |
object | non | 20 clés au plus ; clé ≤ 64, valeur ≤ 500 caractères. |
Réponses
201— Le sous-marchand créé. (object)
GET /v1/sub-merchants/{id}
Lire un sous-marchand
L'état d'un enfant du compte appelant. ⚠️ Réservé aux comptes agrégateurs : un compte qui n'est pas agrégateur (is_aggregator) reçoit 403 sur toutes les routes de cette section.
Paramètres
| Nom | Emplacement | Requis | Description |
|---|---|---|---|
id |
path | oui | L'identifiant PUBLIC du sous-marchand (UUID), tel que renvoyé par la création et la liste. ⚠️ Ce n'est pas l'identifiant interne, qui ne quitte jamais la plateforme. |
Réponses
200— Le sous-marchand. (object)
PATCH /v1/sub-merchants/{id}/capabilities
Modifier les capacités d'un sous-marchand
Neuf capacités sont délégables, activables comme désactivables, chacune sous le droit aggregator_manage_* correspondant du parent : tpe_enabled, cnp_enabled, mobile_money_enabled, internal_transfers_enabled, pi_enabled (paiements instantanés BCEAO, sous aggregator_manage_pi — le rappel (recall) n'a pas de capacité propre : la portée de clé can_recall suit pi_enabled), payout_enabled (sous aggregator_manage_payout), refund_enabled (sous aggregator_manage_refund), collection_accounts_enabled (sous aggregator_manage_collection — le compte de collecte de l'enfant est ensuite ouvert automatiquement une fois son propre KYB approuvé) et settlement_schedule (l'horaire de règlement complet — l'interrupteur seul est refusé sans cycle — et jamais le compte de destination). ⚠️ Le drapeau propre de l'enfant décide ensuite à chaque porte : le parent demande, la capacité et le kyc_status de l'enfant répondent. ⚠️ internal_transfers_enabled accorde à l'enfant SES PROPRES virements ; déplacer l'argent d'un enfant reste sous aggregator_manage_payout. ⚠️ Réservé aux comptes agrégateurs : un compte qui n'est pas agrégateur (is_aggregator) reçoit 403 sur toutes les routes de cette section.
Paramètres
| Nom | Emplacement | Requis | Description |
|---|---|---|---|
id |
path | oui | L'identifiant PUBLIC du sous-marchand (UUID), tel que renvoyé par la création et la liste. ⚠️ Ce n'est pas l'identifiant interne, qui ne quitte jamais la plateforme. |
Corps de la requête
| Champ | Type | Requis | Description |
|---|---|---|---|
tpe_enabled |
boolean | non | |
cnp_enabled |
boolean | non | |
mobile_money_enabled |
boolean | non | |
internal_transfers_enabled |
boolean | non | |
pi_enabled |
boolean | non | |
payout_enabled |
boolean | non | |
refund_enabled |
boolean | non | |
collection_accounts_enabled |
boolean | non | |
settlement_schedule |
object | non | L'horaire de règlement, en bloc. |
settlement_schedule.auto_settlement_enabled |
boolean | non | |
settlement_schedule.settlement_cycle |
string | non | |
settlement_schedule.settlement_delay_days |
integer | non | |
settlement_schedule.settlement_day_of_week |
integer | non | 0–6, dimanche = 0 (hebdomadaire) |
settlement_schedule.settlement_day_of_month |
integer | non | 1–28 (mensuel) |
settlement_schedule.settlement_time_of_day |
string | non | HH:MM |
settlement_schedule.settlement_min_minor |
string | non | unités mineures |
Réponses
200— Le sous-marchand mis à jour. (object)
POST /v1/sub-merchants/{id}/status
Suspendre ou réactiver un sous-marchand
Change l'état d'un enfant. Le motif est conservé. ⚠️ Réservé aux comptes agrégateurs : un compte qui n'est pas agrégateur (is_aggregator) reçoit 403 sur toutes les routes de cette section.
Paramètres
| Nom | Emplacement | Requis | Description |
|---|---|---|---|
id |
path | oui | L'identifiant PUBLIC du sous-marchand (UUID), tel que renvoyé par la création et la liste. ⚠️ Ce n'est pas l'identifiant interne, qui ne quitte jamais la plateforme. |
Corps de la requête
| Champ | Type | Requis | Description |
|---|---|---|---|
status |
string | oui | active | suspended. |
reason |
string | non |
Réponses
200— Le sous-marchand mis à jour. (object)
GET /v1/sub-merchants/{id}/kyb-file
Lire le dossier KYB d'un sous-marchand
L'état du dossier de conformité de l'enfant : pièces attendues, pièces reçues, personnes déclarées, verdict. ⚠️ Réservé aux comptes agrégateurs : un compte qui n'est pas agrégateur (is_aggregator) reçoit 403 sur toutes les routes de cette section.
Paramètres
| Nom | Emplacement | Requis | Description |
|---|---|---|---|
id |
path | oui | L'identifiant PUBLIC du sous-marchand (UUID), tel que renvoyé par la création et la liste. ⚠️ Ce n'est pas l'identifiant interne, qui ne quitte jamais la plateforme. |
Réponses
200— Le dossier KYB.
POST /v1/sub-merchants/{id}/kyb/documents
Téléverser une pièce KYB
⚠️ multipart/form-data, pas du JSON — la pièce est un fichier. 10 Mo au plus. ⚠️ Réservé aux comptes agrégateurs : un compte qui n'est pas agrégateur (is_aggregator) reçoit 403 sur toutes les routes de cette section.
Les pièces attendues dépendent du pays d'immatriculation de l'enfant ; GET /v1/sub-merchants/{id}/kyb-file énumère celles qui manquent.
Paramètres
| Nom | Emplacement | Requis | Description |
|---|---|---|---|
id |
path | oui | L'identifiant PUBLIC du sous-marchand (UUID), tel que renvoyé par la création et la liste. ⚠️ Ce n'est pas l'identifiant interne, qui ne quitte jamais la plateforme. |
Corps de la requête
⚠️ multipart/form-data, pas du JSON.
| Champ | Type | Requis | Description |
|---|---|---|---|
file |
file | oui | Le fichier, 10 Mo au plus. |
doc_type |
string | oui | Le code de la pièce, tel qu'énuméré par kyb-file. |
doc_number |
string | non | |
doc_country |
string | non | ISO alpha-2. |
issued_at |
string | non |
Réponses
201— La pièce enregistrée.
POST /v1/sub-merchants/{id}/kyb/persons
Déclarer un bénéficiaire ou un représentant
Déclare une personne sur le dossier de l'enfant : bénéficiaire effectif, représentant légal, dirigeant. ⚠️ Réservé aux comptes agrégateurs : un compte qui n'est pas agrégateur (is_aggregator) reçoit 403 sur toutes les routes de cette section.
Paramètres
| Nom | Emplacement | Requis | Description |
|---|---|---|---|
id |
path | oui | L'identifiant PUBLIC du sous-marchand (UUID), tel que renvoyé par la création et la liste. ⚠️ Ce n'est pas l'identifiant interne, qui ne quitte jamais la plateforme. |
Corps de la requête
| Champ | Type | Requis | Description |
|---|---|---|---|
person_type |
string | oui | Le rôle déclaré sur le dossier. |
phone |
string | non | |
email |
string | non | |
role |
string | non | |
ownership_pct |
number | non | Pourcentage de détention. |
is_ubo |
boolean | non | Bénéficiaire effectif. |
is_pep |
boolean | non | Personne politiquement exposée. |
Réponses
201— La personne déclarée.
POST /v1/sub-merchants/{id}/kyb/verification
Ouvrir la vérification d'identité d'une personne
Ouvre une session de vérification pour une personne déjà déclarée. Le portail de conformité résout la session par identifiant de contact, d'où phone / email à côté de person_id. ⚠️ Réservé aux comptes agrégateurs : un compte qui n'est pas agrégateur (is_aggregator) reçoit 403 sur toutes les routes de cette section.
Paramètres
| Nom | Emplacement | Requis | Description |
|---|---|---|---|
id |
path | oui | L'identifiant PUBLIC du sous-marchand (UUID), tel que renvoyé par la création et la liste. ⚠️ Ce n'est pas l'identifiant interne, qui ne quitte jamais la plateforme. |
Corps de la requête
| Champ | Type | Requis | Description |
|---|---|---|---|
person_id |
string | oui | |
phone |
string | non | |
email |
string | non |
Réponses
201— La session de vérification ouverte.
GET /v1/sub-merchants/{id}/api-keys
Lister les clés API d'un sous-marchand
Les clés que CE compte a émises pour ce sous-marchand — métadonnées et portées effectives, jamais de secret. Les clés que le sous-marchand a créées lui-même n'y figurent pas : elles ne sont pas celles du parent. ⚠️ Réservé aux comptes agrégateurs : un compte qui n'est pas agrégateur (is_aggregator) reçoit 403 sur toutes les routes de cette section. Ces trois routes exigent EN PLUS le droit aggregator_manage_api_keys du compte (accordé par neo-pays ; 403 sub_merchant_api_keys_not_enabled sinon) et, sur la clé appelante, les portées can_manage_sub_merchants ET can_manage_sub_merchant_api_keys (403 insufficient_scope sinon).
Paramètres
| Nom | Emplacement | Requis | Description |
|---|---|---|---|
id |
path | oui | L'identifiant PUBLIC du sous-marchand (UUID), tel que renvoyé par la création et la liste. ⚠️ Ce n'est pas l'identifiant interne, qui ne quitte jamais la plateforme. |
Réponses
200— Les clés émises par ce compte pour ce sous-marchand. (object[])404— Aucun sous-marchand de ce compte ne porte cet identifiant.
POST /v1/sub-merchants/{id}/api-keys
Émettre une clé API pour un sous-marchand
Émet une clé API appartenant au SOUS-MARCHAND : elle s'authentifie comme lui, jamais comme le parent. Le secret (secret_key, et signing_secret si la signature est exigée) n'est renvoyé qu'UNE fois, dans cette réponse (Cache-Control: no-store) ; seule son empreinte est conservée.
Les portées sont bornées par les capacités du SOUS-MARCHAND, pas par celles du parent : une portée que l'enfant ne peut pas exercer est refusée (409 precondition_failed, qui nomme la capacité). can_use_pi et can_recall sont donc accordables dès que l'enfant a pi_enabled ; can_recall implique can_use_pi.
⚠️ Une portée inconnue ou mal orthographiée est refusée (422 unknown_scope), jamais ignorée. Les portées réservées — can_use_tontine_pi, can_manage_sub_merchants, can_manage_collection_accounts et can_manage_sub_merchant_api_keys — ne peuvent JAMAIS être portées par une clé de sous-marchand (403 reserved_scope).
Une clé live exige un sous-marchand en production (is_live) ; sinon émettez une clé test. L'émission est inscrite au journal d'audit du sous-marchand, au nom du parent. ⚠️ Réservé aux comptes agrégateurs : un compte qui n'est pas agrégateur (is_aggregator) reçoit 403 sur toutes les routes de cette section. Ces trois routes exigent EN PLUS le droit aggregator_manage_api_keys du compte (accordé par neo-pays ; 403 sub_merchant_api_keys_not_enabled sinon) et, sur la clé appelante, les portées can_manage_sub_merchants ET can_manage_sub_merchant_api_keys (403 insufficient_scope sinon).
Paramètres
| Nom | Emplacement | Requis | Description |
|---|---|---|---|
id |
path | oui | L'identifiant PUBLIC du sous-marchand (UUID), tel que renvoyé par la création et la liste. ⚠️ Ce n'est pas l'identifiant interne, qui ne quitte jamais la plateforme. |
Corps de la requête
| Champ | Type | Requis | Description |
|---|---|---|---|
name |
string | non | |
key_type |
string | non | test par défaut. live exige un sous-marchand en production. |
scopes |
object | non | Nom de portée → booléen. Une portée absente vaut false. |
scopes.can_initiate_payment |
boolean | non | |
scopes.can_payout |
boolean | non | |
scopes.can_refund |
boolean | non | |
scopes.can_read_transactions |
boolean | non | |
scopes.can_manage_webhooks |
boolean | non | |
scopes.can_read_customers |
boolean | non | |
scopes.can_write_customers |
boolean | non | |
scopes.can_manage_risk_lists |
boolean | non | |
scopes.can_read_collection_accounts |
boolean | non | |
scopes.can_use_pi |
boolean | non | |
scopes.can_recall |
boolean | non | |
scopes.can_cnp |
boolean | non | |
expires_in_days |
integer | non | 0 = sans expiration. |
require_signature |
boolean | non | Exiger la signature des requêtes (X-NeoPays-Signature) pour cette clé. Définitif pour la vie de la clé. |
Réponses
201— La clé émise, et son secret — affiché une seule fois. (object)403— Droit, portée ou portée réservée refusés.404— Aucun sous-marchand de ce compte ne porte cet identifiant.409— Le sous-marchand ne peut pas exercer une portée demandée, ou n'est pas en production pour une clé live.422— Portée inconnue ou valeur invalide.
DELETE /v1/sub-merchants/{id}/api-keys/{keyId}
Révoquer une clé API d'un sous-marchand
Révocation immédiate et définitive d'une clé que CE compte a émise pour ce sous-marchand ; elle est refusée dès l'appel suivant. Une clé que le parent n'a pas émise reçoit la même 404 qu'une clé inconnue. Corps facultatif {"reason": "…"}, conservé avec la révocation et au journal d'audit du sous-marchand. ⚠️ Réservé aux comptes agrégateurs : la clé appelante doit porter can_manage_sub_merchants. Contrairement à l'émission et à la liste, la révocation n'exige NI le droit aggregator_manage_api_keys NI la portée can_manage_sub_merchant_api_keys : un parent qui les a perdus peut toujours révoquer les clés qu'il a émises. Quand le lien prend fin (détachement, rattachement à un autre parent, clôture), ces clés sont révoquées automatiquement.
Paramètres
| Nom | Emplacement | Requis | Description |
|---|---|---|---|
id |
path | oui | L'identifiant PUBLIC du sous-marchand (UUID), tel que renvoyé par la création et la liste. ⚠️ Ce n'est pas l'identifiant interne, qui ne quitte jamais la plateforme. |
keyId |
path | oui | L'identifiant de la clé, tel que renvoyé par la création et la liste des clés du sous-marchand. |
Corps de la requête
| Champ | Type | Requis | Description |
|---|---|---|---|
reason |
string | non |
Réponses
204— Clé révoquée.404— Aucune clé active émise par ce compte pour ce sous-marchand ne porte cet identifiant.