PIX Disputes (MED)
MED (Mecanismo Especial de Devolução) is the Central Bank of Brazil's mechanism for returning a PIX sent because of fraud or an operational flaw. A PIX dispute is a payer using it to contest a PIX they sent to one of your end users, as a deposit to your main account or one of your sub-accounts. Avenia records the dispute as a brazilianPixDispute, linked to the deposit's ticket, and notifies you with the DISPUTE webhook.
The dispute is then analyzed, and ends accepted (the disputed amount is returned to the payer), rejected or canceled. The endpoints below only read disputes: nothing about a dispute is changed through the API.
The brazilianPixDispute Object
{
"id": "0b0c9a52-6f1e-4f5e-9a3e-2d1b7c8e9f10",
"userId": "99b76c8d-8ab8-4c91-bb7a-aaf619874e23",
"ticketId": "b28e9ef2-0405-49cf-967a-579d84556924",
"ticketCreatedAt": "2026-11-08T14:03:00Z",
"endToEndId": "E00000000202611081403A1B2C3D4E5F",
"status": "CREATED",
"reason": "Reporte fraude: transação foi contestada formalmente pelo usuário pagador",
"disputedAmount": "150.00",
"createdAt": "2026-11-09T10:00:00Z",
"updatedAt": "2026-11-09T10:00:00Z"
}
| Field | Type | Description |
|---|---|---|
id | string | The dispute's ID. |
userId | string | The owner of the disputed deposit: the same value as its ticket's userId. |
ticketId | string | The ticket of the disputed PIX deposit. The payer and the PIX itself are on that ticket: see Payer and Payment Details. |
ticketCreatedAt | string | When the disputed deposit's ticket was created, in UTC (RFC 3339): that ticket's createdAt. A deposit paid to a BR code issued for its ticket has that ticket from when the code was issued, before the payment; a deposit to a PIX key or a static BR code gets its ticket when the payment arrives. |
endToEndId | string | The end-to-end ID of the disputed PIX. Its casing can differ from the ticket's brazilianFiatSenderInfo.endToEndId, so compare the two case-insensitively. |
status | string | CREATED, ACCEPTED, REJECTED or CANCELED. See Dispute Statuses. |
reason | string | Why the PIX is disputed, in full, as free text exactly as it was reported (usually in Portuguese). Empty when the dispute came without one. See Dispute Reason. |
disputedAmount | string | The amount contested, in BRL, as a decimal string. It can be lower than the amount of the PIX when the payer contests only part of it. |
createdAt | string | When Avenia received the dispute, in UTC (RFC 3339). It is the dispute's own date, not the deposit's: that is ticketCreatedAt. |
updatedAt | string | When its status, reason or amount last changed, in UTC (RFC 3339). |
subAccountId | string | Only in answers to subAccountId=*: the sub-account the dispute belongs to, or "" for the main account. Absent when the dispute belongs to a hidden sub-account or your fee account, or when its owner can't be resolved. See Main account, sub-account or whole account. |
Dispute Statuses
| Status | Description |
|---|---|
CREATED | The dispute is open and under analysis. |
ACCEPTED | The dispute was accepted: the disputed amount is returned to the payer. |
REJECTED | The dispute was refused: nothing is returned. |
CANCELED | The dispute was withdrawn before a decision. |
A dispute is CREATED while it is analyzed, then moves to one of the other three statuses. Each status sends its own webhook.
Dispute Reason
reason is the reason given for the dispute, in full and exactly as it was reported, for example Reporte fraude: transação foi contestada formalmente pelo usuário pagador. It is free text, not a fixed list of values. The first report of the dispute that carries a reason sets it, and it doesn't change after; until then it is empty.
List Disputes
Endpoint
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
subAccountId | string | No | Whose disputes to list: omit it for your main account, send a sub-account ID for that sub-account, or * for your whole account. See the table below. |
ticketId | string | No | Filter by the ticket of the disputed deposit. |
endToEndId | string | No | Filter by the end-to-end ID of the disputed PIX. Case-insensitive. |
createdAfter | int64 | No | Unix epoch timestamp in milliseconds (UTC). Returns disputes created on or after this instant (createdAt >= createdAfter). |
createdBefore | int64 | No | Unix epoch timestamp in milliseconds (UTC). Returns disputes created strictly before this instant (createdAt < createdBefore). |
cursor | string | No | The cursor of the previous page, to fetch the next one. |
createdAfter and createdBefore work as on Get All Tickets, and its note on time zones and timestamp formats applies here too.
The filters apply within the account subAccountId selects. To find the dispute of a sub-account's ticket, send that sub-account's ID or *.
Main account, sub-account or whole account
subAccountId works as on Get All Tickets:
subAccountId | Disputes returned |
|---|---|
| omitted | Your main account's. |
| a sub-account ID | That sub-account's. 403 if the sub-account is in this access's subaccount blacklist, 404 if it isn't one of your sub-accounts. |
* | Your whole account's: the main account and every sub-account. Each dispute also carries subAccountId, the sub-account it belongs to, or "" for the main account; it is absent for a hidden sub-account's or your fee account's dispute, or when the owner can't be resolved. An access with a subaccount blacklist gets 403. |
Request example
The whole account's disputes opened since November 1, 2026 (UTC):
curl -X GET "https://api.sandbox.avenia.io:10952/v2/account/disputes/brazilian/pix?subAccountId=*&createdAfter=1793491200000" \
-H "Authorization: Bearer eyJhdXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
Response
The disputes come newest first (by createdAt), up to 100 per page. When the response cursor is non-empty, pass it back as the cursor query parameter to fetch the next page, which can come back empty. An empty cursor means there are no more pages.
{
"brazilianPixDisputes": [
{
"id": "0b0c9a52-6f1e-4f5e-9a3e-2d1b7c8e9f10",
"userId": "99b76c8d-8ab8-4c91-bb7a-aaf619874e23",
"ticketId": "b28e9ef2-0405-49cf-967a-579d84556924",
"ticketCreatedAt": "2026-11-08T14:03:00Z",
"endToEndId": "E00000000202611081403A1B2C3D4E5F",
"status": "CREATED",
"reason": "Reporte fraude: transação foi contestada formalmente pelo usuário pagador",
"disputedAmount": "150.00",
"createdAt": "2026-11-09T10:00:00Z",
"updatedAt": "2026-11-09T10:00:00Z",
"subAccountId": ""
},
{
"id": "a8941958-3ea1-41bf-8138-eff10b344979",
"userId": "3ecdadec-ae45-4615-8204-1f3489367ab4",
"ticketId": "94ffa2f3-8041-45ef-a971-f911cb58b2fa",
"ticketCreatedAt": "2026-11-02T18:46:12Z",
"endToEndId": "E00000000202611021847F5E4D3C2B1A",
"status": "ACCEPTED",
"reason": "Reporte fraude: transação foi contestada formalmente pelo usuário pagador",
"disputedAmount": "40.00",
"createdAt": "2026-11-03T14:21:07Z",
"updatedAt": "2026-11-06T09:12:45Z",
"subAccountId": "c427520f-4613-4ba7-994c-04219448a687"
}
],
"cursor": ""
}
Without subAccountId=*, the disputes don't carry subAccountId.
Get a Dispute by ID
Endpoint
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
dispute-id | string | Yes | The dispute's id, in the path. |
subAccountId | string | No | The account the dispute belongs to, as in List Disputes. A sub-account's dispute read without it returns 404. With *, any dispute of your account is found, and the answer carries its subAccountId as in List Disputes. |
Request example
curl -X GET "https://api.sandbox.avenia.io:10952/v2/account/disputes/brazilian/pix/a8941958-3ea1-41bf-8138-eff10b344979?subAccountId=c427520f-4613-4ba7-994c-04219448a687" \
-H "Authorization: Bearer eyJhdXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
Response
The dispute, wrapped in a brazilianPixDispute object, with the same fields as each element of brazilianPixDisputes in List Disputes:
{
"brazilianPixDispute": {
"id": "a8941958-3ea1-41bf-8138-eff10b344979",
"userId": "3ecdadec-ae45-4615-8204-1f3489367ab4",
"ticketId": "94ffa2f3-8041-45ef-a971-f911cb58b2fa",
"ticketCreatedAt": "2026-11-02T18:46:12Z",
"endToEndId": "E00000000202611021847F5E4D3C2B1A",
"status": "ACCEPTED",
"reason": "Reporte fraude: transação foi contestada formalmente pelo usuário pagador",
"disputedAmount": "40.00",
"createdAt": "2026-11-03T14:21:07Z",
"updatedAt": "2026-11-06T09:12:45Z"
}
}
Get Dispute Rates
How much of your PIX deposits was disputed: of the PIX deposits whose tickets were created in a time window, how many got a dispute, and how much those disputes contest.
Endpoint
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
subAccountId | string | No | Whose deposits to count: omit it for your main account, send a sub-account ID for that sub-account, or * for your whole account, as in List Disputes. |
createdAfter | int64 | No | Unix epoch timestamp in milliseconds (UTC). Counts the PIX deposits whose ticket was created on or after this instant. |
createdBefore | int64 | No | Unix epoch timestamp in milliseconds (UTC). Counts the PIX deposits whose ticket was created strictly before this instant. |
Without createdAfter or createdBefore, that side of the window is open; with neither, the rates cover all your PIX deposits. A bound after 2299-12-31, or a createdAfter later than createdBefore, is refused with 400.
The window selects deposits, not disputes. A dispute counts in the window of its deposit, its ticketCreatedAt, however long after the deposit it was opened. The PIX deposits are counted by when they were received. For a deposit to a PIX key or a static BR code those are the same moment. A deposit paid to a BR code issued in advance can be counted in different windows on each side when the payment comes after the window's end, so the percentages are approximate at a window's edges. A recent window can still gain disputes later, since a payer can contest a PIX well after sending it.
Request example
The whole account's rates for the PIX deposits of October 2026 (UTC):
curl -X GET "https://api.sandbox.avenia.io:10952/v2/account/disputes/brazilian/pix/rates?subAccountId=*&createdAfter=1790812800000&createdBefore=1793491200000" \
-H "Authorization: Bearer eyJhdXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
Response
{
"brazilianPixDisputeRates": {
"pixInCount": 1200,
"pixInAmount": "120000.00",
"disputedCount": 3,
"disputedAmount": "450.00",
"disputedCountPercentage": "0.2500",
"disputedAmountPercentage": "0.3750"
}
}
| Field | Type | Description |
|---|---|---|
pixInCount | integer | The PIX deposits whose ticket was created in the window. |
pixInAmount | string | Their total, in BRL, as a decimal string. |
disputedCount | integer | How many of those deposits got a dispute, whatever its status. |
disputedAmount | string | The sum of those disputes' disputedAmount, in BRL. |
disputedCountPercentage | string or null | disputedCount as a percentage of pixInCount, with four decimals: "0.2500" is 0.25%. null when there were no PIX deposits in the window. |
disputedAmountPercentage | string or null | disputedAmount as a percentage of pixInAmount, with four decimals. null when there were no PIX deposits in the window. |
Payer and Payment Details
Apart from ticketCreatedAt, a dispute carries only its own data. The payer and the PIX itself are on the deposit's ticket: get it with Get Ticket by ID, using the dispute's ticketId and the same subAccountId you read the dispute with. For a dispute from a subAccountId=* answer, use the subAccountId it carries; "" is the main account, so send none. When it carries none, send subAccountId=*.
curl -X GET "https://api.sandbox.avenia.io:10952/v2/account/tickets/94ffa2f3-8041-45ef-a971-f911cb58b2fa?subAccountId=c427520f-4613-4ba7-994c-04219448a687" \
-H "Authorization: Bearer eyJhdXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
| What you need | Where it is on the ticket |
|---|---|
| The payer's name and tax ID | brazilianFiatSenderInfo.name and brazilianFiatSenderInfo.taxId |
| The payer's bank account | brazilianFiatSenderInfo.bankCode, branchCode, accountNumber and accountType |
| The amount of the PIX, in BRL | quote.inputAmount |
| The deposit's status and dates | status, createdAt (the dispute's ticketCreatedAt) and updatedAt |
The ticket's brazilianFiatSenderInfo.endToEndId is the dispute's endToEndId, possibly in a different case.
Errors
| Status | Message | When |
|---|---|---|
400 | InvalidFieldError: subAccountId is invalid | subAccountId is neither * nor a UUID. |
400 | InvalidFieldError: disputeId is invalid | Get a Dispute by ID: the dispute-id in the path is not a UUID. |
400 | InvalidFieldError: ticketId is invalid | List Disputes: ticketId is not a UUID. |
400 | InvalidFieldError: cursor is invalid | List Disputes: cursor can't be read. Send it back exactly as a previous page returned it, with the same filters. |
400 | InvalidFieldError: createdAfter is invalid | Get Dispute Rates: createdAfter is later than createdBefore, or after 2299-12-31. |
400 | InvalidFieldError: createdBefore is invalid | Get Dispute Rates: createdBefore is after 2299-12-31. |
403 | ForbiddenError | subAccountId=* was sent by an access with a subaccount blacklist, or subAccountId is in this access's blacklist. extraInfo says why. |
404 | NotFoundError: subAccountId not found | subAccountId does not belong to your account. |
404 | NotFoundError: dispute not found | Get a Dispute by ID: there is no dispute with this ID in the account you asked for. A sub-account's dispute read without subAccountId also returns 404. |
Webhook
Register your webhook with the DISPUTE subscription, or *, to receive BRAZILIAN-PIX-DISPUTE-CREATED when a dispute is opened on one of your deposits, and BRAZILIAN-PIX-DISPUTE-ACCEPTED, -REJECTED or -CANCELED when it is decided. A dispute opened before we have processed its deposit is sent once the deposit is processed. Each event carries the dispute in data.brazilianPixDispute, in the format above. The payload is in Webhook Events, and how to register a webhook in Webhook Management.