Federico KotekProduct Designer

Billing banks straight from their contracts

Pomelo is fintech infrastructure for Latin America: banks and fintechs use it to issue cards and run account programs. I joined in 2021 as a senior designer on the partner dashboards and stayed almost four years, the last year and a half leading the UX team and still designing billing and automations myself.

This case is about billing. Pomelo charges every client for the cards it issues and the transactions it processes, each on its own contract, currency and tax rules. When I picked it up, all of that was done by hand. Someone in finance read each contract PDF and typed the numbers into a spreadsheet, for 77 clients in five countries, and only 22% of invoices went out on time.

The billing screens, redrawn in 2026 from the original screens, with placeholder data
Role
Senior product designer, then leading the UX team, five people and about seven at one point
When
2023 – 2024, within 2021 – 2025 at Pomelo
With
Product, engineering and finance
Scope
Billing for banks and fintechs across four tax regimes
The decision
Start with sending invoices from one place, and build toward entering each contract once and deriving everything from it
What changed
On-time invoices 22% → 95% · unpaid bills $6M → $3M · no external billing teams

Prices nobody could query, quantities nobody had yet

Prices lived in private contracts that no system could read. Quantities were supposed to come from a data lake that hadn’t been built yet. And invoices went out under four regimes: electronic invoicing in Argentina, NF-e in Brazil, CFDI in Mexico, and government pre-authorisation in Colombia. The tax side was for engineering and finance to build, and I wasn’t the one solving it.

Billing is price times quantity, and both were unknown: prices sat in private contracts no system could read, quantities in a data lake not yet built. The invoice then goes out under one of four tax regimes: electronic invoicing in Argentina, NF-e in Brazil, CFDI in Mexico, government pre-authorisation in Colombia. × one of four tax regimes Pricein private contractsno system could read Quantityfrom a data lake thathadn’t been built yet The invoiceamount unknown ARelectronicinvoicing BRNF-e MXCFDI COgovernmentpre-authorisation both inputsunknown “an undisclosed amountfor an unknown numberof items”
Billing is price times quantity

Starting with the part we could build

The contracts were digital, but nothing stored what was in them in a form the data and engineering teams could use. No system had the price, so no system could multiply it by a quantity, and calculating invoices automatically was blocked until other teams digitised the contracts. Billing covered three products, Cards, Identity and digital accounts, and Cards was by far the most complex: eleven concepts, each of which could change by client, country, contract and card brand.

So we started with the one step every invoice has in common, which is sending it. At the time all of them went out by hand, one by one, four to seven for each client, each email carrying a detailed summary of that client’s operation. Nothing stopped an invoice for one client from going to another, and that had already happened once. Payments were followed by hand too, in one mega-file where the team marked who had paid what (its real name was Global Tracker). Nobody measured whether a client had received what we sent. Starting there also meant building the place where the contract details would live, such as which day to send and to which addresses, which the later calculation would need anyway. The first users were Pomelo’s own billing team, who were doing all of it by hand.

In the backoffice we drew one screen to upload an invoice and describe it, with its number, currency, period and the concepts it bills, and one to set, for each client, the day its invoices go out and the addresses they go to.

A new invoice, redrawn in 2026 from the original screen, with placeholder data, a generic invoice, and added lists and confirmation
How a client’s invoices are sent, redrawn in 2026 from the original wireframe, with placeholder data and wording, and an added modal, Off state and confirmation

The contract as the source of truth

We decided to enter each contract once and derive everything else from it: invoices, reminders, balances. I split the work into two tracks that ran in parallel. A backoffice, where finance sets up a contract and the system generates the invoices, and a dashboard where partners see every invoice and pay it.

One contract, entered once by finance in the backoffice, with its prices, currency and tax rules. Invoices, reminders and balances on the partner dashboard are all derived from it. Backoffice Partner dashboard entered once, by finance derived Contractprices · currency · tax rules Invoicesevery billing cycle Reminders Balances the only thinganyone types all derivedfrom it
One contract, entered once

We drew the backoffice from the client down, since everything billed belongs to one: a client has its data, its contracts and the products it is billed for.

The client list and a client’s detail, redrawn in 2026 from the original wireframes, with placeholder data and wording, and an added search result, copy confirmation and menu

Under a client sit a price addendum and the contract itself. The addendum holds the prices and when each is billed, and the contract is one long form with a block for each price rule.

The price addendum, redrawn in 2026 from the original wireframe, with placeholder data and wording, marked edits, an added list and confirmation
The contract entry, redrawn in 2026 from the original screen, with placeholder data and added lists

We wireframed together in Excalidraw with the whole team on a call. Before drawing any screens, I wrote down every state an invoice can be in: pending, reported, paid, overdue, partially paid, or reversed with a credit note. The partner dashboard is built around those states, so a partner can always tell where a bill stands without having to ask anyone.

