Escrow (séquestre opérationnel)
Bloquer un encaissement Partner jusqu'à libération par la clé plateforme du Service Provider
Produit Service Provider
L'escrow n'est pas un encaissement instantané. Seule la clé plateforme (clé API marchand émise par le Service Provider) peut créer un pot, le lier à un collect, et plus tard le libérer ou le rembourser. Le marchand ne peut pas se débloquer lui-même.
crée uniquement un pot en attente. L'encaissement reste sur les endpoints existants (payment_requests / payment_links) via escrowId. Ce n'est pas un séquestre réglementé : Jèko retient les fonds sur un portefeuille escrow du magasin, invisible dans le solde et dans . Seule la part de l'opérateur de paiement est prélevée au paiement. Les frais Jèko (et votre commission de Service Provider) ne sont prélevés qu'à la libération ou au remboursement.
Clés
| Clé | Encaissement instantané | /escrows et escrowId |
|---|---|---|
| Clé plateforme (émise par le SP pour ce marchand) | Oui | Oui |
| Clé Owner / Dashboard du marchand | Oui | 403 |
Clé entreprise du SP (/service_providers/*) | Non (pas d'argent) | 403 |
La clé plateforme est scoped au marchand. Elle ne peut pas toucher les escrows d'un autre marchand (404). Vous l'obtenez via Clés et magasin dédié.
Il n'y a pas d'activation par marchand. Dès que la clé plateforme existe, et escrowId sont disponibles pour ce marchand.
De la création à la libération
POST /partner_api/escrows { storeId, holdUntil? } → pending
POST /partner_api/payment_requests corps habituel + escrowId
ou POST /partner_api/payment_links corps habituel + escrowId
→ le client paie (redirect / in-app / soundbox / lien)
→ escrow held ; GET /transactions reste vide pour ce job
GET /partner_api/escrows/{id} lifecycle (pending → held)Sans escrowId, le collect crédite tout de suite le solde opérable — comportement inchangé.
1. Créer le pot
Create escrow (Partner API)curl -X POST "https://api.jeko.africa/partner_api/escrows" \
-H "X-API-KEY: platform_key" \
-H "X-API-KEY-ID: platform_key_id" \
-H "Content-Type: application/json" \
-d '{
"storeId": "59ae202a-f583-4a15-970f-9e99bd1e0baa"
}'Corps : uniquement storeId et, optionnellement, holdUntil (ISO 8601 UTC). Pas de paymentDetails, successUrl, deviceId, forceProviderDirect, ni titre de lien.
holdUntilomis → auto-libération à 7 jours (fonds crédités au solde opérable du marchand).- Doit être dans le futur, au plus 30 jours.
- À l'échéance, Jèko libère le hold (pas un remboursement au payeur).
- Un pot = un seul collect. Relier deux fois le même
escrowId→ 409.
Réponse (pending) :
{
"id": "7c2d1a90-0b1e-4c3a-9f11-2e8c4d6a1b20",
"storeId": "59ae202a-f583-4a15-970f-9e99bd1e0baa",
"status": "pending",
"holdUntil": "2026-09-14T20:00:00.000Z",
"amount": null,
"paymentRequestId": null,
"paymentLinkId": null,
"createdAt": "2026-09-07T20:00:00.000Z"
}2. Lier le collect existant
Ajoutez escrowId au corps habituel de Paiement en ligne ou de Liens de paiement.
curl -X POST "https://api.jeko.africa/partner_api/payment_requests" \
-H "X-API-KEY: platform_key" \
-H "X-API-KEY-ID: platform_key_id" \
-H "Content-Type: application/json" \
-d '{
"storeId": "59ae202a-f583-4a15-970f-9e99bd1e0baa",
"amountCents": 1000000,
"currency": "XOF",
"reference": "ORDER-1042",
"escrowId": "7c2d1a90-0b1e-4c3a-9f11-2e8c4d6a1b20",
"paymentDetails": {
"type": "redirect",
"data": {
"paymentMethod": "wave",
"successUrl": "https://example.com/success",
"errorUrl": "https://example.com/error"
}
}
}'Règles au bind :
- Même
storeIdque le pot, pot encorepending, clé plateforme. - Rails v1 : Wave, Orange, Djamo. Autre moyen → 400.
allowMultiplePayments: true+escrowId→ 400.- Clé Owner / Dashboard ou clé entreprise du SP → 403.
- Pot introuvable ou autre marchand → 404.
Le client paie comme aujourd'hui (redirect, soundbox, lien). Poller ou reste valide.
3. Après le paiement (held)
- :
status: "held",amountrenseigné,paymentRequestId(etpaymentLinkIdsi lien). - :
escrowIdprésent, pas detransaction— le hold n'est pas dépensable. - : vide pour ce job. Le solde magasin () ne change pas.
- Webhook
ESCROW_HELD, pasTRANSACTION_COMPLETED. Ne créditez pas le marchand comme si le paiement était dépensable.TRANSACTION_COMPLETEDarrive plus tard, à la libération (voir plus bas).
Exemple ESCROW_HELD (walletAvailableBalance = solde opérable) :
{
"event": "ESCROW_HELD",
"escrowId": "7c2d1a90-0b1e-4c3a-9f11-2e8c4d6a1b20",
"storeId": "59ae202a-f583-4a15-970f-9e99bd1e0baa",
"status": "held",
"amount": { "amount": 985000, "currency": "XOF" },
"paymentRequestId": "d22c81f3-ee04-4ec5-8bd2-cd8af5dabcfc",
"paymentLinkId": null,
"businessName": "Boutique Example",
"storeName": "Cocody",
"walletAvailableBalance": { "amount": 0, "currency": "XOF" }
}Un abonnement events: ["TRANSACTION_COMPLETED"] ne reçoit pas ESCROW_HELD. events: null (défaut) le reçoit. Lisez d'abord l'en-tête Jeko-Event. Le champ event du corps le répète, ce n'est pas le discriminant. Qui reçoit l'appel est dans Événements. L'abonnement se crée avec la clé Service Provider : Webhooks marchand.
/escrows vs /transactions
| Surface | Rôle |
|---|---|
Lifecycle du hold (pending → held → released / refunded) | |
Portefeuille opérable seulement. Instantané, transferts, retraits. Rien pendant le hold. Après libération (manuelle ou timeout) : une ligne type=escrow avec le net crédité, les frais réellement facturés et le moyen de paiement du payeur. | |
| Disponible opérable seulement |
Erreurs fréquentes
| Code | Quand |
|---|---|
| 400 | holdUntil invalide ; rail non supporté ; lien multi-paiements + escrowId |
| 403 | Clé Owner / Dashboard ou clé entreprise du SP |
| 404 | Magasin ou escrow introuvable, ou autre marchand |
| 409 | L'escrow est déjà lié à un collect |
Libération, remboursement, timeout
Tant que le pot est held :
- prélève les frais Jèko (et votre commission de Service Provider), puis crédite le net sur le solde opérable du marchand. Résultat :
status: "released"et une lignetype=escrowsur , avec le net, les frais et le moyen de paiement du payeur. Deux webhooks partent :ESCROW_RELEASEDetTRANSACTION_COMPLETED, dont le corps est cette lignetype=escrow. - renvoie au payeur le montant net de frais : le montant du paiement moins les frais quand le marchand paie les frais, ou le montant hors frais quand le payeur les a payés. Les frais Jèko sont prélevés sur le pot, pas sur le solde opérable. Le solde opérable ne paie que les éventuels frais de remboursement. Résultat :
status: "refunded"et webhookESCROW_REFUNDED, mais pas deTRANSACTION_COMPLETEDet rien de dépensable sur . - À
holdUntil, Jèko libère automatiquement comme unrelease:status: "released",ESCROW_RELEASEDetTRANSACTION_COMPLETED, solde opérable crédité. Ce n'est pas un remboursement.
Exemple : un paiement Wave de 500 XOF avec 8 XOF de frais payés par le marchand. À la libération, la ligne type=escrow affiche un montant de 492 et des frais de 8. En cas de remboursement, le payeur reçoit 492.
Un pot déjà held avant la mise en place de ce fonctionnement garde l'ancien comportement : à la libération, il crédite le net avec des frais à 0 et n'envoie que ESCROW_RELEASED.