Wallet
Wallet lets you run program-scoped accounts under your own brand: your customers top up, send money to each other, pay you, pay by QR, and earn points and cashback. Balances live on a double-entry ledger; every movement produces an operation record and an audit trail.
All amounts are minor-unit integers carried as strings: "amount": "10050" means ₺100.50. There are no decimal or float amounts anywhere in the Wallet API.
Three surfaces
The same capability is exposed on three surfaces with different authority scopes. They are separate controllers — one endpoint is never shared across three identities.
| Surface | Caller | Path | Authentication | Endpoints |
|---|---|---|---|---|
| External API (s2s) | Your backend | /api/v1/wallet/* | Every request is Ed25519-signed — the signature is the identity; it is not exchanged for a Bearer | 60 |
| Portal / SDK | The end user's mobile/web app | /api/portal/v1/wallet/* | Publishable key → OTP → customer session (JWT) | 87 |
| Merchant panel | Your operations team | /api/panel/v1/wallet/* | Panel session (JWT) + RBAC + four-eyes | 186 |
Example: "list operations" exists on all three, but s2s returns the tenant's operations, the panel returns all of them (PII masked), and the portal returns only the session owner's own operations.
The surfaces are not interchangeable: 139 panel endpoints have no s2s counterpart, so you cannot build your own merchant panel with a signing key. Measured comparison: surface comparison matrix.
What you can build
| Capability | Description | Status |
|---|---|---|
| Program & branding | Your own wallet program: currencies, branding, fee and limit policy | ✅ |
| End users & accounts | Individual (PERSONAL) and business (BUSINESS) users, multi-currency accounts | ✅ |
| Card top-up | Top up by card — delegated to the payment stack, 3D Secure included | ✅ |
| Agent top-up | An agent takes cash and credits the customer from a float account | ✅ |
| Wallet-to-wallet transfer | Send by phone number or wallet number, OTP-confirmed | ✅ |
| Wallet payments | Customer → business payment, with commission and cashier reference | ✅ |
| QR | Generate, parse, collect and pay by QR | ✅ (closed loop) |
| Loyalty | Cashback campaigns, points, tiers and badges | ✅ |
| Limits & fees | KYC-tiered limit buckets, fee schedules and quotes | ✅ |
| Refund to wallet | Credit a card refund to the wallet instead of the card network | ✅ |
| Bank transfer top-up | Per-user deposit instructions, matched funds credited automatically | 🚧 |
| Bank withdrawal & IBAN transfer | Withdraw to the user's own IBAN, transfer to a third-party IBAN | 🚧 |
| Bulk payouts | Many payouts from a list, with maker-checker approval | 🚧 |
| Invoices & bill pay | In-wallet invoicing; biller inquiry and payment | 🚧 |
| ATM / QR cash-out | Cardless cash withdrawal code | 🚧 |
| Card issuing | Virtual/physical card bound to the wallet | 🚧 |
For 🚧 capabilities the API contract is complete and stable; running them in production requires a connected provider (bank integration, biller, ATM network, card issuer). See the Roadmap.
Operation lifecycle
Every call that moves money produces an operation. These are the exact status values you see in GET /wallet/operations/:id and in webhook payloads:
FAILED, REVERSED, EXPIRED) and the risk hold (HELD) are left out — they are all in the table below. The diagram makes one point: BANK_PROCESSING and AWAITING_RECON are the middle of the road, not the end of it.| Status | Meaning |
|---|---|
INITIALIZED | Operation opened, funds reserved, awaiting confirmation |
CHALLENGED | Waiting for OTP / step-up verification |
POSTING | Ledger entries being written |
COMPLETED | Done — reflected in the balance |
FAILED | Final failure; reserved funds released |
REVERSED | A completed operation was reversed (refund/undo) |
REVERSING | A reversal has started and awaits the ledger result; the system completes it automatically |
BANK_PROCESSING | In flight on the bank side |
AWAITING_RECON | Outcome uncertain — sent to reconciliation instead of being silently failed |
HELD | Held by a risk decision; funds blocked and unusable |
EXPIRED | Timed out before confirmation; reservation released |
AWAITING_RECON, HELD and REVERSING are not terminal. Do not treat them as failures and retry — query with the same Idempotency-Key or wait for the webhook.
The money-movement pattern: quote → execute → complete
Most outbound operations take three steps, so the user sees the fee before the debit and the confirmation is verifiable:
/quote— returns fee, tax, limit eligibility and (where relevant) which integration will be used. No money moves./…(execute) — opens the operation, reserves funds, triggers OTP if required. ReturnsintegrityHash+nonce./…/:id/complete— confirm with theintegrityHashandnoncefrom step 2, plusotpCodewhen an OTP was issued.
integrityHash guarantees the amount/fee shown in step 2 is the same as the one settled in step 3. If what the user saw differs from what would leave the account, the request is rejected.
Security model
- Moving money means signing. On the s2s surface, every request — reads included — is signed with your Ed25519 key, and each call needs the matching wallet permission on that key (Key permissions).
- Idempotency is mandatory. Money-moving and record-creating calls require an
Idempotency-Key(full list). Replaying the same key returns the original response instead of repeating the operation. - Four eyes. For manual intervention, campaign approval and bulk payout approval, the requester and the approver cannot be the same principal — enforced in the service layer by principal comparison, not by a role gate. A manual intervention is a stored request: the requester and the approver are taken from their panel sessions, never from the request body.
- Fail closed. If a gate (limit, KYC, fraud, provider) cannot answer, the operation is rejected. There is no "let it through" path.
Related products
- Refund to Wallet — credit a card refund to the wallet
- Payment Orchestrator — card top-ups are delegated to it
- Fraud & Fraud AI — risk decisions on wallet outflows
- Identity — device and session intelligence in portal sessions