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 le net sur un portefeuille escrow du magasin, invisible dans le solde et dans .
Clés
| Clé | Encaissement instantané | /escrows et escrowId |
|---|---|---|
| Clé plateforme (émise par le SP pour ce marchand) | Oui | Oui (si le flag est activé) |
| 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).
Flux
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 → expiration à 7 jours.- Doit être dans le futur, au plus 30 jours.
- 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, flag escrow activé, clé plateforme. - Rails v1 : Wave, Orange, Djamo. Autre moyen → 400.
allowMultiplePayments: true+escrowId→ 400.- Clé Owner / flag off / clé SP entreprise → 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.
Exemple ESCROW_HELD (enveloppe, 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. Parsez event avant de traiter le corps comme une transaction.
/escrows vs /transactions
| Surface | Rôle |
|---|---|
Lifecycle du hold (pending → held → plus tard released / refunded / expired) | |
| Portefeuille opérable seulement. Instantané, transferts, retraits. Rien pendant le hold. | |
| Disponible opérable seulement |
Erreurs fréquentes
| Code | Quand |
|---|---|
| 400 | holdUntil invalide ; rail non supporté ; lien multi-paiements + escrowId |
| 403 | Clé Owner / Dashboard, clé entreprise SP, ou flag escrow inactif |
| 404 | Magasin ou escrow introuvable, ou autre marchand |
| 409 | L'escrow est déjà lié à un collect |
La libération () et le remboursement / timeout arrivent dans les livraisons suivantes. D'ici là, un hold reste held jusqu'à expiration configurée côté Jèko.