Disputes

A dispute — a chargeback — is a customer formally contesting a payment through their bank. The disputed amount leaves your balance the moment it opens, and a deadline starts ticking. This page covers the full lifecycle from chargeback to arbitration, and the API for fighting or accepting one.

The dispute lifecycle

Two fields track a dispute. status is the working state — who needs to act, and how it resolved. stage is how far the dispute has escalated through the card network's process. The status cycle repeats at each stage:

status — within each stage needs_response under_review submit evidence won resolved in your favor lost cardholder's favor accepted accept evidence_due_by passes — forfeited stage — how far it escalates chargeback pre_arbitration arbitration losing side contests to the network initial dispute second round of evidence network ruling — binding waiting on you — act before the deadline terminal — funds returned terminal — funds to cardholder
statusMeaningTerminal
needs_responseWaiting on you. Submit evidence or accept before evidence_due_by.No
under_reviewEvidence submitted; the issuer or network is reviewing. Nothing for you to do.No
wonResolved in your favor — the withheld funds return to your balance.Yes
lostResolved for the cardholder — the withheld funds are gone.Yes
acceptedYou accepted liability — same money outcome as lost, by your choice.Yes
stageMeaning
chargebackThe initial dispute. Most disputes start and end here.
pre_arbitrationThe side that lost the chargeback round contested the outcome. The status cycle runs again — a new needs_response, a new deadline, one more chance to submit evidence.
arbitrationThe card network itself decides. Its ruling is binding — there is no further escalation. Arbitration carries network fees for the losing side; going there is worth it only for large amounts with strong evidence.

Escalation to pre_arbitration arrives as a dispute.updated event: stage moves forward and status resets to needs_response with a fresh evidence_due_by. Nothing about your response is carried over automatically — the second round needs its own evidence submission.

The dispute object

Disputes are created by the network, never by you — the first you hear of one is a dispute.created webhook. Every dispute references the payment it contests:

GET /v1/disputes/dp_5Kw2mR8vQz1N
{
  "id": "dp_5Kw2mR8vQz1N",
  "object": "dispute",
  "payment": "pay_3Vt7Kd9sLm2x",
  "amount": 12900,
  "currency": "EUR",
  "reason": "fraudulent",
  "stage": "chargeback",
  "status": "needs_response",
  "evidence_due_by": "2026-07-30T23:59:59Z",
  "livemode": false,
  "created_at": "2026-07-16T18:40:22Z"
}

amount is the disputed amount in minor units — it can be less than the payment's amount when the customer contests part of an order. reason is normalized across card networks into five values:

reasonThe customer says…Evidence that wins
fraudulent"I didn't authorize this."Proof the cardholder made the order: AVS/CVV passes, 3DS authentication, delivery to the billing address, prior undisputed orders from the same customer.
product_not_received"It never arrived."tracking_number with delivery confirmation, or service_date with proof of provision for services.
duplicate"I was charged twice."Receipts showing two distinct orders — or, if it really is a duplicate, refund one charge and accept the dispute.
credit_not_processed"The refund never came."The refund id (rf_…) and its date if it was issued; your refund_policy and the customer's agreement to it if it was refused.
generalAnything else.Everything relevant — order details, communication, delivery proof.

Money during a dispute

When a dispute opens, the disputed amount is withheld from your balance — it shows on your settlement lines as a dispute debit against the original payment, whichever provider processed it. Then:

  • Won: the withheld amount returns to your balance in full.
  • Lost or accepted: the funds go to the cardholder and the debit stands.

The dispute keeps the payment's currency; on multicurrency accounts the debit hits the corresponding currency balance. Refunding a disputed payment doesn't resolve the dispute — once a chargeback is open, the money moves through the dispute, not through POST /v1/refunds.

Deadlines — evidence_due_by

Every dispute in needs_response carries evidence_due_by — an ISO 8601 timestamp set by the card network's rules for that stage. It is the single most important field on the object.

