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
1
Set up (once)
Get your secret key, and optionally seed categories and look up a
countryId.2
Onboard your customers
Create the buyer and seller as merchant customers.
3
Create the deal
Create a standard escrow or a milestone escrow. You get a
paymentToken and an id.4
Fund it
The buyer pays into escrow. Funds are held, not released.
5
Deliver & release
The buyer confirms (or each milestone is confirmed), releasing funds net of fees.
6
Handle exceptions
Claims, disputes and refunds (only if the happy path doesn’t complete).
Phase 0: Set up (once per merchant)
These don’t move money, so do them once and cache the IDs.
Phase 1: Onboard your customers
Almost every later call needs acustomer-id, so you create the people first.
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.1
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.2
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.3
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.4
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.5
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.1
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.2
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.3
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.4
Auto-complete
When the final milestone is released, the escrow moves to
CLOSED / COMPLETED automatically. No separate confirm-payment call.Phase 4: Monitor & reconcile (any time)
Endpoint checklist
- Standard payment
- Milestone payment
POST /v1/customer/create: seller, then buyer (once)POST /v1/escrow/createwithcustomer-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/escrowwithcustomer-id: buyerPOST /v1/escrow/confirm-payment/{escrowId}withcustomer-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.