// reference build

Tapstub

Fintech — corporate cards & spend management

Tap the card. Catch the receipt.

Tapstub is a corporate card and spend-management app for the people who actually carry the card. The moment a card is swiped, an authorization push lands on the employee's phone, they snap the receipt in the notification, and the expense codes itself against policy before they've left the counter. Finance and line managers use the same app from the other side: a queue of coded expenses cleared with a single biometric approval that is cryptographically signed on device.

A BuildspaceLabs reference build. We designed Tapstub in-house to show how we approach native mobile — it is not a client engagement, and every name, record and figure inside these screens is fictional demo data.

  • Push on every swipe
  • Receipt OCR
  • Face ID approval
  • Freeze the card
Tapstub shown on three phones — Wallet, Transaction, receipt and approval, Wallet, Material 3 — on a fintech brand backdrop
// platforms

Two native designs, one shared core

Tapstub is designed twice — once in the iOS idiom and once in Material 3 — on top of a shared domain core, rather than one layout wrapped twice for both stores. The frameworks below are the stack each side is specced against.

iOS

Swift · SwiftUI2 screens in this set

Android

Kotlin · Jetpack Compose · Material 31 screen in this set
// screens

The screens

3 surfaces from the build — 2 in the iOS idiom and 1 redesigned in Material 3 on Android. Everything inside the frames is fictional demo data.

Tapstub — the Wallet screen, running on iOS
01iOS

Wallet

The employee's home: card hero with masked PAN and reveal hint, quick actions, the monthly limit at 61% of $3,000, a live "swiped 12 seconds ago" banner for the $18.40 Meridian Coffee Roasters authorization, and the day's transaction feed with per-row coding status and a row held open on its trailing "Not mine — dispute" swipe action.

Tapstub — the Transaction, receipt and approval screen, running on iOS
02iOS

Transaction, receipt and approval

Opened from the swipe push: the amount hero, the captured receipt with its on-device extraction reconciled against the authorization, the auto-coded category, GL code and cost centre, the policy checks — under a Face ID confirmation sheet clearing three expenses worth $717.00 with a Secure Enclave signature.

Tapstub — the Wallet, Material 3 screen, running on Android
03Android

Wallet, Material 3

The same screen and the same records rebuilt in Android idioms: M3 top app bar, elevated card at 28dp, a horizontally scrollable assist-chip row, a wavy linear progress indicator, segmented buttons, the same list item held open on its trailing dispute action, an extended FAB for scanning, a navigation bar with a pill active indicator, and an undoable snackbar.

// why native

Why it has to be native

The case for building this twice rather than wrapping a web app. Each one is designed around an operating-system capability a browser either cannot reach or cannot be trusted to hold.

Sub-two-second authorization push

The alert is fired straight off the issuer-processor webhook using the APNs Time Sensitive interruption level and a matching Android high-priority notification channel, so it breaks through Focus and Do Not Disturb while the customer is still at the terminal. A web push has no interruption level and no delivery guarantee at that latency.

Wallet provisioning

Virtual cards are pushed into the device wallet through PassKit In-App Provisioning and the Google Pay Push Provisioning API, including in-app issuer terms presentment. Neither API is reachable from a browser.

On-device receipt capture

VisionKit's document camera with Vision text recognition on iOS, and the ML Kit Document Scanner on Android, do live quad edge detection, perspective correction and line-item extraction (subtotal, tax, tip, total) against the raw camera buffer. The frame buffer never leaves the handset.

Hardware-backed approval

Face ID bound to a Secure Enclave key, and BiometricPrompt bound to a StrongBox-backed Keystore key, each return a signed approval payload rather than a boolean. That signature is what makes the approval non-repudiable in an audit; a browser can only tell you a user "passed" a check.

Live Activity and Dynamic Island

A pending authorization stays on the Lock Screen and in the Dynamic Island while the amount moves from Authorized to Settled, mirrored by an Android ongoing notification whose inline Snap receipt action opens the camera without a cold app launch.

Offline-first receipt queue

Receipts captured on a plane or in a basement car park encrypt to local storage and upload later via BGProcessingTaskRequest and WorkManager, with coarse location used to match the merchant and flag geo mismatches. Background execution of that kind has no web equivalent.

// stack

The stack it is designed for

The target architecture this build is specced against, chosen per constraint rather than per habit — the stack shifts with the problem.

  • iOS: Swift 6 with strict concurrency, SwiftUI plus the Observation framework, ActivityKit for the pending-authorization Live Activity
  • Android: Kotlin 2.x with Jetpack Compose and Material 3 Expressive, edge-to-edge with predictive back
  • Kotlin Multiplatform shared domain layer — policy engine, auto-categorization rules, FX conversion and the sync state machine — compiled to both a Swift package and an AAR so a policy change ships once
  • On-device receipt OCR: VisionKit document camera plus Vision text recognition on iOS, ML Kit Document Scanner and Text Recognition v2 on Android, behind a shared line-item parser
  • Biometrics: LocalAuthentication with a Secure Enclave key on iOS and AndroidX BiometricPrompt with a StrongBox-backed Keystore key on Android, both signing an approval payload rather than returning a boolean
  • Wallet provisioning: PassKit In-App Provisioning and the Google Pay Push Provisioning API against an issuer-processor sandbox
  • Local persistence and offline queue: SQLDelight with SQLCipher, background sync via BGProcessingTask and WorkManager, transport over gRPC with protobuf
  • Backend edge: a Kotlin/Ktor service ingesting card-network authorization webhooks and fanning out to APNs and FCM, with signed-approval verification and an append-only audit log
// next

Working on something shaped like this?

Tapstub is a reference build, so there is nothing to buy on this page. If your team has a problem that needs this kind of depth — offline for a full shift, real sensors, work that has to happen with the screen off — tell us about it and we will tell you honestly whether we are the right people to build it.