Miss the deadline, lose the dispute If evidence_due_by passes with no evidence and no acceptance, the dispute is forfeited — it moves to lost and the funds go to the cardholder. Treat dispute.created as an operational alert with a timer on it, not a notification to read later.

Submit well before the deadline, not at it: evidence is forwarded to the network in the format each scheme expects, and a package submitted with hours to spare leaves no room for a formatting round-trip. Once the dispute resolves, evidence_due_by is null.

Accept or contest — deciding

Two moves exist, and doing nothing is the worst version of accepting. The economics:

AcceptContest
WhenThe dispute is legitimate — the fraud was real, the goods didn't ship, the refund slipped.You have documentary evidence against the stated reason.
MoneyWithheld funds go to the cardholder now.Funds return if you win; nothing further is lost if you don't.
TimeImmediate, terminal.Weeks under review; longer if it escalates.
SignalCounts toward your dispute rate either way — accepting doesn't make the dispute not have happened.Same.

Fighting a legitimate dispute and losing costs the same as accepting — it just takes longer and adds review work on both sides. Accept the real ones fast, fight the wrong ones hard:

POST /v1/disputes/{id}/accept
curl -X POST https://api.finscale.dev/v1/disputes/dp_5Kw2mR8vQz1N/accept \
  -H "Authorization: Bearer sk_test_51FinscaleDemo…" \
  -H "Idempotency-Key: idem_dp_5Kw2mR8vQz1N_accept"

# → { "id": "dp_5Kw2mR8vQz1N", "status": "accepted", "evidence_due_by": null, … }

Accepting is terminal and cannot be undone. Only disputes in needs_response can be accepted — anything else returns dispute_not_actionable (see errors).

Submitting evidence

To contest, send the evidence package to POST /v1/disputes/{id}/evidence. fields carries structured text keyed by field name; files carries supporting documents as HTTPS URLs reachable by Finscale. Finscale forwards the package to the network in the format each scheme expects:

POST /v1/disputes/{id}/evidence — contest a product_not_received dispute
curl https://api.finscale.dev/v1/disputes/dp_5Kw2mR8vQz1N/evidence \
  -H "Authorization: Bearer sk_test_51FinscaleDemo…" \
  -H "Idempotency-Key: idem_dp_5Kw2mR8vQz1N_evidence" \
  -H "Content-Type: application/json" \
  -d '{
    "fields": {
      "product_description": "Wireless headphones, order ord_9f21_0716",
      "tracking_number": "3SFINS0912837465",
      "shipping_address": "Keizersgracht 12, 1015 CN Amsterdam, NL",
      "customer_communication": "Order confirmation and delivery notification, exported as PDF"
    },
    "files": [
      "https://files.example.com/evidence/ord_9f21_0716-delivery.pdf"
    ]
  }'
200 OK — the dispute moves to under_review
{
  "id": "dp_5Kw2mR8vQz1N",
  "object": "dispute",
  "payment": "pay_3Vt7Kd9sLm2x",
  "amount": 12900,
  "currency": "EUR",
  "reason": "fraudulent",
  "stage": "chargeback",
  "status": "under_review",
  "evidence_due_by": null,
  "livemode": false,
  "created_at": "2026-07-16T18:40:22Z"
}

Any fields keys are accepted; these are the ones the networks recognize:

FieldUse for
product_descriptionWhat was bought, tied to your order reference.
customer_communicationConfirmations, support threads, anything showing the customer knew about and engaged with the order.
tracking_numberCarrier tracking for physical goods — the single strongest field for product_not_received.
shipping_addressWhere it went — matching the billing address strengthens fraudulent defenses.
refund_policyYour policy text, for credit_not_processed disputes where the refusal was per policy.
service_dateWhen a service was provided, for non-shipped goods.
One shot per stage Most card schemes allow a single evidence submission per stage — there is no "add one more document" later. Assemble the complete package, then submit once. After submission the dispute is under_review and no longer actionable until (and unless) it returns to needs_response at a later stage.

