Wallets & Accounts
Who calls these endpoints?External API (s2s)
- Base path
/api/v1/wallet- Identity
- Ed25519 request signature —
X-Key-Id,X-Date,X-Nonce,Digest(when there is a body),X-Signature. ±5 min clock window, single-use nonce, optional per-key IP allow-list. - Authorization
- The key must carry the wallet product and the wallet permission the call requires; a call without it gets
403 WALLET_INSUFFICIENT_SCOPE. Permissions per endpoint: Key permissions. - Cross-surface
- Both endpoints require
wallet:enduser:manageorwallet:program:manageon your key. The endpoint that lists a user's wallets is merchant-panel only.
When an end user is created, the default wallet opens with a single account. With the two endpoints on this page you:
- Add an account in another currency to an existing wallet — the most common need.
- Open an extra wallet for the user — for example to set money aside for a separate purpose.
Both are limited to the currencies enabled in your program.
Open an account
POST /api/v1/wallet/wallets/{walletId}/accounts| Header | Required | Rule |
|---|---|---|
Idempotency-Key | ✅ | 1–128 characters |
| Body field | Type | Required | Rule |
|---|---|---|---|
currency | string | ✅ | 3–8 letters; upper-cased. Must be enabled in your program. |
Rules:
- A wallet can hold only one account per currency. A second account in the same currency gets
409 WALLET_ACCOUNT_EXISTS. - If the currency is not enabled in your program:
409 WALLET_CURRENCY_NOT_ALLOWED. - If the wallet is not
ACTIVE(for example because the user was closed):409 WALLET_STATE_INVALID.
curl -X POST "https://api-gateway.lunixi.com/api/v1/wallet/wallets/1e7f9a3b-5c2d-4a8e-b6f1-3d9c0e2a7b58/accounts" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: account-crm-88213-usd" \
-H "X-Key-Id: …" -H "X-Date: …" -H "X-Nonce: …" -H "Digest: …" -H "X-Signature: …" \
-d '{"currency":"USD"}'{
"status": "success",
"code": "SUCCESS",
"message": "…",
"data": {
"id": "7b4e1c9a-2f6d-4a3b-9e8c-1d5f7a2b6c90",
"walletId": "1e7f9a3b-5c2d-4a8e-b6f1-3d9c0e2a7b58",
"currency": "USD",
"accountCode": 5100,
"fullWalletNo": "58107634125100",
"status": "ACTIVE"
},
"requestId": "…"
}data.id is the new account's walletAccountId. fullWalletNo is the wallet number followed by the account code.
Open an extra wallet
POST /api/v1/wallet/end-users/{id}/wallets| Header | Required | Rule |
|---|---|---|
Idempotency-Key | ✅ | 1–128 characters |
| Body field | Type | Required | Rule |
|---|---|---|---|
name | string | — | Wallet name, 1–80 characters. Defaults to Cüzdanım. |
currencies | string[] | — | Currencies of the accounts to open in the wallet. Values are upper-cased and duplicates count once; each must be enabled in your program. If omitted or empty, the wallet opens without accounts. |
Rules:
- The user must be
ACTIVE; a wallet cannot be opened for aFROZENorCLOSEDuser (409 WALLET_STATE_INVALID). - The new wallet has
isDefault: false; the default wallet does not change. - Each wallet gets its own 10-digit
walletNo.
curl -X POST "https://api-gateway.lunixi.com/api/v1/wallet/end-users/8d4c2a1f-3b6e-4f7a-9c5d-2e8b1a0f6c34/wallets" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: wallet-crm-88213-savings" \
-H "X-Key-Id: …" -H "X-Date: …" -H "X-Nonce: …" -H "Digest: …" -H "X-Signature: …" \
-d '{"name":"Savings","currencies":["TRY"]}'{
"status": "success",
"code": "SUCCESS",
"message": "…",
"data": {
"id": "6c2f8e1a-4b9d-4d3e-a7f5-0e1b9c3d2a84",
"endUserId": "8d4c2a1f-3b6e-4f7a-9c5d-2e8b1a0f6c34",
"walletNo": "7349028156",
"name": "Savings",
"isDefault": false,
"status": "ACTIVE",
"accounts": [
{
"id": "e9a1d4c7-3b2f-4e6a-8d5c-7f0b1a2e3c69",
"walletId": "6c2f8e1a-4b9d-4d3e-a7f5-0e1b9c3d2a84",
"currency": "TRY",
"accountCode": 5000,
"fullWalletNo": "73490281565000",
"status": "ACTIVE"
}
],
"createdAt": "2026-10-11T12:04:51.330Z"
},
"requestId": "…"
}⚠️
A wallet opened without accounts is invisible to s2s reads: the balances endpoint lists accounts only, and the endpoint that lists a user's wallets is panel-only. Store data.id from the response and use it when opening an account.
Idempotency
Idempotency-Key is required on both endpoints:
- Repeating the same request with the same key returns the first successful response as is; no second wallet or account is opened.
- Using the same key with a different request returns
409 WALLET_IDEMPOTENCY_CONFLICT. The comparison useswalletIdandcurrencyfor opening an account, and the user,nameandcurrenciesfor opening a wallet, as you sent them. - If the first request failed, the key is released.
If you repeat an account opening with a new key, you get 409 WALLET_ACCOUNT_EXISTS because the account already exists; read it from the balances endpoint.
Errors
| HTTP | Code | When |
|---|---|---|
| 400 | VALIDATION_ERROR | The body breaks a rule or contains an undefined field |
| 400 | — | A path id is not a UUID; Idempotency-Key missing, empty or longer than 128 characters |
| 400 | WALLET_VALIDATION | The currency is not supported by the platform |
| 403 | WALLET_INSUFFICIENT_SCOPE | The key lacks wallet:enduser:manage or wallet:program:manage |
| 404 | WALLET_NOT_FOUND | The user or wallet does not exist or is not yours |
| 409 | WALLET_ACCOUNT_EXISTS | The wallet already has an account in this currency |
| 409 | WALLET_CURRENCY_NOT_ALLOWED | The currency is not enabled in your program |
| 409 | WALLET_STATE_INVALID | The user (opening a wallet) or the wallet (opening an account) is not ACTIVE |
| 409 | WALLET_IDEMPOTENCY_CONFLICT | The same Idempotency-Key was used with a different request |
| 409 | WALLET_IDEMPOTENCY_IN_PROGRESS | The first request sent with the same key is still being processed |