Skip to content

Disputes

When a payer contests a payment, how you respond, and what a loss costs you.

A dispute is a payer, or their card network, telling Wajub that a payment was wrong. It is opened against a single payment and ends one of two ways: you keep the money, or it goes back and your balance is debited.

Unlike a refund, you do not start a dispute and you cannot create one through the API. Your side of it is answering.

Where a dispute comes from

A dispute reaches you from one of two places.

The payer opens it from Pocket, the Wajub wallet where they can see the payments they have made. They pick a reason, describe the problem, and that description becomes the first message on the dispute thread.

Reason the payer picksWhat they are claiming
product_not_receivedThey paid and nothing arrived
product_not_as_describedWhat arrived was not what was sold
duplicate_chargeThey were charged twice for one thing
fraudulentThey did not make this payment
otherAnything else, explained in the description

A dispute from Pocket carries the full amount of the payment, and a due_date to answer by, seven days after it opened.

The provider reports a chargeback. When a card network or a provider notifies a chargeback on one of your payments, Wajub opens a dispute for it. It carries the provider's own provider_reference, its reason code in reason, and the amount the provider disputes, which can be less than the payment. It also carries a due_date: the provider's deadline when it sends one, seven days after opening otherwise.

Either way, a payment has one dispute in flight at a time. A second notice for the same case does not open a second dispute.

The amount is held while the dispute is open

A dispute opened from Pocket, on a payment collected through Wajub's own provider, moves the disputed amount from your available balance to your disputed balance, as far as your available balance allows. Winning moves it back. Losing debits it, as described below.

The states a dispute moves through

A dispute lands open. Submitting evidence moves it to under_review on its own, you do not set that yourself. From either of those two states it can end as won or lost, and both are final.

Wajub adjudicates. There is no endpoint that lets you declare yourself the winner; what you can do is put the evidence in front of the people who decide, or concede.

A resolved status you will not see

The list endpoint accepts ?status=resolved, but that status is never returned. Filter on won and lost for finished disputes.

Respond with evidence

This is the part that decides the outcome, and it is worth being thorough. Each piece of evidence is filed under a type, and you can post several calls to build up a case.

POSThttps://api.wajub.com/disputes/{id}/submit-evidence
evidence_typeenumrequired
One of customer_communication, proof_of_delivery, service_documentation, receipt, product_description, cancellation_policy, refund_policy, duplicate_charge_documentation, other.
evidence_textstringoptional
Your written argument for this piece, up to 2 000 characters.
evidence_filefileoptional
One file: PDF, JPG, JPEG, PNG, DOC, DOCX or TXT, 10 MB at most. Send the call as multipart/form-data.

The type is a slot, not a label. Post twice with proof_of_delivery and the second call replaces the first, it does not add to it. Use a different type for each distinct piece, and put everything you want to say about one piece into that one call.

Send a text, a file, or both: a call with neither answers 422, and the dispute stays where it was. Without a file, the piece is stored as your text alone: evidence.proof_of_delivery is then a string rather than an object. A file is stored under a name of its own, with the extension of its content; the name you gave it comes back as file_name.

Files are private: no address opens one on its own. Every answer of the API that returns the dispute gives each file, evidence and message attachments alike, a url, a signed link valid 30 minutes. Past that, read the dispute again for a fresh one. A webhook carries file_path and no link, since it is kept and resent long after a link would have expired.

Because a file is involved, this is a form upload rather than a JSON body.

curl https://api.wajub.com/disputes/dsp_hrgUOE225KMKULRQqYvlh/submit-evidence \
  -H "Authorization: sk.xxxxxxxxxxxxxxxx…" \
  -F "evidence_type=proof_of_delivery" \
  -F "evidence_text=Delivered 12 Sept, signed for by the customer." \
  -F "evidence_file=@/path/to/delivery-note.pdf"

The call answers 200 OK with the dispute as it now stands, already moved to under_review, and your evidence collected under evidence.

Response · 200 OK
{
"code": 200,
"status": "OK",
"message": "Evidence submitted successfully",
"dispute": {
"id": "dsp_hrgUOE225KMKULRQqYvlh",
"transaction": "trx_CSUGajfv9xh0XQ5wu2lx",
"customer": "cus_sAaim5apjocIgtlhzJY3wQ8s",
"amount": 25000,
"currency": "XAF",
"status": "under_review",
"reason": "product_not_received",
"evidence": {
"proof_of_delivery": {
"text": "Delivered 12 Sept, signed for by the customer.",
"file_path": "…",
"file_name": "delivery-note.pdf",
"uploaded_at": "2026-09-11T12:04:00+00:00",
"url": "https://…?signature=…"
}
},
"sandbox": false,
"created_at": "2026-09-11T12:00:00+00:00"
}
}

Evidence can only be filed while the dispute is open or under_review. Once it is won or lost, the call answers 422 and the case is shut.

Conceding, and a call that does not do what its name suggests

If the payer is right, concede early rather than letting it run.

POSThttps://api.wajub.com/disputes/{id}/accept

Accepting takes an optional merchant_response, up to 2 000 characters, which is recorded against the dispute. It sets the dispute to lost immediately and there is no way back, and it sends the money back to the payer: Wajub creates a refund of the disputed amount, capped to what is still refundable on the payment.

That refund carries the reason customer_complaint and the dispute's own reason in metadata.dispute_reason, and it gives the payer back everything they paid for that amount, a fee they paid on top included. If the refund cannot be created, the call fails and the dispute stays as it was.

