Bayarcash SDK ecosystem
One payment API, ten official client libraries — eight languages plus Laravel and Django integrations, kept honest by a single shared contract.
Bayarcash is a Malaysian payment gateway — FPX, DuitNow and friends. Merchants integrate it from whatever stack they already run, which in practice means every stack: agencies on Laravel, startups on Node, a bank integration team on .NET, a Flutter app that needs payment status on the device.
My job was to make the answer to “do you have an SDK for X?” always be yes — and to make all ten answers behave identically. The same API also grew a product surface I work on: Bayarcash Link for no-code payment links, and the merchant onboarding and sign-up campaign portals that bring merchants in.
The problem
A payment SDK is a thin wrapper around HTTP, which is exactly why it goes wrong. Ten
hand-written wrappers drift: one library names a field order_ref, another orderRef;
one retries on timeout, another doesn’t; one validates the callback checksum, another
trusts the network. For payments, drift isn’t a style problem — a missed checksum
validation is money.
The approach
- One API contract, ten expressions of it. Every SDK implements the same operations against the same request/response shapes — create a payment intent, query a transaction, verify a callback. The contract lives with the API, not in any one SDK’s head.
- Checksum verification is not optional. Every SDK ships the callback-verification path as a first-class function, because the alternative is merchants skipping it.
- Idiomatic on the surface, identical underneath. The Rust SDK feels like Rust and the Ruby SDK feels like Ruby, but a developer moving between them recognises every concept. Framework packages for Laravel and Django go one step further and wire configuration, service registration and callbacks into the framework’s own conventions.
What it taught me
Maintaining ten parallel libraries is a lesson in API design economics: every awkward corner of an API gets paid for ten times. It pushed changes upstream — if something was annoying to wrap consistently in ten languages, that was usually the API’s fault, not the SDKs’.