> ## Documentation Index
> Fetch the complete documentation index at: https://docs.payluk.ng/llms.txt
> Use this file to discover all available pages before exploring further.

# Dispute resolution

> How disputes are raised between your customers and how you, the merchant, resolve them and disburse the held funds.

A **dispute** is how a funded escrow is contested when delivery doesn't go to
plan. Because Payluk is a [merchant platform](/concepts/merchant-customers),
disputes always involve **three** roles:

* **Buyer**: one of your customers (`merchant_user`) who funded the escrow.
* **Seller**: the customer (`merchant_user`) who created the payment link.
* **You, the merchant**: the **super-admin** account that arbitrates and
  releases the held funds. You are recorded on the dispute as the `admin`.

The held funds stay locked in escrow until **you** resolve the dispute. Neither
the buyer nor the seller can move the money once a dispute is open; only your
merchant super-admin key can.

<Warning>
  **Payluk does not resolve disputes between your customers.** You, the merchant,
  handle and settle every dispute raised by your customers yourself, using the
  dispute APIs documented here. Payluk only holds the funds in escrow and executes
  the outcome **you** submit (release to the seller or refund the buyer); it never
  arbitrates a `merchant_user` dispute on your behalf. Building a fair review and
  resolution process for your customers is your responsibility.
</Warning>

<Info>
  A dispute can only be raised while the escrow is **`OPENED`** (funded and held).
  Before funding there is nothing to dispute; after the escrow is `CLOSED`
  (`COMPLETED` / `REFUNDED`) it is terminal and can't be reopened.
</Info>

<Note>
  **Milestone escrows cannot be disputed.** Disputes apply only to **standard**
  escrows. A [milestone escrow](/concepts/milestone-escrows) releases its funds
  milestone-by-milestone as the buyer confirms each one, so there is no single held
  amount to contest; any attempt to open a dispute on one is rejected with
  `Milestone escrows cannot be disputed`.
</Note>

## Who opens a dispute, and who responds

**Only the buyer can open a dispute.** The seller cannot initiate one; they can
only **respond** to a dispute the buyer has already raised. Once both sides have
been heard, you (the merchant) review and resolve it.

Both parties act through
[Submit dispute](/api-reference/disputes/submit-dispute)
(`POST /v1/escrow/submit-dispute/{paymentToken}`), sending the acting customer's
ID in the **`customer-id`** header:

<CardGroup cols={2}>
  <Card title="Buyer: opens the dispute" icon="user">
    Raises the dispute any time after payment, while the escrow is `OPENED`,
    typically "I paid but the item never arrived / isn't as described."
  </Card>

  <Card title="Seller: responds only" icon="store">
    **Cannot open a dispute.** Their only proactive recourse is to
    [request to claim the funds](/api-reference/escrow/claim-funds) once the
    delivery window passes. If the buyer opens a dispute, the seller then replies
    on this endpoint to put their side on record before you resolve it.
  </Card>
</CardGroup>

Each side may submit **once**. A repeat submission is rejected
(`Buyer already submitted Dispute` / `Seller already submitted Dispute`). The
request is `multipart/form-data` with a `message` and an optional evidence `file`.

## How the status moves

The escrow's `status` tracks the dispute as each party weighs in:

<Steps>
  <Step title="Buyer opens the dispute → DISPUTED">
    The escrow moves to `status: DISPUTED` and the **seller is notified**. The
    buyer's submission is recorded under `dispute.buyer`.
  </Step>

  <Step title="Seller responds → INVESTIGATING">
    Once the seller has replied (recorded under `dispute.seller`), both sides are
    on record and the escrow automatically moves to `status: INVESTIGATING`. This
    is your cue to step in.
  </Step>

  <Step title="You resolve → COMPLETED or REFUNDED">
    You review both sides and
    [resolve the dispute](/api-reference/disputes/resolve-dispute), disbursing the
    held funds to the seller (`COMPLETED`) or back to the buyer (`REFUNDED`).
  </Step>
