If you work with Pix at a fintech, one thing is certain: sooner or later you'll have to deal with fraud. And the bar the Central Bank sets for that just went up. In August 2025 the MED 2.0 rules came out (starting with Resolution BCB nΒΊ 493), the new version of Pix's Special Refund Mechanism β optional to adopt from Nov 23, 2025 and with a mandatory rollout scheduled for 2026.
In this article I want to explain, in a simple and technical way, what the MED entities are, the fields that matter in each one and how the flow works end to end β with a focus on whoever is going to write the code.
π§© First: what MED is (and why it exists)
MED (Mecanismo Especial de DevoluΓ§Γ£o β Special Refund Mechanism) is a regulatory obligation from the Central Bank for every Pix participant β banks, payment institutions, fintechs, anyone who does Pix.
The idea is simple: when fraud or an operational failure happens, there must be a standardized and auditable path to return the victim's money. Without MED, each institution would solve it its own way (or not at all).
Important: MED is not for commercial disputes, buyer's remorse, or "I sent a Pix to the wrong person because I wasn't paying attention." It's for:
- Scam / fraud (phishing, social engineering, coercion)
- Account takeover
- Fraudulent access to channels
- Institution's operational error (duplicate Pix, wrong amount from a system failure)
π‘ Rule of thumb: MED = proven fraud or an error by the institution. It's not a "cancel my Pix" channel.
π What changes in MED 2.0
MED 1.0 had an Achilles' heel: it only blocked and refunded at the first receiving account of the fraudulent Pix. So the scammer pulled the classic move β received the money and scattered it in a cascade across many accounts in seconds. By the time the block arrived, the money had already evaporated. According to the BCB, in 2025 only 9.3% of the disputed amount was recovered on average.
MED 2.0 tackles exactly that: it now traces the money's path beyond the first account. The big highlights:
- Multi-layer tracing. DICT follows the money through the transaction graph and picks the transactions most likely to be on the drain path.
- Targeted blocking. The amount is blocked at each node of the path β only what matters, not the whole account (more on this below).
- Refund in its own name. The receiver's institution debits the mule account and refunds the victim directly, appearing as the payer on the statement.
- Digital self-service. The harmed customer triggers the process from the app.
- Standardized deadlines and UX (Timing Manual and Minimum UX Requirements).
π§± The MED entities (and how they connect)
Before diving in, the most important thing is to understand the end-to-end flow. It's what gives meaning to each entity:
- The harmed customer contacts their PSP, which opens a Funds Recovery (
FundsRecovery). This is the starting point. -
DICT traces the transactions from the root transaction and sends Infraction Reports (
InfractionReport) to the PSPs of the accounts along the money's path. - Each receiving PSP blocks the balance (only the indicated amount) and analyzes the Infraction Report.
- Once the infractions are analyzed, the paying PSP triggers the start of the Refund Requests β and the money goes back to the victim, layer by layer.
- Along the way, fraud markers are recorded in DICT, feeding prevention.
So there are four entities. Understand these four and you understand MED:
| Entity | Base endpoint | Role in the flow |
|---|---|---|
| Funds Recovery | /funds-recoveries/ |
Opens the case. The harmed customer starts it; it traces and orchestrates everything (the 2.0 highlight). |
| Infraction Report | /infraction-reports/ |
What each PSP in the chain receives. Triggers the block and the analysis. |
| Refund Request | /refunds/ |
Executes the refund of the money to the victim, layer by layer. |
| Fraud Marker | (automatic on agreement) | Flags receivers as fraudsters in DICT, feeding prevention. |
Let's go through them one by one, in the order they appear in the flow.
πΈοΈ Funds Recovery (FundsRecovery)
This is the big novelty of MED 2.0 β and where everything begins. When the customer is a fraud victim, the paying PSP opens a Funds Recovery (POST /funds-recoveries/). From there, DICT traces the money and orchestrates blocks and refunds.
The stages (this is where the "several statuses" live)
Funds Recovery isn't a single step β it moves through stages with their own statuses, and your backend needs to react to each transition. Today the flow is fully automated: DICT does the tracing, prioritization and dispatch of the Infraction Reports with no manual step from the PSP.
| Status | Stage |
|---|---|
CREATED |
Funds Recovery created over the root transaction |
TRACKED |
Transaction tracking graph created |
AWAITING_ANALYSIS |
Infraction Reports generated; receiving PSPs analyzing (up to 7 days) |
ANALYSED |
Infraction Reports analyzed and closed; the paying PSP can trigger the refund |
After ANALYSED comes the refund (requests run sequentially) and, at the end, DICT signals completion through the FUNDS_RECOVERY_COMPLETED event.
Tracking graph parameters
Parameters that bound the graph tracing (applied by DICT's algorithm):
| Parameter | What it controls |
|---|---|
MinTransactionAmount |
Minimum amount of each transaction considered |
MaxTransactions |
Maximum number of transactions in the graph |
HopWindow |
Time window between money entering and leaving an account |
MaxHops |
Maximum graph depth (how many layers to go down) |
Main endpoints
| Method + route | What it does |
|---|---|
POST /funds-recoveries/ |
Create a Funds Recovery |
GET /funds-recoveries/{id} |
Query a Funds Recovery |
POST /funds-recoveries/{id}/tracking-graph |
Create a tracking graph |
GET /funds-recoveries/{id}/tracking-graph |
Query the graph |
POST /funds-recoveries/{id}/block |
Request the transaction blocks |
GET /funds-recoveries/{id}/infraction-reports |
List the Infraction Reports of the recovery |
POST /funds-recoveries/{id}/refund |
Request a refund within the recovery |
GET /funds-recoveries/{id}/refunds |
List the refunds of the recovery |
POST /funds-recoveries/{id}/cancel |
Cancel the recovery |
π Don't sit there polling. DICT has an events endpoint (
GET /event-notifications) with two key signals for the recovery:
FUNDS_RECOVERY_ANALYSEDβ the Infraction Reports were analyzed; you evaluate the result and trigger (or not) the start of the refund.FUNDS_RECOVERY_COMPLETEDβ the refund phase is over; anyone still holding blocked funds can release them (if there's no other basis to keep the block).
π’ Infraction Report (InfractionReport) β the block
If Funds Recovery is the customer pulling the trigger, the Infraction Report is what lands on the PSPs of the accounts along the money's path. Each prioritized transaction generates an Infraction Report for the PSP of that node, which then blocks the balance and analyzes the case.
Main fields
| Field | What it is |
|---|---|
TransactionId |
EndToEndId of the suspicious transaction (e.g., E999990101234...) |
InfractionType |
Type: FRAUD, REFUND_REQUEST, REFUND_CANCELLED
|
FundsRecoveryId |
(MED 2.0) links the report to the Funds Recovery |
InfractionAmount |
(MED 2.0) the amount that must be blocked from that transaction |
InfractionData.DebitedParticipant / CreditedParticipant
|
ISPBs of the payer and the receiver |
InfractionData.ReportedBy |
DEBITED_PARTICIPANT or CREDITED_PARTICIPANT
|
InfractionData.TransactionDate |
Transaction date-time |
InfractionData.InfractingAccountData |
Branch + account involved at the node |
TransactionDepth |
(latest) position of the transaction in the money-movement chain β how far it is from the initial fraud (DICT Manual v8.5) |
Status |
OPEN, ACKNOWLEDGED, CLOSED, CANCELLED
|
AnalysisResult |
AGREED or DISAGREED
|
The block: only the InfractionAmount, not the whole account
This is the part that causes the most bugs if you're not careful. What you block is not the account's entire balance, nor the full amount of the original transaction β it's exactly the InfractionAmount: the amount that node received and that needs to be held on that specific transaction.
Why? Because the money spreads out. A mule account may have received R$ 800 from one branch and R$ 200 from another; each Infraction Report carries the right amount to block on each transaction. Blocking too much holds the customer's legitimate money; blocking too little lets funds slip away. Block the InfractionAmount, no more, no less.
β±οΈ The receiving PSP has up to 7 days to analyze and close the report (
.../acknowledgeon receipt,.../closewithAGREED/DISAGREED). Every agreement generates a fraud marker for that receiver β even if they never end up receiving a refund request.
πΈ Refund Request (Refund) β bringing the money back
Once the Infraction Reports are analyzed (FUNDS_RECOVERY_ANALYSED event), the paying PSP triggers the start of the refund. From there DICT fires the Refund Requests sequentially, without you having to orchestrate them one by one.
The key point: each refund goes to the harmed customer, only for the missing amount
Here lies the biggest mindset shift of 2.0. Every refund request is destined to the harmed customer (the user of the paying PSP who opened the recovery), and the goal is to return the money wherever it is in the chain. Rules that show up on the test:
- The 1st request always goes to the receiver of the root transaction.
- The subsequent ones follow the priority defined in the blocking stage.
- Each PSP debits the mule account and refunds directly to the harmed customer, appearing as the payer on the statement.
- Only the missing amount is requested to complete the total β never the full initial amount again. BCB's own example: even with R$ 800 blocked at a node, if R$ 250 was already recovered, the refund is requested for the remaining R$ 750 only. The amounts are updated automatically with each new refund.
In other words: the system keeps "scraping" whatever it can from each account until the total is met, never refunding more than owed.
Main fields
| Field | What it is |
|---|---|
TransactionId |
Transaction being refunded |
RefundReason |
FRAUD, OPERATIONAL_FLAW, REFUND_CANCELLED
|
RefundAmount |
Requested amount β the remainder, not the full value |
FundsRecoveryId |
(MED 2.0) links the refund to the recovery |
RefundAccount |
(MED 2.0) destination account for the payment (the harmed customer's) |
MonitorAccount |
(MED 2.0) whether the account should be monitored for future blocks |
EffectiveRefundedAmount |
(MED 2.0) on closure, the amount actually refunded |
Status |
OPEN, CLOSED, CANCELLED
|
AnalysisResult |
TOTALLY_ACCEPTED, PARTIALLY_ACCEPTED, REJECTED
|
RefundRejectionReason |
NO_BALANCE, ACCOUNT_CLOSURE, CANNOT_REFUND, OTHER
|
π‘ Partial refund + monitoring is the nastiest real-world case. If the account doesn't have the full balance at the moment (
PARTIALLY_ACCEPTED/NO_BALANCE), you accept what you can, report theEffectiveRefundedAmountand, withMonitorAccounton, monitor the account to keep blocking and refunding in parts as money comes in. Model this from the start β it's not an exception, it's routine.
π© Fraud Marker (prevention)
MED isn't only about putting out fires β it feeds prevention.
When an Infraction Report is agreed (AGREED), the receiver is flagged as a fraudster in DICT, automatically. And there's an important 2.0 detail: all receivers of transactions with an agreed report get flagged β even the ones that never receive a refund request (e.g., a node that fell outside the continuous path of the graph).
These markers feed DICT's anti-fraud data (counters of settlements, reported frauds and confirmed frauds, by key, by owner and by account).
π― Where this becomes gold: query that anti-fraud data for the destination key/account before releasing a cash-out. A recent fraud signal? You hold, ask for a double-check or add friction. Preventing is far cheaper than running the whole recovery flow.
π The deadlines you CAN'T miss
A blown deadline in MED = money lost or a regulatory fine. Nail these into your scheduler (the definitive source is the Pix Timing Manual):
| Rule | Deadline |
|---|---|
| Maximum transaction age to open a case | 80 days after the Pix |
| Infraction Report analysis by the receiving PSP | up to 7 days |
| Start the refund after the reports are analyzed | up to 72 hours |
Strong recommendation: model each deadline as a scheduled job with alerts. Don't rely on someone watching a spreadsheet. A due SLA is a system event.
β When to use (and NOT use) MED
You can use it for:
- Proven scam/fraud
- Account takeover / coercion / fraudulent access
- The institution's own operational error
You can't use it for:
- Commercial disputes ("the product never arrived")
- Buyer's remorse
- A Pix sent to the wrong person by the payer's own mistake
- Disputes between good-faith third parties
π Wrapping up
MED 2.0 changes the game of fraud recovery on Pix: gone is the focus on a single account, in comes tracing the money's path, with targeted blocking and layer-by-layer refunds. For your fintech, the summary is:
- π§ The flow starts with the customer: they open the Funds Recovery, which traces and fires the Infraction Reports.
- π Block the
InfractionAmount, not the whole account β that's the detail that bites the most. - πΈ Each refund goes to the harmed customer and only for the missing amount β the goal is to bring the money back wherever it is.
- π Use events, not polling (
FUNDS_RECOVERY_ANALYSED,FUNDS_RECOVERY_COMPLETED). - π The source of truth is always the DICT API spec and the BCB rules β check the current version before coding.
Official sources (BCB)
- Pix rules β Central Bank of Brazil and Resolution BCB nΒΊ 493/2025
- Circuito Pix β MED 2.0, Day 1 and Day 2
- Refund procedures implementation guide (MED)
- DICT API β official repository
bacen/pix-dict-api
That's it! If you're implementing MED 2.0 at your fintech and hit a wall, drop a comment and let's talk it through. π






Top comments (0)