Three cases create no refund, and the dispute still ends lost:

  • A chargeback. The payer's bank has already returned the money and the provider takes it back from Wajub, so a refund would pay the payer twice.
  • Nothing left to refund. Earlier refunds already returned the whole payment.
  • A dispute in another currency than its payment. There is no amount to refund in the payment's own currency.

Talk to the payer

A dispute carries a message thread, opened by the payer's own description. You can reply on it.

POSThttps://api.wajub.com/disputes/{id}/messages

Messages take content, required and up to 5 000 characters, and an optional attachments array of files under the same limits as evidence. Each attachment comes back with file_name, file_path and the same 30-minute url. POST /disputes/{id}/send-message is an alias for the same thing. Your messages are recorded with a sender_type of merchant, the payer's with customer, and the whole thread comes back on a retrieve. The thread stays open after the outcome: a message on a dispute already won or lost is accepted and recorded, but changes nothing about the result.

Reading disputes

Retrieving one returns it with its transaction, its customer and its full message thread.

GEThttps://api.wajub.com/disputes/{id}
GEThttps://api.wajub.com/disputes
Query parameterAccepts
per_page1 to 100, defaults to 25
statusopen, under_review, won, lost
searchFree text over the dispute id, reason and description
date_from, date_toDates, date_to no earlier than date_from
cursorSwitches to cursor pagination

Beyond the obvious fields, a dispute carries description from the payer, your merchant_response, the evidence you filed, resolved_at once it is finished, and metadata.

How due_date is set

Every dispute carries due_date, the deadline to answer by. On a dispute opened from Pocket, it is seven days after the opening. On a provider chargeback, it is the provider's deadline when it sends one, seven days after the opening otherwise. Past its deadline, a Pocket dispute stays open until Wajub decides it.

What a loss costs

On a payment collected through Wajub's own provider, a lost dispute takes the disputed amount off your balance, capped at whatever has not already left through a refund on the same payment, so the money cannot be taken twice. On a payment collected through your own provider account, Wajub holds none of the money, and the provider settles the chargeback with you directly.

A flat dispute fee is charged on top, 15 000 XAF by default in the dispute's currency, when the loss comes from the API, with accept or close, or from a provider chargeback. Accepting from the Dashboard does not charge it. So losing a 25 000 XAF dispute through the API costs 40 000 XAF, not 25 000. The debits happen on the status change itself, not on anything you call afterwards.

A dispute does not change the original payment's status. The refund created when you accept shows in it like any other refund, from API version 2026-10-11. When you accept, the refund Wajub creates for the payer is an ordinary refund, with its own refund.* events, except that it does not take the disputed amount a second time: the loss took it once, whichever is recorded first, and the refund sends it to the payer. If the payer paid Wajub's fee on top of the price (bearer: customer), that fee is debited from you as well, since the payer gets back everything they paid. The money movement shows on your balance, which is where you reconcile it.

Losing also feeds back into risk scoring: a lost dispute raises the assessed risk of the payer behind it, so Shield weighs future payments from them more heavily.

Webhooks

Seven events, and the ones worth acting on are the outcomes, plus the reminder.

EventFires when
dispute.createdA dispute was opened, by a payer or from a chargeback. Read it and decide how to answer
dispute.updatedAny field changed, including every status change
dispute.wonResolved in your favour, nothing leaves your balance
dispute.lostResolved against you, the amount is debited
dispute.closedSent together with dispute.lost. A won dispute does not send it
dispute.deadline_approachingThe deadline is two days away and the dispute is still open or under_review. Sent once, with metadata.reminded_at set; answer it now
dispute.deletedThe dispute record was removed

dispute.deadline_approaching is sent in live and in sandbox, for every dispute with a due_date: Pocket disputes and chargebacks alike. Writing metadata.reminded_at on the dispute also sends a dispute.updated beside it.

dispute.createdevent
A payer has opened a dispute on one of your payments.
Payload
{
"id": "evt_Qp7Tz3Wk5Yb1NdLm2Xc94Rf8",
"event": "dispute.created",
"created": "2026-09-11T12:00:00+00:00",
"livemode": true,
"data": {
"id": "dsp_hrgUOE225KMKULRQqYvlh",
"transaction": "trx_CSUGajfv9xh0XQ5wu2lx",
"customer": "cus_sAaim5apjocIgtlhzJY3wQ8s",
"amount": 25000,
"currency": "XAF",
"status": "open",
"reason": "product_not_received",
"description": "Ordered on 2 Sept, nothing delivered."
}
}

Deduplicate on X-Wajub-Delivery-Id, as everywhere else. Registration and signature verification are in Webhooks.

In the Dashboard

Disputes lists them with their status and the payment behind each one. Opening a dispute gives you the payer's description, the message thread, and the same three actions the API exposes plus one it does not: you can mark a dispute as won from here when Wajub has adjudicated in your favour.

The section needs the manage_disputes permission, which is separate from manage_payments, so a teammate can run orders without being able to concede a dispute on your behalf.

Fewer disputes is cheaper than winning them

A dispute costs you time whatever the outcome, so the work that pays best happens before one exists.

Refund willingly when a customer complains and you have no case: a refund you choose costs you the amount, a dispute you lose costs the amount plus the flat dispute fee. Keep proof of delivery where you can attach it in one click. And let Shield reject the payments most likely to come back at you, since a payment refused up front cannot be disputed at all.

What did you think of this content?