Core Concepts
Every call in the Wallet API rests on these six concepts. Reading this first makes the field names on later pages self-explanatory.
Program
A program is your wallet product. It defines currencies, branding, fee and limit policy, and which integrations are enabled. One tenant can run several programs (for example "Employee Card" and "Customer Wallet" with different policies).
{
"name": "Customer Wallet",
"loopMode": "CLOSED_LOOP",
"currencies": ["TRY"],
"branding": {
"displayName": "Acme Wallet",
"logoUrl": "https://cdn.acme.com/logo.svg",
"primaryColor": "#0F172A",
"supportEmail": "[email protected]"
}
}If you omit programId and your tenant has exactly one program, the platform resolves it. With more than one program, programId is required.
List your programs with GET /wallet/programs/me. That endpoint is read-only; programs are created and edited from the merchant panel.
End user
An end user is the wallet holder. There are two types:
accountType | Who |
|---|---|
PERSONAL | Your individual customer — tops up, sends, pays |
BUSINESS | A business inside the program — collects payments, subject to commission |
End users are deduplicated by phone number within a program. The same phone never creates a second user in the same program.
{
"programId": "5b9e2f3a-7c41-4d8e-a6f2-9e1b3c4d5f60",
"accountType": "PERSONAL",
"phone": "+905321234567",
"externalCustomerId": "crm-88213",
"displayName": "A. Yilmaz"
}externalCustomerId is the identifier in your own system; GET /wallet/end-users/by-external/:extId lets you reach the user by your id, so you never have to store ours.
The phone number is the deduplication key. Binding a wallet to an unverified phone means handing the wallet to whoever takes over that number. The portal flow enforces OTP verification; on the s2s surface, verification is your responsibility.
Wallet and account
These are two layers, and conflating them is the most common integration mistake:
- Wallet — the user's container inside a program. It has a name and there can be several ("Spending", "Savings").
- Wallet account — the balance of a wallet in one currency. Money always sits in an account.
All money-movement endpoints take an account id (sourceWalletAccountId, creditWalletAccountId), never a wallet id.
There is no balance column; the balance is a projection of the ledger. GET /wallet/end-users/:id/balances returns the current ledger-derived balance.
Operation
Every money-moving call produces an operation — a first-class object with a record, a status, fees and audit history. Operation types:
| Type | What |
|---|---|
TOPUP_CARD | Card top-up |
TOPUP_TRANSFER | Bank transfer top-up |
TOPUP_AGENT | Cash top-up via an agent |
TOPUP_REFUND | Refund of a card top-up |
W2W_TRANSFER | Wallet-to-wallet transfer |
W2IBAN_WITHDRAW | Transfer to a third party's IBAN |
WITHDRAW_BANK | Withdrawal to the user's own IBAN |
PAYMENT_BUY | Wallet payment (individual → business) |
There are also cash-out, card authorization, crypto and refund types. For the status machine see Overview; for listing and receipts see Operations.
W2IBAN_WITHDRAW and WITHDRAW_BANK share the same bank integration but are distinct types: one is a transfer to a third party, the other a withdrawal to the user's own account. Reporting, limit buckets and fee schedules count them separately.
Suspense funds
If money arrives on your account but cannot be attributed to a user, it is not lost — it goes to suspense. From the panel it is either matched (bound to a deposit instruction) or returned to the sender. This is the safety net that stops "money arrived, but whose?" from being silently credited.
Idempotency
Idempotency-Key is mandatory on money-moving calls and on calls that create records (end users, wallets, accounts, QR codes, bulk payouts …); the full list is on the Authentication page.
-H "Idempotency-Key: order-9988-topup-1"A second request with the same key does not repeat the operation; it returns the first request's result. Derive the key from your business meaning (order number + attempt) rather than generating a fresh UUID on each retry — otherwise a retry after a network error becomes a second money movement.
quote → execute → complete
Most outbound operations take three steps:
| Step | What happens | Money moves? |
|---|---|---|
POST /…/quote | Returns fee, tax, limit eligibility | No |
POST /… | Opens the operation, reserves funds, sends OTP if needed | Reserved |
POST /…/:id/complete | Confirms with integrityHash + nonce (+ otpCode) | Yes |
integrityHash proves the amount quoted is the amount settled. If what you showed the user differs from what would leave the account, the request is rejected — which makes hiding a fee from the user structurally impossible.
nonce is single-use. If a complete call fails, do not retry with the same nonce — query the operation and decide based on its status.
Next
- Authentication — signed requests and tokens
- Quickstart — your first end-to-end flow