Skip to main content
A dispute is how a funded escrow is contested when delivery doesn’t go to plan. Because Payluk is a merchant platform, 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.
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, refund the buyer, or split the held funds between them); it never arbitrates a merchant_user dispute on your behalf. Building a fair review and resolution process for your customers is your responsibility.
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 / SPLIT) it is terminal and can’t be reopened.
Vault escrows cannot be disputed. A vault escrow is a pooled stake with no buyer and seller to contest, so it is settled by you declaring a winner; opening a dispute on one is rejected with Vault escrows cannot be disputed. A milestone escrow can be disputed, over whatever is still held: the milestones the buyer never confirmed. Once every milestone has been released there is nothing left to contest.

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 (POST /v1/escrow/submit-dispute/{paymentToken}), sending the acting customer’s ID in the customer-id header:

Buyer: opens the dispute

Raises the dispute any time after payment, while the escrow is OPENED, typically “I paid but the item never arrived / isn’t as described.”

Seller: responds only

Cannot open a dispute. Their only proactive recourse is to request to claim the 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.
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:
1

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.
2

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.
3

You resolve → COMPLETED, REFUNDED or SPLIT

You review both sides and resolve the dispute, disbursing the held funds to the seller (COMPLETED), back to the buyer (REFUNDED), or dividing them between the two in amounts you name (SPLIT).
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.

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. 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 (POST /v1/escrow/dispute/resolve/{escrowId}) with no customer-id header, as multipart/form-data: What happens under the hood depends on the outcome you choose:
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. Any additional (delivery) fee is credited to your merchant wallet, exactly as it would be on a normal completion. additionalFeeRefundable is ignored here.
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. Any additional (delivery) fee is settled in the same pass, to the party additionalFeeRefundable names.
sellerAmount is released to the seller’s main balance and buyerAmount is returned to the buyer’s, in one pass. The escrow closes as SPLIT, a split object records the division, and commission is charged once, as on a completion. Any additional (delivery) fee is settled to the party additionalFeeRefundable names, exactly as on a refund. On a milestone escrow, every milestone that was still held is marked SPLIT.

Splitting the held funds

When neither side is wholly right, divide the money instead of handing all of it to one party. Send status: SPLIT with both amounts:
The two amounts must add up to exactly what the escrow still holds, which is not always its amount: Amounts carry at most two decimal places, because the pool can end in a half unit: the escrow fee is a percentage and whoPays: both halves it again. Read the pool off the escrow before you rule.
A split whose amounts do not add up to what is held is rejected and no money moves. The same applies to a SPLIT sent without amounts, and to amounts sent alongside a COMPLETED or REFUNDED resolution.
The division is recorded on the escrow and returned in the response, the escrow.split webhook, and every later read of the escrow:

Deciding who keeps the delivery fee

By the time you rule on a dispute you know something you could not know when the escrow was priced: whether the delivery actually happened. So this is the moment the delivery fee’s fate is decided. Send additionalFeeRefundable alongside your ruling.
  • true: the buyer gets the delivery fee back with the principal.
  • false: you are credited it anyway; use this when you already paid to ship.
  • omitted: the escrow’s existing setting applies (true unless you changed it when setting the fee).
Your choice is persisted on the escrow, so the resolution response and the webhook both reflect what you decided. Either way the money is settled to a party; it is never left sitting with the platform.
Only REFUNDED and SPLIT resolutions are affected. Sending the field with COMPLETED changes nothing about the payout: a completed escrow always pays the delivery fee to you.
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, REFUNDED or SPLIT will be rejected with Escrow already completed.

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, moving the escrow to CLAIMED. This is the un-contested counterpart to a dispute; see the escrow lifecycle for how CLAIMED, DISPUTED, and INVESTIGATING fit alongside the happy path.
For the precise meaning of every status value and how it combines with the escrow state, see the status reference.