Embed a wallet in your product
GoHub Wallet gives your users a Malaysian e-money wallet inside your own app. You keep your brand, your screens and your user accounts. We hold the money, the ledger and the licence.
That last part shapes everything else in these docs. GoHubPay is the e-money issuer, so the obligation to identify the customer is ours, not yours. You send us who someone is; we verify them, we decide whether they pass, and we answer to the regulator for that decision. It is why signup has more steps than you might expect, and why you cannot mark your own users as verified.
Your integration has two halves
Both are yours. The difference is which part of your system makes the call, and therefore which credential it carries.
| Your backend | Your app | |
|---|---|---|
| Credential | machine token (client_credentials) | the wallet holder's own token |
| Does | registers customers, posts transactions, reads the ledger | shows a balance, tops up, withdraws |
Every operation page says which token it takes. Your users only hold one if you mint it for them — see Two tokens, one integration and How the integration works before you build.
Base URL
Sandbox https://api-wallet.dev.gohubpay.com.my/api/v1/wallet
Production https://api-wallet.gohubpay.com.my/api/v1/wallet
Every request carries Authorization: Bearer <jwt> and X-Tenant-Code: <your code>. Every
endpoint that moves money additionally carries Idempotency-Key: <uuid> — not every mutation does,
and the difference matters when you write your retry logic. See The contract
before you write any code — it covers idempotency, money handling and errors, and getting those
wrong is expensive to unpick later.
Your first call
Confirm your credentials and tenant code resolve:
curl https://api-wallet.dev.gohubpay.com.my/api/v1/wallet/tenants/code/ACME_RIDES \
-H "Authorization: Bearer $TOKEN"
A 200 with your tenant's name and status means you are ready.
The journey
Build in this order. Each chapter ends where the next begins.
- Signup — tell us who your user is, and prove their contact details
- Open the wallet — create it, read its balance and fund buckets
- Payment — move money in and out with a double-entry ledger behind it
- Ledger — reconcile against your own books
- Top-up — take money in through the payment gateway
- Money out — withdrawals, and what stands behind them today
Before that, spend five minutes on How the integration works. It is short, and it explains the one decision that shapes the rest: whether your users get a wallet session of their own.
What is not built yet
We would rather you read this here than discover it in an error response.
| Status | |
|---|---|
| Email contact verification | Live |
| SMS contact verification | Not built — the API accepts SMS and returns 501. Blocked on MCMC sender-ID registration, which has external lead time |
| KYC evidence capture, offline adjudication | Live |
| Automated eKYC (document + liveness) | Designed, not built — see eKYC onboarding |
| Outbound webhooks to your endpoint | Designed, not built — poll instead; see Top-up |
| Customer authorisation on money-out (OTP or step-up) | Designed, not built. A delegated token can authorise a payout today with no customer involvement — see Money out |
Operations that are partially implemented say so on their own reference page, on the exact field that behaves differently. If you find something in the API reference that this table does not cover and that does not behave as documented, tell us — that is a documentation bug and we treat it as one.