</Steps>

The `dispute` object on the escrow holds each side's contribution: `buyer`,
`seller`, and (after resolution) `admin`. Every entry carries its `message`,
optional `proofUrl`, the `userId`, and `createdAt`.

```json theme={null}
{
  "status": "INVESTIGATING",
  "dispute": {
    "buyer":  { "userId": "…c01", "message": "Item never arrived",       "proofUrl": "https://…", "createdAt": "1750584900" },
    "seller": { "userId": "…c02", "message": "Shipped, tracking attached", "proofUrl": "https://…", "createdAt": "1750585200" }
  }
}
```

## Reviewing disputes as the merchant

You have both a per-customer and a merchant-wide view. **Watch the `customer-id`
header**: it's required on the per-customer routes and **must be omitted** on
the merchant-wide ones.

| View                        | Route                                                                                       | `customer-id` |
| --------------------------- | ------------------------------------------------------------------------------------------- | ------------- |
| One customer's disputes     | [`GET /v1/escrow/dispute/get`](/api-reference/disputes/list-my-disputes)                    | **Required**  |
| A single dispute thread     | [`GET /v1/escrow/dispute/get/{escrowId}`](/api-reference/disputes/get-dispute-by-escrow-id) | **Required**  |
| Every customer's disputes   | [`GET /v1/escrow/all-dispute`](/api-reference/disputes/list-all-customers-disputes)         | **Omit**      |
| All escrow activity (feeds) | [`GET /v1/escrow/feeds`](/api-reference/disputes/get-escrow-feeds)                          | **Omit**      |

The merchant-wide routes are scoped to **your** `merchantId` automatically, so you
only ever see disputes belonging to your own customers.

## Resolving and disbursing funds

Resolution is **merchant super-admin only**: the route sits behind the
super-admin guard, so an individual customer cannot resolve their own dispute.
Call [Resolve dispute](/api-reference/disputes/resolve-dispute)
(`POST /v1/escrow/dispute/resolve/{escrowId}`) with **no `customer-id` header**,
as `multipart/form-data`:

| Field        | Required | Notes                                                            |
| ------------ | -------- | ---------------------------------------------------------------- |
| `resolution` | yes      | Your decision note, stored under `dispute.admin`.                |
| `status`     | yes      | `COMPLETED` (release to seller) or `REFUNDED` (return to buyer). |
| `file`       | no       | Optional supporting document.                                    |

What happens under the hood depends on the outcome you choose (disputes apply to
**standard** escrows only):

<AccordionGroup>
  <Accordion title="status: COMPLETED (release to the seller)">
    The full held amount (net of the seller fee) is released to the seller's main
    balance and the escrow closes as `COMPLETED`, with commission charged once.
  </Accordion>

  <Accordion title="status: REFUNDED (return to the buyer)">
    The held amount plus the buyer's pro-rata fee share is refunded to the
    buyer's main balance and the escrow closes as `REFUNDED`.
  </Accordion>
</AccordionGroup>

<Warning>
  You can only resolve a dispute on an escrow that belongs to one of **your**
  customers (the escrow's `merchantId` must match your account), and only while it
  is still open; an escrow already `COMPLETED` or `REFUNDED` will be rejected with
  `Escrow already completed`.
</Warning>

## The seller's recourse: claim funds

Since the seller can't open a dispute, their way to push a stalled deal forward is
to **request to claim the funds**. If the delivery window passes and the buyer
never confirms, the seller calls
[Claim funds](/api-reference/escrow/claim-funds), moving the escrow to `CLAIMED`.
This is the un-contested counterpart to a dispute; see the
[escrow lifecycle](/concepts/escrow-lifecycle) for how `CLAIMED`, `DISPUTED`, and
`INVESTIGATING` fit alongside the happy path.

<Note>
  For the precise meaning of every `status` value and how it combines with the
  escrow `state`, see the [status reference](/essentials/status-reference).
</Note>
