root@construct:~/projects/yooga$
<-- back to /projects

Yooga Payments & SmartPOS

Payments for 2,100+ merchants on a 7,000+ restaurant platform

KotlinAndroidStone SDKJavaQuarkusKafka

>Context

Yooga is a restaurant operating system with 7,000+ restaurants. Payments is the area that takes the money from sales and pays it out to the merchant: 2,100+ merchants were integrated into the payments solution.

I joined in September 2023 as Senior Software Engineer on Payments. I built the core flows for merchant transactions, billing cycles and financial reconciliation while the domain moved from a monolith to services. In May 2025 I was promoted to Tech Lead and led the 5-engineer team until August 2026: architecture, the roadmap with product, support and commercial, code review standards and onboarding of every new joiner.

The bug class that mattered most was the ordinary one: the same webhook delivered twice, or a customer tapping pay again. Much of the work was making every transaction safe to run twice, across two providers.

I also architected and built SmartPOS, which takes Yooga into the payment terminal: the app runs Yooga on the device and integrates with the terminal's own payments through the Stone SDK.

>High-level design

Payments ran on Java 21 and Quarkus services, in containers on Kubernetes, on AWS. The services used MySQL and MongoDB. Observability was New Relic, Prometheus/Grafana and OpenTelemetry.

A charge leaves a Yooga channel, enters the payments service with an idempotency key and reaches the provider through pluggable drivers: Pix directly with Itaú; cards, Apple Pay and Google Pay through Tuna and Pagar.me, with anti-fraud. Status comes back through signed webhooks from Tuna and Pagar.me, validated before any state change and safe to arrive twice. SmartPOS is a Kotlin/Android app on the terminal itself: it uses Yooga's APIs and takes payment through the Stone SDK.

Off the charge path, the work is asynchronous. Scheduled jobs build withdrawal batches, compute the payout date around holidays and weekends, pay out by Pix through Itaú, run reconciliation and post a daily report to Slack. The Kafka event layer carries orders and status between the microservices and the delivery connectors (iFood and partners), with SASL/SSL, ordering, replay and idempotent consumption. Changes reached production behind feature toggles, with gradual rollout.

Hover or focus a piece: it lights up with its links.
Payment terminalYooga backendexternal servicesPayments · AWS + Kubernetes2 SmartPOS1 Yooga channels4 Yooga services6 Payments service9 Drivers and webhooks3 Stone SDK11 Tuna7 MySQL and MongoDB13 Itaú5 Kafka12 Pagar.me8 Delivery connectors14 iFood and partners10 Settlement and recon
14 pieces13 links4 areas

Components

  • Payments service :: A Java 21/Quarkus service on Kubernetes in AWS that records each charge with an idempotency key and calls the provider through the right driver.
  • Provider drivers :: Pix directly with Itaú, and cards, Apple Pay and Google Pay through Tuna and Pagar.me, with anti-fraud that collects session data at the start of the transaction and uses both providers' engines.
  • Webhook handlers :: Validate Tuna's and Pagar.me's signature before processing and treat redelivery as the normal case, with no duplicate charge or inconsistent state.
  • Automated settlement :: Scheduled jobs build withdrawal batches per merchant, compute the date around holidays and weekends, pay out by Pix through Itaú, reconcile and post the daily report to Slack.
  • Self-service onboarding :: Merchant sign-up with CPF/CNPJ validation, bank account verification and a direct integration with Tuna's merchant API.
  • Kafka event layer :: Order and status events between the microservices and the delivery connectors (iFood and partners), with SASL/SSL, ordering, replay and idempotent consumption.
  • SmartPOS :: A Kotlin/Android app with Clean Architecture and Jetpack Compose that runs Yooga on Sunmi, Positivo and Tectoy terminals, uses Yooga's APIs and takes payment through the Stone SDK.

>Trade-offs

Treat the second delivery as the normal case: an idempotency key on every transaction, and a signed webhook verified before any state change.

Alternative rejected: Trust the provider to deliver each webhook once and the customer to tap pay once.

Why: The bug that mattered most was the same webhook arriving twice or a customer tapping pay again. Across both providers, idempotency is what removed duplicate charges, race conditions and inconsistent payment states.

Pluggable provider drivers inside the payments service.

Alternative rejected: Put every payment method on a single provider.

Why: Pix, 98% of transaction volume, went directly through Itaú, while cards went through Tuna and Pagar.me, all behind the same pluggable driver architecture.

Idempotent consumption with replay on the Kafka layer.

Alternative rejected: Assume the broker delivers each event exactly once.

Why: In an event-driven system any step can run twice. With handlers designed for the second delivery from day one, a broker incident never produced a duplicate or a lost order.

>Highlights

  • >US$70M+ processed across 6M+ transactions for 2,100+ merchants
  • >Pix through a direct Itaú integration: 98% of transaction volume
  • >800+ automated tests covering payment flows and webhooks
  • >SmartPOS on terminals from 3 manufacturers: Sunmi, Positivo and Tectoy
  • >Led a team of 5 engineers for 1 year and 4 months
  • >Claude Code and Cursor as core tools: team delivery speed tripled
Yooga Payments & SmartPOS | The Broad Way | Kinho.dev