Skip to main content

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​

JSON
{
"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"
}
FieldTypeDescription
idstringThe dispute's ID.
userIdstringThe owner of the disputed deposit: the same value as its ticket's userId.
ticketIdstringThe ticket of the disputed PIX deposit. The payer and the PIX itself are on that ticket: see Payer and Payment Details.
ticketCreatedAtstringWhen 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.
endToEndIdstringThe end-to-end ID of the disputed PIX. Its casing can differ from the ticket's brazilianFiatSenderInfo.endToEndId, so compare the two case-insensitively.
statusstringCREATED, ACCEPTED, REJECTED or CANCELED. See Dispute Statuses.
reasonstringWhy 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.
disputedAmountstringThe 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.
createdAtstringWhen Avenia received the dispute, in UTC (RFC 3339). It is the dispute's own date, not the deposit's: that is ticketCreatedAt.
updatedAtstringWhen its status, reason or amount last changed, in UTC (RFC 3339).
subAccountIdstringOnly 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​

StatusDescription
CREATEDThe dispute is open and under analysis.
ACCEPTEDThe dispute was accepted: the disputed amount is returned to the payer.
REJECTEDThe dispute was refused: nothing is returned.
CANCELEDThe 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​

GEThttps://api.sandbox.avenia.io:10952/v2/account/disputes/brazilian/pix

Query Parameters​

ParameterTypeRequiredDescription
subAccountIdstringNoWhose 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.
ticketIdstringNoFilter by the ticket of the disputed deposit.
endToEndIdstringNoFilter by the end-to-end ID of the disputed PIX. Case-insensitive.
createdAfterint64NoUnix epoch timestamp in milliseconds (UTC). Returns disputes created on or after this instant (createdAt >= createdAfter).
createdBeforeint64NoUnix epoch timestamp in milliseconds (UTC). Returns disputes created strictly before this instant (createdAt < createdBefore).
cursorstringNoThe 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:

subAccountIdDisputes returned
omittedYour main account's.
a sub-account IDThat 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
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.

JSON
{
"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​

GEThttps://api.sandbox.avenia.io:10952/v2/account/disputes/brazilian/pix/{dispute-id}

Parameters​

ParameterTypeRequiredDescription
dispute-idstringYesThe dispute's id, in the path.
subAccountIdstringNoThe 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
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:

JSON
{
"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​

GEThttps://api.sandbox.avenia.io:10952/v2/account/disputes/brazilian/pix/rates

Query Parameters​

ParameterTypeRequiredDescription
subAccountIdstringNoWhose 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.
createdAfterint64NoUnix epoch timestamp in milliseconds (UTC). Counts the PIX deposits whose ticket was created on or after this instant.
createdBeforeint64NoUnix 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
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​

JSON
{
"brazilianPixDisputeRates": {
"pixInCount": 1200,
"pixInAmount": "120000.00",
"disputedCount": 3,
"disputedAmount": "450.00",
"disputedCountPercentage": "0.2500",
"disputedAmountPercentage": "0.3750"
}
}
FieldTypeDescription
pixInCountintegerThe PIX deposits whose ticket was created in the window.
pixInAmountstringTheir total, in BRL, as a decimal string.
disputedCountintegerHow many of those deposits got a dispute, whatever its status.
disputedAmountstringThe sum of those disputes' disputedAmount, in BRL.
disputedCountPercentagestring or nulldisputedCount as a percentage of pixInCount, with four decimals: "0.2500" is 0.25%. null when there were no PIX deposits in the window.
disputedAmountPercentagestring or nulldisputedAmount 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
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 needWhere it is on the ticket
The payer's name and tax IDbrazilianFiatSenderInfo.name and brazilianFiatSenderInfo.taxId
The payer's bank accountbrazilianFiatSenderInfo.bankCode, branchCode, accountNumber and accountType
The amount of the PIX, in BRLquote.inputAmount
The deposit's status and datesstatus, createdAt (the dispute's ticketCreatedAt) and updatedAt

The ticket's brazilianFiatSenderInfo.endToEndId is the dispute's endToEndId, possibly in a different case.

Errors​

StatusMessageWhen
400InvalidFieldError: subAccountId is invalidsubAccountId is neither * nor a UUID.
400InvalidFieldError: disputeId is invalidGet a Dispute by ID: the dispute-id in the path is not a UUID.
400InvalidFieldError: ticketId is invalidList Disputes: ticketId is not a UUID.
400InvalidFieldError: cursor is invalidList Disputes: cursor can't be read. Send it back exactly as a previous page returned it, with the same filters.
400InvalidFieldError: createdAfter is invalidGet Dispute Rates: createdAfter is later than createdBefore, or after 2299-12-31.
400InvalidFieldError: createdBefore is invalidGet Dispute Rates: createdBefore is after 2299-12-31.
403ForbiddenErrorsubAccountId=* was sent by an access with a subaccount blacklist, or subAccountId is in this access's blacklist. extraInfo says why.
404NotFoundError: subAccountId not foundsubAccountId does not belong to your account.
404NotFoundError: dispute not foundGet 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.