Fees
- 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
POST fees/quoteexists on all three surfaces (s2s, portal, panel). Managing fee and commission SCHEDULES is panel-only — 17 endpoints,wallet:fee:manage, version submit/approve chain and four-eyes.
Wallet fees are defined by a schedule and computed per operation with a quote. There is one core rule:
What is quoted is what is charged. The amount you show the user in the quote must equal the amount that leaves the account. This is not advice but a platform-enforced constraint: the initiate step fixes the amounts in the operation's integrityHash, the complete step verifies it, and a mismatch rejects the operation.
Quoting a fee
POST /api/v1/wallet/fees/quote| Field | Type | Required | Description |
|---|---|---|---|
programId | string | ✅ | |
operationType | string | ✅ | Which operation type |
currency | string | ✅ | |
amount | string | ✅ | Minor-unit transaction amount |
at | string | — | Compute as of a given instant (ISO date) |
{
"status": "success",
"code": "SUCCESS",
"data": {
"feeAmount": "250",
"constantPart": "100",
"percentagePart": "150",
"percentageBps": 15,
"expenseAmount": "0",
"taxLegs": [{ "name": "BSMV", "amount": "125" }],
"taxTotal": "125",
"totalCharge": "10425",
"scheduleVersionId": "2d8b5e1c-7f4a-4c9e-a3b6-8e1f5c2d9a74",
"appliedTimeKey": "WEEKDAY",
"appliedThreshold": "10000"
}
}| Field | Meaning |
|---|---|
feeAmount | Total fee (fixed + percentage) |
constantPart | Fixed component |
percentagePart | Percentage component |
percentageBps | Applied rate in basis points (15 bps = 0.15%) |
expenseAmount | Expense component |
taxLegs | Tax lines — name and amount |
taxTotal | Total tax |
totalCharge | Total leaving the account (amount + fee + tax) |
scheduleVersionId | Schedule version used |
appliedTimeKey | Which time-of-day/week rule applied |
appliedThreshold | Which amount-threshold branch was taken |
Show the user totalCharge, not amount. If "send ₺100" will debit ₺104.25, they must see that before sending.
Pinning the schedule version
If you send the quote's scheduleVersionId back when initializing, the fee is pinned to that version. Omit it and the schedule current at execution time applies.
{
"endUserId": "8d4c2a1f-3b6e-4f7a-9c5d-2e8b1a0f6c34",
"sourceWalletAccountId": "c2a5e8f1-9d3b-4c7a-8e6f-5b1d2a9c0e47",
"destinationPhone": "+905339876543",
"amount": "10050",
"currency": "TRY",
"scheduleVersionId": "2d8b5e1c-7f4a-4c9e-a3b6-8e1f5c2d9a74"
}When a long time can pass between quote and execute (the user left the screen open), sending scheduleVersionId is the correct behaviour — otherwise the fee the user saw and the fee charged diverge, and the operation is rejected at integrityHash verification.
How the fee is computed
A fee schedule is a matrix: at the intersection of operation type × currency it branches by amount thresholds and time windows.
totalCharge, not amount: that is what actually leaves the account, fee and tax included. The scheduleVersionId in the quote pins the fee you displayed.appliedThreshold and appliedTimeKey tell you which branch the quote landed on — the first place to look when a fee surprises you.
Fees vs commission
| Fee | Commission | |
|---|---|---|
| Charged to | The user performing the operation | The collecting business |
| Where it appears | feeTotal | commissionTotal |
| Schedule | Fee schedule | Commission schedule |
Both can occur on one operation: the user pays a fee while the business pays collection commission.
Schedule management and approval
Fee schedules are versioned and approved:
The person who drafts and the person who approves must differ. An approved version becomes active and the previous one retires; past operations stay traceable through their own scheduleVersionId.
Panel side: Panel — Limit & Fee Schemes.
End-user surface
POST /api/portal/v1/wallet/fees/quoteThe same computation, under the user's own session. Call it as the amount is typed so the fee updates live in your app.
Common mistakes
| Symptom | Cause | Fix |
|---|---|---|
| "More was charged than I expected" | You displayed amount instead of totalCharge | Show the total on screen |
Operation rejected on integrityHash | The schedule changed between quote and execute | Send scheduleVersionId |
| Fee lands on an unexpected branch | Different amount threshold or time window | Inspect appliedThreshold and appliedTimeKey |
| No tax shown | taxLegs is empty | The schedule defines no tax component |