Ishmam Abid
Write to me

Backend engineer. Founder, Revnio. Software Engineer III at Fin. Dhaka.

I build the systems money moves through.

Ledgers, vendor routing, event layers and the APIs around them, designed and built end to end. At Fin, a platform that moves billions a year across more than thirty countries, I architected the event layer and wrote the routing engine. At Revnio, the company I founded, I build the whole stack myself.

What follows is a walkthrough. Follow one example payment, two hundred dollars from a sender in New York to a recipient in Sylhet, through a modern money-movement stack. Every stop is a system I designed or built. Nothing actually moves.

Start the walkthroughOr read the record

Demo
demo_01K7Q2M8…SYL
From
A sender, New York
To
A recipient, Sylhet
Amount
USD 200.00
Status
initiated
A route from New York to Dhaka, then on to Sylhet New York Dhaka Sylhet

New YorkSylhet

Hop 1 of 7verifiedUSD 200.00

Who is sending, and who gets it.

The problem: before a cent moves, both ends have to be checked, and "sort of verified" is not a state a payment system can act on. At Fin I built the customer, beneficiary and virtual account APIs for this, including the v2 rebuild of customers, each with an explicit state machine and webhooks. A customer is in exactly one state, and every service hears when that changes.

The bug I'm fondest of catching: a beneficiary in Mexico was accepted with a UK sort code. The value was well formed, just for the wrong country, and because it matched no Mexican account on file, duplicate detection waved it through. Now the validator knows which fields a country can have before it looks for duplicates.

Beneficiary ben_4e…MX, before and after the fix
country      MXname         Rosa M.- sort_code    40-30-21   accepted+ sort_code    40-30-21   rejected, not an MX field+ clabe        required   18 digits, bank and branchstate        pending → verified

Hop 2 of 7sent onceUSD 200.00

The same payment, sent twice.

The problem: phones retry, gateways time out and resend, people tap twice. The second copy of a payment has to be caught at the door, not found in reconciliation on Friday and unwound by hand.

What I built for it at Fin: idempotency on both paths. An Idempotency-Key on every REST write, and dedupe on the Kafka consumers, so a replayed event is a no-op rather than a second two hundred dollars. Same key, same body: the original response comes back. Same key, different body: 409, and nothing moves.

Three requests, one transfer
POST /v1/transfers   key 9d0c…b41e  200.00 USD        → 201 CreatedPOST /v1/transfers   key 9d0c…b41e, 0.8 s later  200.00 USD        → 200 OK, replayedPOST /v1/transfers   key 9d0c…b41e  250.00 USD        → 409 Conflict, body changedmoved              200.00 USD, once

Hop 3 of 7routedUSD 200.00

Which rail, which vendor.

The problem: a payment into Bangladesh can travel a few ways, through a licensed payout partner, a bank rail, or a stablecoin leg into a local off-ramp. Fin is a platform that moves money across more than thirty licensed countries and forty currencies, over SWIFT, Fedwire, FedNow, RTP, SEPA, local banks, e-wallets, Solana and Ethereum, with most payments settling in under an hour. Something has to decide which door each one goes through.

What I built for it: the vendor routing engine, of which I'm the sole author. A Go service on Echo, Postgres and Redis, hexagonal inside. Vendors declare what they can do as data: which corridors, which counterparty types, which currencies. Adding a vendor, or a whole country, is a config change, not a release. It's one of three production services at Fin that are mine alone, with an event-driven notification service and a multi-agent code pipeline.

Routing decision, corridor US to BD
corridor      US → BD        200.00 USDcounterparty  individual, bank, BDTvendor A      BD, bank, BDT    capable, quotedvendor B      BD, wallet, BDT  capable, slowervendor C      no BD corridor   skippedchosen        vendor A, from data not code

Hop 4 of 7in flightUSD 200.00

Every state change, told once, to everyone.

The problem: before the event layer, services asked each other "is it done yet?" on a timer, and people reconciled by hand whatever the timers missed. What I built for it: the Kafka event layer at Fin for live money movement, which I architected. Payments orchestration, the ramp engine, the ledger and the web3 services all speak through it. When a payment changes state, each of them hears it once, in order.

