Beyond the Payment API: Webhooks, Reconciliation and Idempotency (Lessons from Pix)

  • Newton Duarte
Integração PIX: O Difícil vem depois da API

Every time I start a Pix integration, I'm reminded of the same thing: the API is only a small part of the project.

(For readers outside Brazil: Pix is the country's instant-payment system, run by the Central Bank — account-to-account transfers that settle in seconds, 24/7, similar in spirit to India's UPI or the UK's Faster Payments. It's now the most-used way to pay in Brazil.)

Consuming the endpoint, creating a charge, receiving a payment — that's usually the smooth part. The real work begins when webhooks, reconciliation, refunds and all those scenarios no one remembers during planning come into play. And that's exactly where payment integrations blow past deadline or spring a surprise in production.

The lessons here apply to any modern payment integration; I'll use Pix as the concrete example, because it's where I run into these traps most often. In this article, I'll break down the three points I always validate before starting — and why each of them matters more than the API itself.

The API is only the beginning

A payment integration doesn't end when the payment is created. It lives in what happens next: the notification that arrives (or doesn't), the amount that has to reconcile at the end of the day, the customer who requests a refund, the call that arrives twice. Treating the API as the whole project is the mistake that delays most teams.

Let's get to the three points.

1. Treating Pix as just another payment method

It isn't. Pix has its own rules that cards and boletos (Brazilian bank slips) don't: a refund flow — including the Special Return Mechanism (MED) for fraud cases — settlement in seconds, 24/7 availability, and specific identifiers like txid and EndToEndId.

Anyone who treats Pix as "just another payment method" ends up discovering these differences in production, the hard way. The integration itself is usually the easy part; the challenge shows up with refunds, webhooks and the exception handling that is specific to this arrangement.

2. Leaving reconciliation for later

I've seen teams build the entire payment flow and only "remember" reconciliation once financial discrepancies started showing up in production. At that point, nobody is happy.

Reconciliation isn't a final step — it has to be a requirement from the start. In practice, it means cross-checking what your system recorded against the statement from the PSP or the bank, matching each transaction by a reliable identifier (the EndToEndId is a good candidate, since it identifies the transaction end to end). Without it, discrepancies pile up silently and only surface at close — when they have already become a financial problem.

A good reconciliation design accounts for: transactions that don't match, payments received with no corresponding order, partial and full refunds, and an exceptions dashboard that shows only what needs human attention.

3. Not treating duplicate requests as a normal scenario

This is the most underestimated point — and the one that most often causes phantom payments (duplicate charges and credits).

A few days ago, my business partner Cláudio Santos and I had an interesting conversation with a commercial partner about integration resilience and idempotency. At one point, I raised a question:

"How are you handling a possible duplicate call to your webhook?"

The answer was roughly:

"But why would you send the same information twice?"

And my answer was simple:

"The idea is precisely not to. But we work in IT... failures happen. There are timeouts, retries, network issues and recovery processes. The better prepared the integration is for these scenarios, the smaller the impact when they occur."

In distributed systems, we don't work on the assumption that everything will run perfectly all the time. We work so that, when something goes wrong, the system stays consistent.

What idempotency is (and why it protects your money)

Idempotency is the guarantee that processing the same message twice has the same effect as processing it once. Applied to payments: if the same webhook arrives twice, the customer isn't charged (or credited) twice.

In practice, you can handle it like this:

  • Use an idempotency key. In Pix, the EndToEndId works as a natural transaction identifier — record already-processed events by that key.
  • Deduplicate before processing. When a webhook arrives, check whether that event has already been handled. If it has, respond with success and don't repeat the effect.
  • Respond idempotently. The webhook sender expects a confirmation; if it doesn't get one (timeout), it retries. Your endpoint has to withstand that retry without duplicating anything.
  • Assume "at-least-once" delivery. Most webhook providers guarantee at-least-once, not exactly-once. In other words: duplication isn't a rare exception — it's expected behavior.

Timeouts happen. Retries happen. Webhooks can be delivered more than once. If the integration wasn't designed for these scenarios from the start, sooner or later some payment will spring a surprise.

Checklist: what to validate before integrating Pix

Before writing the first line of the integration, make sure you have clear answers to these points:

  • Webhooks: how you handle retries, delays and duplicate deliveries.
  • Idempotency: what your key is and where you record already-processed events.
  • Reconciliation: how, and how often, you cross-check your records against the PSP/bank statement.
  • Refunds: full and partial refund flows, and MED handling.
  • Security: validating the webhook's origin and protecting the data.
  • Observability: visibility to catch a small problem before it becomes an incident.

Frequently asked questions

Is integrating Pix hard?

The API part is usually simple. The complexity is in the surrounding scenarios: duplicate webhooks, reconciliation, refunds and exception handling. That's where projects fall behind.

What is idempotency in payments?

It's the guarantee that processing the same notification more than once doesn't produce a duplicate effect — for example, it doesn't credit the same Pix twice. It's essential because webhooks can be delivered more than once.

Why does Pix reconciliation matter?

Because it's what ensures that what your system recorded matches what was actually settled. Without reconciliation from the start, financial discrepancies only surface at close.

What is the EndToEndId in Pix?

It's the unique end-to-end identifier of a Pix transaction. It works both for reconciliation and as a natural idempotency key when handling webhooks.

Do you need to integrate Pix reliably?

If your operation depends on payments that can't fail, it's worth designing the integration for real-world scenarios from the start — instead of patching it later. Talk to T4tech and let's discuss your integration.