Overview
Either party can raise a dispute on an active, funded, or inspection escrow. Raising a dispute freezes the escrow — no releases, refunds, or state changes can occur until the dispute is resolved.
Status flow
negotiation (24-hour window — parties try to agree)
├─► resolved ✓ (agreement reached — admin or mutual)
└─► escalated (24h expired without resolution)
└─► resolved ✓ (admin decision: release or refund)
└─► closed (admin closed without resolution)
Raising a dispute
POST /dispute-raise
Authorization: Bearer <token>
{
"escrow_id": "<id>",
"reason_code": "item_not_as_described",
"reason": "The phone arrived with a cracked screen."
}
A 24-hour negotiation window starts immediately. Both parties are notified.
Reason codes
reason_code | Use case |
|---|
item_not_as_described | Goods don’t match the listing |
item_not_delivered | Goods/service never arrived |
service_not_completed | Freelance work not delivered |
payment_issue | Payment amount or timing dispute |
cancel_request | Buyer wants to cancel after acceptance |
other | Anything else — use free-text reason |
Escalating to admin
After the 24-hour negotiation window, either party can escalate:
POST /dispute-escalate
Authorization: Bearer <token>
{
"dispute_id": "<id>",
"note": "Seller is unresponsive."
}
An admin (support/compliance role) will review and resolve.
Resolving
Admin resolution:
POST /dispute-resolve
Authorization: Bearer <token> # must be admin
{
"dispute_id": "<id>",
"resolution": "release", # or "refund"
"note": "Seller provided delivery proof."
}
release → funds go to payee. refund → funds return to payer.
Rules
A disputed escrow is completely frozen. No milestone releases, no manual withdrawals of locked funds, and no status changes until the dispute is resolved.
- Only one open dispute per escrow at a time
- Disputes on milestone-based escrows freeze only the specific milestone, not the whole escrow
POST /escrow-cancel internally calls POST /dispute-raise if the escrow is already funded