disputes
Stable. Describes behaviour that is built and covered by tests in this repository.
GET /v1/disputes #
The cases customers opened with their banks about a payment, newest first
A dispute (a chargeback, or an inquiry that may become one) is kept as the provider last reported it: outcome is open while it is undecided (for a chargeback the provider has taken the money back until it decides), won when it ended in your favour or never became a chargeback, lost when the cardholder won. Each step is also sent as the payment.disputed webhook event. A dispute of a payment Payrudder did not make has no invoice_id. Stripe's and Paddle's own words are in provider_status; UNVERIFIED against a live account. 503 when the payment service does not answer.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
invoice_id | query | string · uuid | Only the disputes of this invoice |
outcome | query | open | won | lost | |
limit | query | integer |
Responses
| Status | Meaning | Body |
|---|---|---|
200 | OK | ListDisputesResponse |
400 | Error envelope | Error |
503 | Error envelope | Error |
Example response
{
"disputes": [
{
"id": "string",
"provider": "stripe",
"dispute_id": "string",
"payment_ref": "string",
"amount_minor": "string",
"currency": "string",
"outcome": "open",
"formal": false,
"provider_status": "string",
"opened_time": "2026-11-03T10:15:00Z",
"handled": false,
"note_count": 1
}
]
}curl
curl -X GET https://YOUR-API-ADDRESS/v1/disputes \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"GET /v1/disputes/{id}/history #
The notes and marks you made on a dispute, newest first
What you did with the case inside Payrudder: each note, and each time it was marked as handled or the mark was lifted. id is the case's id as GET /v1/disputes gives it. actor (who) is left out for a viewer of the account, as in the audit log. At most the newest 200. 404 payments.dispute.not_found for a case that is not yours.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id required | path | string |
Responses
| Status | Meaning | Body |
|---|---|---|
200 | OK | ListDisputeEventsResponse |
400 | Error envelope | Error |
404 | Error envelope | Error |
503 | Error envelope | Error |
Example response
{
"events": [
{
"id": "string",
"action": "note",
"create_time": "2026-11-03T10:15:00Z"
}
]
}curl
curl -X GET https://YOUR-API-ADDRESS/v1/disputes/<id>/history \
-H "Authorization: Bearer $PAYRUDDER_API_KEY"POST /v1/disputes/{id}/notes #
Write a note on a dispute
A note is for you and your colleagues: what you found out, what you answered at the provider, where the evidence is. It is kept with the case, one to 2000 characters, and recorded in the audit log without its text. Payrudder sends it nowhere: the case is answered at the provider, Payrudder submits no evidence.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id required | path | string |
Request body
| Field | Type | Description |
|---|---|---|
note required | string |
Example
{
"note": "string"
}Responses
| Status | Meaning | Body |
|---|---|---|
201 | Created | DisputeEvent |
400 | Error envelope | Error |
404 | Error envelope | Error |
503 | Error envelope | Error |
Example response
{
"id": "string",
"action": "note",
"create_time": "2026-11-03T10:15:00Z"
}curl
curl -X POST https://YOUR-API-ADDRESS/v1/disputes/<id>/notes \
-H "Authorization: Bearer $PAYRUDDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"note":"string"}'PUT /v1/disputes/{id}/handled #
Mark a dispute as handled in Payrudder, or lift the mark
Your own mark: it says you have dealt with the case (answered it at the provider, accepted it, refunded it). It changes nothing at the provider, in the payment ledger, or in what was announced (payment.disputed). Setting what is already set is not an error and writes nothing. Recorded in the audit log. The answer is the case as it stands.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id required | path | string |
Request body
| Field | Type | Description |
|---|---|---|
handled required | boolean |
Example
{
"handled": false
}Responses
| Status | Meaning | Body |
|---|---|---|
200 | OK | Dispute |
400 | Error envelope | Error |
404 | Error envelope | Error |
503 | Error envelope | Error |
Example response
{
"id": "string",
"provider": "stripe",
"dispute_id": "string",
"payment_ref": "string",
"amount_minor": "string",
"currency": "string",
"outcome": "open",
"formal": false,
"provider_status": "string",
"opened_time": "2026-11-03T10:15:00Z",
"handled": false,
"note_count": 1
}curl
curl -X PUT https://YOUR-API-ADDRESS/v1/disputes/<id>/handled \
-H "Authorization: Bearer $PAYRUDDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"handled":false}'Models
AddDisputeNoteRequest
| Field | Type | Description |
|---|---|---|
note required | string |
Dispute
| Field | Type | Description |
|---|---|---|
id required | string | Payrudder's id of the case |
provider required | string | |
dispute_id required | string | The provider's reference of the case (Stripe's du_..., Paddle's cb_ or cbw_ and the transaction) |
payment_ref required | string | The payment that is disputed, as the provider calls it (a Stripe PaymentIntent id, a Paddle transaction id) |
invoice_id | string · uuid | The invoice of that payment; absent for a payment Payrudder did not make |
amount_minor required | string · int64 | The disputed amount |
currency required | string | |
outcome required | open | won | lost | |
formal required | boolean | A chargeback proper, which takes the money back; false is an inquiry or a warning ahead of one |
provider_status required | string | The provider's own word (Stripe's needs_response, under_review, won, lost, warning_closed ...) |
reason | string | The cardholder's reason in the provider's words (Stripe's fraudulent, product_not_received ...); absent when the provider does not say |
evidence_due_time | string · date-time | When your evidence is due; absent when the provider does not say |
opened_time required | string · date-time | |
closed_time | string · date-time | Absent while the case is open |
fee_minor | string · int64 | What the provider took for the case, when a notification said (in `fee_currency`, which is the currency the provider settles in and can differ from `currency`). It is also a row of the payment ledger of its own. Stripe's is read from the balance transactions of the dispute and Paddle's from the chargeback fee of the payout totals; UNVERIFIED against a live account. Absent when no notification named a fee |
fee_currency | string | The currency of `fee_minor` |
handled required | boolean | Your own mark that you dealt with the case (`PUT /v1/disputes/{id}/handled`). It changes nothing at the provider |
handled_time | string · date-time | Absent when the case is not marked |
handled_by | string | Who marked it; absent when it is not marked, for a viewer of the account, and for an API key that holds no audit:read (the read_only and billing roles) |
note_count required | integer · int64 | How many notes you wrote (`GET /v1/disputes/{id}/history`) |
DisputeEvent
| Field | Type | Description |
|---|---|---|
id required | string | |
action required | note | handled | unhandled | A note, the mark that the case was handled, or that mark lifted |
note | string | The text of a note; absent for a mark |
actor | string | Who: the person's address, or the API key as `api_key:<id>`; absent for a viewer of the account |
create_time required | string · date-time |
Error
| Field | Type | Description |
|---|---|---|
error required | object |
ListDisputeEventsResponse
| Field | Type | Description |
|---|---|---|
events required | array of DisputeEvent |
ListDisputesResponse
| Field | Type | Description |
|---|---|---|
disputes required | array of Dispute |
SetDisputeHandledRequest
| Field | Type | Description |
|---|---|---|
handled required | boolean |