Invoice states: issued as pending; reporting a payment moves it to reported, and a due date passing moves it to overdue, from where a reported payment also leads to reported. Confirmed, it is paid; if only part is paid it is partially paid until the rest is reported. A credit note reverses a paid invoice. Issued Report payment Due date passes Report payment Confirmed Part of it paid Report the rest Credit note Pending Overdue Reported Partially paid Paid Reversed late can stillend up paid the happy pathruns straight down a partial paymentloops back untilthe rest is in
Six states an invoice can be in, and what moves it between them
Excalidraw wireframes of the billing flows, drawn in a remote session with the team
Early wireframes, drawn in Excalidraw with the team, client names covered
Specification of every invoice state: pending, reported, paid, overdue, partial, with the due-date and multi-currency rules
Every state an invoice can be in, written down before the screens

The partner dashboard that came out of them lists every invoice, with a drawer that shows the PDF and a pay action, and lets a partner report a payment with the bank details and, for Brazil, a PIX code.

The partner dashboard’s invoices, redrawn in 2026 from the original screen, with placeholder data
The invoices in two tabs, issued and still to issue, redrawn in 2026 from the original wireframe, with placeholder data, an added search and a day going by

We also drew the invoices with a second tab for the ones not yet issued, with what has accrued toward each and the days left before it goes out. Paying is a short form, and so is reporting a problem with an invoice, which opens with the invoice’s own data already on it.

Reporting a payment, redrawn in 2026 from the original screen, with placeholder data and wording, and an added receipt and confirmation
Reporting a problem with an invoice, redrawn in 2026 from the original wireframe, with placeholder data and wording, and an added attachment and confirmation

Behind the partner’s view is the backoffice, where finance works. When an invoice that has already gone out needs correcting, they raise a credit note against the original, line by line, and the invoice goes to the state the spec says it should.

A credit note in the backoffice, redrawn in 2026 from the original screen, with placeholder data and added reasons and confirmation

Six small things from the dashboard and the backoffice, close up and set moving, with placeholder data: where an invoice stands, a row’s actions, sending an idea, copying a number, which concepts are billed and a tour of the page.

Where an invoice stands
A row’s actions
An idea, sent
A number, copied
Concepts, on and off
A tour, a step at a time

Three A/B tests, and what each moved

We ran three A/B tests along the way. A direct payment reminder got 20% more payments before the due date than one that explained the context. A PIX code on Brazilian invoices, which clients there had asked for so they could scan a QR and pay directly, made no difference in the test. We shipped it anyway, and as far as I know it stayed. PIX carries a lot of weight in Brazil today. And taking the amount out of the notification email raised platform DAU by 8%.

Three A/B tests. A direct payment reminder beat a contextual one by 20% more payments before the due date. A PIX code on Brazilian invoices made no difference. Hiding the amount in the notification email raised platform DAU by 8%, and I argued against shipping it. +20% payments before the due date Payment reminder Contextual Direct no difference PIX code on Brazilian invoices Without With +8% platform DAU Amount in the notification email Shown Hidden less context,more payments a clientasked forthis one it won, and I arguedagainst shipping it:it hid informationto drive traffic
Three A/B tests, and what each one moved

That last one won, and I argued against it. It meant hiding the amount to get people into the platform. We tried several variants of that email, and I don’t remember which one stayed.

Matching payments was the bigger problem

Billing turned out to be a small part of something larger. It grew into collections, finance, reconciliation and payments, all built from nothing, and reconciling payments was the hardest of them. Pomelo had a banking licence, so we considered giving each client its own CBU to pay into. The limits on transfers to a CBU did not allow the amounts clients had to pay, so it was not an option. We threw away a lot of ideas like that one.

Leading the team while designing billing

Through this project I was also leading the UX team, and I had more or less started before the title said so. It was five people, about seven at one point. Leading it meant hiring, planning, estimating the workload and working out how many people it needed, while I kept designing billing and automations myself as a senior. A lot of that was above my pay grade at the time.

What I learned there is that culture and a healthy place to work are almost everything, and so is trusting the people on your team (I know it sounds like feng shui). We had a good time working together, and I still keep in touch with every one of them. I also think a design lead has to stay hands-on: one who can’t keep up with the tools, the systems and the problems the team works on, or decides not to, can’t lead it well.

What changed

Invoices delivered on time 22%→95% More than four times as many, on time
Error rate per invoice 6%→2% A third of the errors
External billing teams 4→0 None needed any more
Unpaid bills, USD 6M→3M Half as much owed

Looking back, the order is what I would keep: we started with the one step nobody else had to build first, sending the invoices, and the place we made for it, with each client’s send day and addresses, was built to hold what the calculation would need later. Collections, reconciliation and payments grew out of it, all from nothing.

Fintech-as-a-service Billing automation Backoffice + partner dashboard Led the UX team