- Fintech
- Payments
- KYC
CrossBorda
Cross-border payouts for African corridors
- Role
- Lead Product Designer
- Timeline
- 2023, seven months
- Team
- Two engineers, one PM, me
- Platforms
- Web dashboard and customer portal
- Status
- Shipped, in production
- Outcome
- Support tickets about payment status dropped noticeably after the status rework. Directional
Directional: observed in practice, not instrumented
The problem
Cross-border payouts aren't one transaction, they're a chain of them, and every link can fail differently. A business had to onboard, get verified against rules that change by jurisdiction, add recipients, initiate payouts, then track them through states that could sit unchanged for two days without anything being wrong. The people doing this were finance and operations staff. They were being shown raw webhook state names and asked to work out what to do next.
What made it hard
- Compliance came first, not the user experience. Verification steps that people would rather skip were legally required, so the design had to make them feel purposeful instead of hiding them.
- Nobody using the product was technical. All the system complexity had to stop at the interface.
- "Pending" is a legitimate state that can last days. The design had to communicate patience without communicating breakage.
- The recipient model had to support both one-off and recurring payouts from launch, because rebuilding it later would have meant migrating live financial data.
Three decisions
With what I turned down, and what each one cost.
Decision 01
Verification gates moved to the point of need
- Chose
- Basic access at sign-up, with each verification requirement introduced at the moment the action requiring it is attempted.
- Rejected
- Collecting every identity document upfront in a single onboarding wizard, which is what the compliance team originally asked for.
- Why
- Front-loading the documents meant a business had to hand over its incorporation papers before seeing a single screen of the product. The drop-off happens before anyone has a reason to push through it. Tying each gate to the action it unlocks gives the requirement an obvious purpose.
- What it cost
- It's harder to build. Every gated action needs its own state, and the compliance team had to sign off on a flow they couldn't read top-to-bottom on one page.
Decision 02
Recipients became an entity, not a form
- Chose
- A recipient directory of saved, validated profiles that payouts reference.
- Rejected
- Entering recipient details per transaction, which was simpler and matched how the API already worked.
- Why
- Operations teams don't send one-off payments to strangers. They pay the same twenty suppliers every month. Re-entering an account number each time is both slow and the single most likely place for a costly typo.
- What it cost
- It forced a data model change mid-build and added a whole management surface — editing, archiving, and handling a recipient whose bank details change between payouts.
Decision 03
Status names describe what to do, not what happened
- Chose
- A translation layer mapping technical webhook states to operator language with an explicit next action. FAILED_RETRY became "Payment rejected. Check the reason and send again."
- Rejected
- Surfacing the underlying state names with tooltips explaining each one.
- Why
- A finance operator doesn't need to know the system's internal vocabulary. They need to know whether this is their problem and what to do about it. Tooltips put that answer one hover away from someone under time pressure.
- What it cost
- The mapping has to be maintained. Every new webhook event needs an operator-facing translation, and if that step gets skipped the untranslated state leaks through.