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. Thetype 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.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.
Result class
Outcomes group into two result classes by which side of the claim they favor. The class of a closed dispute never changes:Merchant-favorable
DISMISSED and WITHDRAWN — the merchant keeps the funds.Merchant-unfavorable
UPHELD — the funds go back to the payer.CLOSED, its outcome is final within its class, but it may be restated to the other outcome in the same class. The most common case: a claim closes DISMISSED because the reporting institution’s analysis disagreed, and the provider then sends a follow-up cancellation, which restates the same verdict as WITHDRAWN. Both mean the merchant keeps the funds.
A restatement:
- Overwrites
outcomeon the dispute. - Leaves
status,amount,dispute_details,deadline_at, andconcluded_atat their first-close values. - Does not emit another
dispute.status-changedevent, because the status did not move.
GET /v1/disputes/{id} for your own company, or GET /v1/merchants/disputes/{id} for your organization’s merchants. If your reconciliation only relies on events, a merchant-favorable dispute stays merchant-favorable and no action is required on your side.
A terminal state whose outcome falls in the other result class (for example, a DISMISSED dispute followed by an UPHELD verdict) is treated as a contradiction, not a restatement. Rinne rejects it and no event fires; the dispute keeps its first-close outcome, and no further update is applied to it until Rinne resolves the conflict.
Disputes and the disputed transaction
Every dispute is linked to the transaction it challenges throughtransaction_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; a few are easy to misread:
amountis 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_detailsis 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.company_name(trading name, nullable) andcompany_full_name(legal name) identify the merchant the claim is filed against, alongsidecompany_id. They match the pair the transaction response exposes, so you can show the merchant from the event without a second lookup. Both are optional on theentitysnapshot: an event can carry neither, so fall back tocompany_idwhen they are absent. Neither field is in the dispute schema of the API reference yet.
dispute.created
Emitted when Rinne records a dispute for the first time.
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.
An outcome restated within the same result class (for example,
DISMISSED → WITHDRAWN) does not emit a second dispute.status-changed. The status is still CLOSED, so nothing moved. If your workflow needs the latest outcome value, read the dispute through the API rather than waiting for another event.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

