Context
The checkout platform handles checkout, conversion, payments, orders and authentication for multiple merchants and storefronts. It is a system where the architecture already existed and where several teams and clients consume the same APIs, which means compatibility is part of the job, not an afterthought.
Problem
- Features have to land without breaking existing consumers of the API.
- Checkout is the revenue path: correct behaviour matters more than elegant code, and failures are visible immediately.
- Data crosses boundaries: orders, payments and authentication live in different services, communicated over REST and gRPC.
- An interface change in the back end implies coordinated change in the applications that consume it.
My responsibility
Evolving existing features and endpoints, creating new endpoints when the feature required it (following the architectural patterns already established by the team), consuming those APIs in the front end, and writing tests.
What I worked on
- Checkout and conversion flows in the web applications, including international purchase UI fixes.
- Payments and orders: features around the order lifecycle and their representations in the product surface.
- Authentication flows used by the applications consuming the platform.
- Endpoints: evolution of existing ones and creation of new ones, then consuming them from the front end.
- Data correctness: moving the front end onto monetary fields expressed in cents, so amounts stop depending on floating-point representation.
- Observability and tests: Sentry for production issues, automated tests as the safety net for changes in a revenue path.
How I approached it
Before writing anything I read the other endpoints in the same service and followed their conventions (naming, error shape, validation) because consistency is what makes an API learnable. For changes to contracts, I treated existing consumers as constraints: extend rather than redefine, and keep the previous behaviour valid. Because the same change usually spans back end and front end, I worked on both sides of the contract instead of handing off a shape nobody had validated. And for anything touching money or order state, tests came before the change shipped.
Challenges
- Keeping compatibility while evolving a shared API used by multiple applications.
- Reasoning across REST and gRPC boundaries within one feature.
- Debugging in a system where the failure path has business consequences, using logs, traces through the observability stack, and error tracking.
- Fixing UI problems whose root cause sat in the API contract: the visible bug was rarely where the fix belonged.
Decisions and trade-offs
- Follow the existing patterns instead of introducing a new one. Trade-off: occasionally a pattern is not the best fit, but a consistent codebase for the next engineer beat a locally elegant solution.
- Extend contracts additively. Trade-off: the API surface grows and carries legacy fields; the alternative was coordinating breaking changes across clients.
- Money handled as integer cents end to end. Trade-off: a coordinated migration across the front end and a moment where two representations exist in the wild, in exchange for removing a class of rounding bugs permanently.
Result
Features delivered on a revenue-critical path, and a front end that stopped carrying a class of monetary-representation bugs. The scale around it: over R$3 billion transacted per year on the platform.
What I learned
- In a shared API, compatibility is a feature with its own design cost.
- Reading existing code before writing new code is the cheapest architecture review available.
- Understanding the business consequence of a failure changes how much testing is enough.