Status flow

draft
  └─► invite_pending   (counterparty invited)
        └─► funded      (payment confirmed)
              ├─► active        (counterparty accepted)
              │     ├─► inspection   (goods-based: 24h window)
              │     │     └─► released ✓
              │     ├─► released ✓    (immediate release categories)
              │     └─► disputed ─► resolved → released / refunded
              ├─► cancelled ✗   (before acceptance)
              └─► refunded ✗

Step-by-step API calls

1. Create the escrow

POST /escrow-create
Authorization: Bearer <token>

{
  "category": "goods_products",
  "payer_role": "initiator",
  "title": "iPhone 15 Pro Max 256GB",
  "counterparty_phone": "+2348012345679",
  "amount": 500000
}
Response includes fee_breakdown (so your UI can show costs before payment) and conversation_id.

2. Fund the escrow

POST /escrow-fund
Authorization: Bearer <token>

{
  "escrow_id": "<id>",
  "payment_method": "wallet"
}
Also accepts saved_card (with card_id) or bank_transfer (async — returns virtual account details). Status moves to funded once confirmed → counterparty is notified via WhatsApp.
See the Payments & Fund Releases guide for fee structure, funding source details, and the bank transfer async flow.

3. Counterparty accepts

POST /escrow-accept
Authorization: Bearer <token>

{
  "escrow_id": "<id>"
}
Status moves to active. For goods_products, a 24-hour inspection window starts automatically.

4. Release funds

POST /escrow-release
Authorization: Bearer <token>

{
  "escrow_id": "<id>"
}
Funds are unlocked from escrow and credited to the payee’s available_balance atomically. If the payee has auto_withdraw enabled, a Paystack bank transfer fires immediately — no separate withdrawal step needed. For milestone-based escrows, use POST /milestone-release per milestone instead. The escrow moves to released automatically once all milestones are released.
See the Payments & Fund Releases guide for the full release and withdrawal lifecycle.

Key rules

Buyer and seller cannot be the same user. The API enforces this at creation.
Once funded, an escrow can only be cancelled via POST /escrow-cancel, which internally raises a dispute. The counterparty must agree or an admin resolves it.
  • Only the payer can call POST /escrow-fund
  • Only the counterparty can call POST /escrow-accept or POST /escrow-decline
  • Either party can call POST /dispute-raise on an active/inspection escrow
  • Only the payer (or admin) can call POST /escrow-release