Vertigem

Making offline receipt capture reliable in Vertigem's expense platform

Receipts captured outside mobile coverage were dropped without anyone noticing, on shared handsets that killed the app mid-upload. Our engineers worked inside Vertigem's squads on the capture path and the reconciliation queue.

Industry
FinTech
Published

Outcomes

What changed, and how we know

  1. 01

    Captures lost when a handset left coverage

    From silent loss to deferred delivery

    Before
    Dropped silently, discovered only when a receipt never appeared
    After
    Held on the device and delivered when signal returned
    Window
    Measured over the eight weeks after the outbox shipped on both platforms
    Method
    Client telemetry comparing captures recorded on the device against ledger entries accepted, per handset
  2. 02

    Duplicated captures reaching the reconciliation queue

    From a daily correction to an exception

    Before
    A recurring share of every day's queue, corrected by hand
    After
    Rare enough that finance stopped tracking them as a category
    Window
    Measured over the same eight weeks
    Method
    Counts taken from Vertigem's own reconciliation reports, compared week on week against the same report before rollout
  3. 03

    Screens to resolve a duplicated capture

    From a manual adjustment to a single decision

    Before
    Four screens and a manual ledger adjustment
    After
    One screen, with the capture history alongside the decision
    Window
    At rollout of the reconciliation queue
    Method
    The resolution flow walked end to end in the shipped queue and in the version it replaced, counting the screens a finance approver passes through

Challenge

Vertigem sells expense management to businesses whose staff work away from an office. Receipts are captured on a phone in the field and reconciled by finance teams in a web back-office.

Captures made outside coverage were dropped silently, and a field worker learned a receipt was missing only when it failed to appear days later. Where a retry did survive the handset's background limits, it arrived as a second entry the queue could not tell apart from a genuine one.

Constraints

  • Field handsets are low-end shared Android devices with strict background execution limits, and the app was routinely killed mid-upload
  • Crews hand the same handset on between shifts, so nothing in the capture path could assume a device stays with one person
  • Receipt images carry cardholder and personal data and could not sit unencrypted on a device between capture and sync
  • Vertigem's own architecture group owned every design decision; we proposed and they ruled

Approach

Team
Two senior mobile engineers and one senior front-end engineer, embedded in two of Vertigem's existing squads. No RiseForge lead — their engineering managers ran the work.
Engagement model
Staff augmentation
Duration
Nine months, with engineers rolling on and off at four weeks' notice

We worked Vertigem's board, their two-week cadence and their definition of done, and every design went through their architecture review before it went anywhere near code.

Architecture

Every capture lands immediately in an encrypted on-device outbox that survives the app being killed, then drains when signal returns rather than at the moment it was taken. Each entry carries a key minted on the device at capture, so a delivery retried hours later resolves to the same ledger entry, and the web queue shows finance one item with its capture history beside it.

  • Kotlin
  • Swift
  • TypeScript
  • React
  • Node.js
  • PostgreSQL
  • SQLite

Key decisions

An encrypted on-device outbox rather than an in-memory retry queue
Background execution limits on the handsets the field crews carry killed the app mid-upload, and anything held only in memory went with it. Durability had to survive the process, not just the request.
A delivery key minted on the device at capture rather than at upload
An outbox that drains hours later will retry by design, and by then the upload may be the third attempt. The shutter is the only moment that is unambiguously one receipt.
Conflict resolution in the web queue, not on the phone
Vertigem's call, and the right one. Field staff cannot judge whether two similar captures are one receipt twice or two receipts for the same amount; finance can, and they are already the approvers of record.

What staff augmentation gave Vertigem, and what it did not

Our engineers sat in two of Vertigem's squads, on their board, under their definition of done. The outbox and the delivery key were our proposal, but the decision to adopt them was taken by their principal engineer in their own architecture review, and the decision to resolve conflicts in the web queue rather than on the phone was theirs outright — we argued the other way for a fortnight and we were wrong.

That division is the model rather than a caveat about it. We are accountable for the calibre of the engineering: the tests, the reviews, whether the sync layer is legible to the people who own it now that we have gone. We are not accountable for the outcome, because we did not set the roadmap, the priority order or the release schedule. Anyone offering to guarantee an outcome under staff augmentation is describing a different contract.

It also bounds what we could see. Our squads owned the capture path and the queue; a change inside the ledger service needed a sponsor in a team we were not placed in, so we raised it and waited like everyone else.

What we would do differently

Our engineers took their first ticket in week two, which felt like good value and was not. We built duplicate suppression against the sync logs before anyone had sat with a finance team, and it took two iterations to learn that their expensive problem was deciding which of two captures to keep, not counting how many arrived. We would now write a slower, billed ramp into the placement and say plainly why it is the cheaper option.

Similar problem?

If you are working on something like this in fintech, tell us what you are measuring today and we will tell you whether we can move it.