Skip to content
All Case Studies
Case Study

Building Mobile Payment Flows with Explicit State

Kotlin · Jetpack Compose · Retrofit · Coroutines · Material 3

Executive Summary

Built wallet features for card reloads, QR payments, and bill-pay. The Retrofit API layer maps failures into repository results while the payment view model exposes bounded processing and terminal states.

The Problem

  • Payment flows were overly coupled to banking onboarding.
  • Asynchronous payment intent states need to remain visible while the client polls for a terminal result.

Architecture & Approach

  • 1
    Feature-based packages (screens, view models, DI)
  • 2
    Retrofit interfaces with clean DTOs, interceptors, consistent error envelopes
  • 3
    Compose UI with unified components (cards, inputs, buttons) and a11y labels
  • 4
    PaymentFlowViewModel with bounded exponential polling and explicit creating, processing, succeeded, failed, and canceled states

Challenges & Trade-offs

Duplicate payment-intent creation → send an Idempotency-Key from the Android repository

Long-running requests → poll with backoff capped at ten seconds and a two-minute client timeout

UI complexity → keep API/repository failures separate from the view-model state machine

Outcomes & Results

  • The client models payment creation, processing, success, failure, cancellation, and timeout as distinct states
  • Repository methods expose API/network failures instead of treating unsuccessful responses as completed payments
  • External-provider settlement and production payment outcomes remain unverified