Skip to content
Hardcount
Run it locally
Pre-1.0 · one maintainer · Stripe and cards only · no SDKs (client libraries) yet · no production users yet. Docs describe v0.9.1 (29 Oct 2026) · What’s new →

List the card disputes on an invoice

GET
/v1/invoices/{id}/disputes
curl --request GET \
--url 'http://localhost:8080/v1/invoices/example/disputes?limit=50&offset=0' \
--header 'Authorization: Bearer <token>'

Returns the card disputes (chargebacks) Stripe reported against the invoice’s payments, oldest first. An invoice without any returns an empty list. Hardcount records them from Stripe’s charge.dispute.* webhook events, which must be turned on for the Stripe webhook endpoint. Hardcount never changes the invoice because of a dispute: respond to it in Stripe, and if it is lost, record the loss with a credit note or a write-off in your books.

id
required
string
limit
integer
default: 50 >= 1 <= 100

Rows per page, from 1 to 100. Default 50. Any other value, or one that is not a whole number, is a 422 with param: limit.

offset
integer
0

Rows to skip, 0 or more. Default 0. A negative value, or one that is not a whole number, is a 422 with param: offset.

The invoice’s disputes.

Media typeapplication/json
object
data
required
Array<object>

A card dispute (chargeback) Stripe reported against one of the invoice’s payments, recorded from Stripe’s charge.dispute.created, .updated and .closed webhook events. It holds the dispute as the newest of those events showed it, whatever order they arrived in. Hardcount records and reports a dispute, and nothing else: the invoice stays paid and no money moves.

object
id
required
string
invoice_id
required
string
stripe_dispute_id
required
string
stripe_charge_id
string
stripe_payment_intent_id
required

The disputed payment.

string
status
required

Stripe’s dispute status, as Stripe sends it. The warning_ statuses are an inquiry, which comes before a chargeback or instead of one. won, lost, warning_closed and prevented are closed.

string
Allowed values: warning_needs_response warning_under_review warning_closed needs_response under_review won lost prevented
reason

The reason the cardholder gave, for example fraudulent.

string
amount_cents
required

The disputed amount. It can differ from the payment.

integer format: int64
currency
required
string
evidence_due_by

The deadline to respond in Stripe. Absent when Stripe gave none.

string format: date-time
opened_at
required

When Stripe opened the dispute.

string format: date-time
closed_at

When Stripe closed it. Absent while it is open.

string format: date-time
livemode
required
boolean
created_at
required
string format: date-time
updated_at
required
string format: date-time
total
required

How many rows match the request’s filters, on every page, not only this one. The audit log and the customer list’s search and name or email sort say where they stop counting.

integer

Example

{
"data": [
{
"id": "hc_dsp_6f1c0a7e9b2d4c8e1a3b5d7f",
"stripe_dispute_id": "du_1MtJUT2eZvKYlo2CNaw2HvEv",
"status": "warning_needs_response",
"currency": "USD"
}
]
}

Invoice not found.

Media typeapplication/json
object
error
object
type

One of invalid_request_error, authentication_error, rate_limit_error or api_error. Every error the API answers has this shape, including an unknown path (404, code route_not_found) and a method the path does not take (405, code method_not_allowed, with an Allow header). The few exceptions are listed in docs/api-surface.md.

string
code
string
message
string
request_id
string
param

The request field the error is about. Sent only when the error names one. A request body may hold only the fields its operation lists, spelled and cased as listed: any other field, or one the server sets (such as id), is refused with 422 and param naming it. An operation with no request body lists no fields: send no body, {} or null. The Stripe and Postmark webhooks and the LiteLLM callback take their sender’s body as it comes.

string

Example

{
"error": {
"type": "invalid_request_error"
}
}

limit or offset is out of range or not a whole number, or the request sends the removed after cursor (param names it)

Media typeapplication/json
object
error
object
type

One of invalid_request_error, authentication_error, rate_limit_error or api_error. Every error the API answers has this shape, including an unknown path (404, code route_not_found) and a method the path does not take (405, code method_not_allowed, with an Allow header). The few exceptions are listed in docs/api-surface.md.

string
code
string
message
string
request_id
string
param

The request field the error is about. Sent only when the error names one. A request body may hold only the fields its operation lists, spelled and cased as listed: any other field, or one the server sets (such as id), is refused with 422 and param naming it. An operation with no request body lists no fields: send no body, {} or null. The Stripe and Postmark webhooks and the LiteLLM callback take their sender’s body as it comes.

string

Example

{
"error": {
"type": "invalid_request_error"
}
}