customer-id header points to at each step. Read
it once and the individual API reference
pages will fall into place.
Two actors run through every flow:
- Seller — the merchant customer selling the item (the escrow is created on their behalf).
- Buyer — the merchant customer funding the escrow.
customer-id header to whichever one the current step concerns. The
secret key (Authorization: Bearer sk_…) is on every request.The journey at a glance
Phase 0 — Set up (once per merchant)
| # | Call | Endpoint | Notes |
|---|---|---|---|
| 0.1 | Get countries | GET /v1/misc/countries | Returns the countryId you need to create customers. |
| 0.2 | List categories / Create category | GET / POST /v1/escrow/category… | Optional. Group your escrows into a catalog. |
Phase 1 — Onboard your customers
Almost every later call needs acustomer-id, so you create the people first.
| # | Call | Endpoint | customer-id |
|---|---|---|---|
| 1.1 | Create merchant customer (seller) | POST /v1/customer/create | — (super-admin key) |
| 1.2 | Create merchant customer (buyer) | POST /v1/customer/create | — (super-admin key) |
| 1.3 | Update permissions | PUT /v1/customer/permissions/{customerId} | — |
The seller needs
canSell, the buyer needs canBuy. A buyer with canBuy disabled is rejected at payment time.customer-id header for the rest
of the flow.
Phase 2 — The standard escrow flow
A single item, paid once, released once. This is the common case.Create the escrow — as the seller
POST /v1/escrow/create with
customer-id: <sellerId>. This is multipart/form-data (so you can attach
up to 5 images).id and paymentToken; state: AWAITING_PAYMENT, status: PENDING,
settlementType: STANDARD. While in AWAITING_PAYMENT you can still
edit or
delete it.Buyer resolves the link (optional)
Share the
paymentToken. The buyer’s side can read the full escrow with
GET /v1/escrow/verify/{paymentToken}
to display amount, purpose and images before paying.Make sure the buyer's wallet is funded
Paying with
gateway: WALLET requires balance. Top it up first:- Production:
POST /v1/payment/create-intent(transactionType: DEPOSIT) → returns anauthorizationUrl→ buyer pays →POST /v1/payment/verify. - Staging shortcut:
POST /v1/payment/topupwithcustomer-id: <buyerId>.
PAYSTACK/FLUTTERWAVE gateway.Fund the escrow — as the buyer
POST /v1/payment/escrow with
customer-id: <buyerId>.state: OPENED / status: ONGOING and the delivery window starts.With a non-wallet gateway this returns an
authorizationUrl; after the buyer pays, call POST /v1/payment/verify to settle it into escrow.Release the funds
The happy path — the buyer confirms delivery:
POST /v1/escrow/confirm-payment/{escrowId}
with customer-id: <buyerId>. The escrow closes as COMPLETED and the seller
is paid net of fee.If the happy path doesn’t happen
Buyer never confirms → seller claims
Buyer never confirms → seller claims
After the delivery window elapses, the seller calls
GET /v1/escrow/claim-funds/{paymentToken}
(customer-id: <sellerId>). Allowed only when OPENED and the window has
passed. Closes as CLAIMED.Something's wrong → dispute
Something's wrong → dispute
Either party opens
POST /v1/escrow/submit-dispute/{paymentToken}.
You, the merchant, then resolve it with
POST /v1/escrow/dispute/resolve/{escrowId} —
release to the seller or refund the buyer (REFUNDED).
Phase 3 — The milestone escrow flow
Fund the whole project upfront; release it in stages as each milestone is confirmed. Same money rails, different create + release steps.Create the milestone escrow — as the seller
POST /v1/escrow/milestone/create
with customer-id: <sellerId>. Unlike standard create, this is JSON (no
file upload).At least 2 milestones.
Milestone amounts must sum to the escrow
amount.whoPays must be buyer on milestone escrows.settlementType: MILESTONE with a milestones[] array — each milestone
has its own id and status: PENDING.Fund it in full — as the buyer
Same endpoint as standard:
POST /v1/payment/escrow with
customer-id: <buyerId>. The buyer pays the entire amount once. Escrow →
OPENED.Confirm each milestone — as the buyer
Read the current milestones any time with
GET /v1/escrow/milestone/{paymentToken}.
As each deliverable lands, the buyer confirms it:
POST /v1/escrow/milestone/confirm/{escrowId}/{milestoneId}
with customer-id: <buyerId>. That milestone’s net share (its amount minus
its pro-rata fee) is released and its status becomes RELEASED.Phase 4 — Monitor & reconcile (any time)
| Call | Endpoint | Use |
|---|---|---|
| List escrow transactions | GET /v1/escrow/transactions | All escrows and their states. |
| Get payment history | GET /v1/payment/history | Money in/out per customer. |
| Get customer wallet | GET /v1/wallet | mainBalance vs escrowBalance. |
| List my disputes / feeds | GET /v1/escrow/dispute/get, /feeds | Dispute activity. |
Endpoint checklist
- Standard payment
- Milestone payment
POST /v1/customer/create— seller, then buyer (once)POST /v1/escrow/create—customer-id: sellerGET /v1/escrow/verify/{paymentToken}— buyer previews (optional)- Fund wallet:
POST /v1/payment/create-intent→POST /v1/payment/verify(ortopupon staging) POST /v1/payment/escrow—customer-id: buyerPOST /v1/escrow/confirm-payment/{escrowId}—customer-id: buyer
- Exceptions:
GET /v1/escrow/claim-funds/{paymentToken}·POST /v1/escrow/submit-dispute/{paymentToken}·POST /v1/escrow/dispute/resolve/{escrowId}
Selling multiple units off one link? That introduces escrow duplication —
read Multi-quantity escrows next.