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.
Outcomes
What changed, and how we know
- 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
- 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
- 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.

