Skip to main content
A dispute is a challenge against a payment your merchant has already received, where a third party asks for those funds to be returned. Rinne ingests the challenge from the payment provider, tracks it through a single lifecycle, and reports every step to your organization through the dispute.created and dispute.status-changed webhooks.
Rinne is never the claimant. It receives the provider’s report and relays it, so a dispute always originates outside Rinne—there is no way for your organization or Rinne to open one.

Where disputes come from

Disputes arrive from the provider that processed the original transaction. Each rail has its own vocabulary for the same idea, and Rinne absorbs that difference at the provider boundary: event names and payload fields describe Rinne’s lifecycle, not the provider’s. You integrate once, regardless of which rail a dispute came from. The type field names the rail:
Today disputes reach you from the PIX rail (PIX_INFRACTION). Card chargebacks will arrive through these same two events, so handling both types now needs no later change.
There are no dispute endpoints to call. Disputes are delivered to you exclusively as webhooks.

Lifecycle

A dispute tracks progress and verdict on two separate fields: status says how far the claim has got, and outcome says how it ended. status is an ordered progression and a dispute only ever moves forward. CLOSED is the single terminal status, so a finished dispute is exactly status == "CLOSED". outcome is null for the entire life of the dispute until it closes, and is always set once it has: A partially resolved claim is UPHELD with a smaller amount, not a separate outcome.
A dispute never regresses and never reopens. If you receive an event whose new_status is not ahead of the status you have stored, treat it as a duplicate and ignore it—old_status is always strictly earlier than new_status, so a stale or repeated provider delivery produces no event at all.

Disputes and the disputed transaction

Every dispute is linked to the transaction it challenges through transaction_id. Use that field to reconcile a dispute against the payment in your own system. The dispute lifecycle is tracked separately from the transaction lifecycle: a dispute.created or dispute.status-changed event reports the claim’s progress and is not a transaction status change. You receive dispute events independently of any transaction.status-changed event for the same payment. A single transaction can accumulate more than one dispute. Key your own records on dispute_id, not on transaction_id.

The dispute webhooks

Both events use the same envelope, Svix signatures, and retry behavior as every other Rinne event—see Webhooks. In the envelope, source is dispute-service and company_id is the merchant the claim is filed against. Both payloads carry an entity field holding the full dispute object as it stood when the event was emitted, so you never need a follow-up request to act on a dispute. The API reference lists every field it contains; two of them are easy to misread:
  • amount is the amount at risk, in cents—an upper bound rather than an exact figure, currently derived from the disputed transaction. Rails that report an amount of their own will carry it here instead.
  • dispute_details is free text describing the claim, and its author is not recorded—it may be the payer in their own words, a risk analyst at the reporting institution, or a generated message. Display it and read it, but never parse it or branch your logic on its contents.

dispute.created

Emitted when Rinne records a dispute for the first time.
A dispute is usually created at OPEN. A dispute whose first notification to reach Rinne already describes a finished claim is created at CLOSED, with outcome already set—so handle a created event that is already closed rather than assuming a status change will follow.

dispute.status-changed

Emitted when the dispute moves forward: OPEN to UNDER_REVIEW, or either of those to CLOSED with a verdict in outcome.
Group the events belonging to one dispute by dispute_id. Unlike some Rinne events, correlation_id here is unique per event rather than shared across a dispute’s lifetime, so it identifies the delivery, not the claim.

Next steps

Webhooks

Endpoint setup, Svix signature verification, and retries

Transactions

The payment lifecycle a dispute challenges

Ledger entries

How settled amounts are recorded against a merchant

API reference

Full dispute event schemas under Webhooks → Events