Listing and monitoring

Webhooks are the push channel; the list endpoint is the reconciliation view. The filter you'll run daily is the action queue — everything waiting on you:

GET /v1/disputes — the action queue
curl "https://api.finscale.dev/v1/disputes?status=needs_response&limit=20" \
  -H "Authorization: Bearer sk_test_51FinscaleDemo…"

{
  "object": "list",
  "data": [
    {
      "id": "dp_5Kw2mR8vQz1N",
      "object": "dispute",
      "payment": "pay_3Vt7Kd9sLm2x",
      "amount": 12900,
      "currency": "EUR",
      "reason": "fraudulent",
      "stage": "chargeback",
      "status": "needs_response",
      "evidence_due_by": "2026-07-30T23:59:59Z",
      "livemode": false,
      "created_at": "2026-07-16T18:40:22Z"
    }
  ],
  "has_more": false,
  "url": "/v1/disputes"
}

Filter by status or by payment id; results are most recent first and paginate with starting_after. Retrieve a single dispute with GET /v1/disputes/{id}.

Webhook events

EventWhen
dispute.createdA dispute opened. Funds are already withheld; the response clock is running. Start here.
dispute.updatedStage or status changed without resolving — evidence acknowledged (under_review), or an escalation reset the dispute to needs_response at the next stage.
dispute.closedTerminal outcome: won, lost, or accepted. Reconcile the money on this event.
dispute.created — webhook payload
{
  "id": "evt_8Wn3xK7qP2Rd",
  "object": "event",
  "type": "dispute.created",
  "created_at": "2026-07-16T18:40:23Z",
  "livemode": false,
  "request_id": null,
  "data": {
    "object": {
      "id": "dp_5Kw2mR8vQz1N",
      "object": "dispute",
      "payment": "pay_3Vt7Kd9sLm2x",
      "amount": 12900,
      "currency": "EUR",
      "reason": "fraudulent",
      "stage": "chargeback",
      "status": "needs_response",
      "evidence_due_by": "2026-07-30T23:59:59Z",
      "livemode": false,
      "created_at": "2026-07-16T18:40:22Z"
    }
  }
}

Verify Finscale-Signature before trusting any payload, and treat request_id: null as normal — disputes originate from the network, not from one of your API requests. Delivery ordering is not guaranteed; key your handler on the dispute's current status, not on event arrival order. Details on the Webhooks page.

Error scenarios

ScenarioResponse
Evidence or accept on a dispute not in needs_response — already under review, already resolved, or a second evidence submission at the same stage 400 invalid_request_error, code dispute_not_actionable
Unknown dispute id 404 invalid_request_error
Deadline passed with no response Not an API error — the dispute silently becomes lost and dispute.closed fires.
400 — dispute_not_actionable
{
  "error": {
    "type": "invalid_request_error",
    "code": "dispute_not_actionable",
    "message": "This dispute is under_review and cannot accept evidence.",
    "doc_url": "https://docs.finscale.dev/errors/#dispute_not_actionable",
    "request_id": "req_7Hf3kQd2"
  }
}

Preventing disputes

The cheapest dispute is the one that never opens:

  • Screen the fraud out first. The risk engine blocks or reviews high-risk card payments before authorization — your dispute rate is the lagging measure of how well its thresholds are tuned.
  • Authenticate with 3DS. A payment authenticated via 3-D Secure shifts fraud liability to the issuer — fraudulent disputes on authenticated payments are largely defensible by design.
  • Refund fast. A refund issued when the customer first complains costs the disputed amount; the same refund after a chargeback costs the amount plus the dispute. credit_not_processed disputes are almost always a race you could have won.
  • Be recognizable. A clear billing descriptor and an order reference the customer can match to their purchase prevents the "I don't recognize this charge" reflex that becomes a fraudulent dispute.