The events share one Protobuf schema for the whole company, which I own. Go and TypeScript are published from a single source, so the ledger and the dashboard can never disagree about what "settled" looks like.

topic transfers.v1, partition 3
4181  transfer.initiated4182  beneficiary.verified4183  transfer.routed        vendor A4184  ledger.posted          3f9a…c21e4185  payout.submitted4186  payout.settledheard by  ramp ✓ ledger ✓ web3 ✓ notify ✓

Hop 5 of 7postedUSD 200.00

Written down, in two columns, forever.

The problem: a payment system is only as trustworthy as its books, and most books can be edited. This is the part I care about most, so I built my own. Revnio Payments, codename Valhalla, is payments infrastructure for businesses and platforms, in development and built solo in Go, Postgres and Temporal. At its centre is a double-entry, append-only ledger. Every movement is a debit and a credit that sum to zero. Nothing is ever edited. If something is wrong, you post a reversal that points at what it reverses, and both stay on the books. Each entry carries the hash of the one before it, so a quiet change to history breaks the chain.

Around the ledger: KYC, user-controlled USDC wallets, on- and off-ramps designed to run through licensed partners, vendor failover that only happens before funds move, treasury, and three dashboards in five languages. I validated it end to end through those dashboards against simulated vendors. It is not live, and it moves nobody's money today.

Ledger posting, example fee
AccountDebitCredit
sender:wallet:USD200.00
vendor_a:in_transit:USD198.00
house:fees:USD2.00
sums to200.00200.00
hash3f9a…c21e after 7b02…e8d4

Hop 6 of 7settledUSD 200.00

Taka, through a licensed partner.

The problem: the last leg, where dollars become taka, is the one a platform must not improvise. In Valhalla it is designed to run only through a licensed partner in Bangladesh. The platform holds no funds itself; it orchestrates, records and reconciles. The partner's settlement arrives as a webhook, which is verified, deduped and stored raw before anything acts on it, and the ledger posts the payout against the in-transit account so the books still sum to zero.

Why I care about this leg: I grew up in Bangladesh. Money sent home keeps a lot of families going, and every hop on the way takes a cut, a flat fee and then a margin hidden in the rate. I want the infrastructure underneath that to be correct and cheap to run. That is the problem Revnio Payments is built for, starting with the United States to Bangladesh corridor, then Nigeria and Kenya.

Settlement webhook, handled and posted
webhook    payout.settled      vendor A
signature  valid     seen once, stored raw
posting    in_transit:USD        −198.00
posting    partner_payout:BDT   24,057.00
rate       121.50, example
reconcile  matched, partner statement line 41

Hop 7 of 7if it failsUSD 200.00

When it doesn't land.

The problem: sometimes a payment fails. A card expires, a bank bounces, a webhook arrives twice. For subscription businesses this is a slow leak: revenue that was agreed to and never collected.

What I built for it: Revnio Recovery, the SaaS I founded, live at getrevnio.com. It helps subscription businesses recover failed card payments. It connects to their Stripe, Paddle or Chargebee, retries with timing that follows the decline code, sends recovery emails, and runs win-back for subscribers who churned. Recovered money settles in the business's own account. Revnio never holds it and never sees a card number.

One failed invoice, recovered
invoice   in_7f3…   49.00 USD   declinedreason    insufficient_fundsretry 1   +3 d   by decline code     failedemail     "Your card didn't go through"retry 2   +4 d                       paidrecovered                  49.00 USD

Delivereddemo completeBDT 24,057

It lands in Sylhet.

That is the walkthrough: one example payment, seven systems, and nothing actually moved. The point of all of it is that the person at the end never has to think about sort codes, partitions or hash chains.

What I want to build next is the version of this stack a small team can run correctly: books that cannot be quietly edited, routing that is configuration, failure that recovers itself.

If you're building payment infrastructure, write to me.

Founders, teams hiring for payments infrastructure, investors, and anyone with an opinion about the Bangladesh corridor. I read everything.

[email protected]