Fee Ledger
Read the fee calculations recorded for a user and reconcile the quote against what settlement charged.
Before You Start
Read the following guides before proceeding:
| Guide | Why |
|---|---|
| Getting Started | Platform overview and setup |
| Api Basics | Required headers and request configuration |
| Authentication | How to obtain access tokens |
Overview
The fee ledger returns the fee calculations Wirex recorded for one user, newest first. It prices nothing
and derives nothing — what it returns is exactly what the fee service already quoted or charged, so a
partner can audit charging per operation without re-deriving fee math itself.
Requires a partner token. This endpoint is registered for the Self-Signed Partner JWT provider only.
The subject is the user named byX-User-Wallet, never a request parameter — a partner reads one of its
own users at a time and nothing else.
Calculation Lifecycle
A calculation moves forward through three stages as the operation it prices progresses, and is never moved
backward:
CALCULATION_STATUS_PENDING → CALCULATION_STATUS_CONSUMED → CALCULATION_STATUS_FINALIZED
| Status | Meaning |
|---|---|
CALCULATION_STATUS_PENDING | Priced, not yet bound to anything. A quote the user never executed stays here |
CALCULATION_STATUS_CONSUMED | Bound to a transaction accepted for execution |
CALCULATION_STATUS_FINALIZED | Settlement amounts recorded. Terminal |
src_amount_fee_charged and dst_amount_fee_charged are what settlement produced — present only once the
record is CALCULATION_STATUS_FINALIZED. An amount the platform has not settled yet is absent from the
record rather than reported as zero. The quote the user was shown at the originating endpoint is not part of
this record; compare the finalized record against that estimate to reconcile.
Rate markup is not a fee amount. It is the distance between operation_rate_precise and
user_rate_precise, summarized by effective_fx_markup_bps, and applies even where the fee amounts
themselves are zero.
Get Fee Ledger
GET /api/v1/fees/ledger
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
op_type | string | No | Filter by operation type, e.g. OP_TYPE_TRADE_CRYPTO. An unrecognized value returns 400 |
status | string | No | Filter by calculation status — one of the three lifecycle values. An unrecognized value returns 400 |
transaction_id | string (UUID) | No | Filter to the calculation bound to this transaction on Consume |
consumed_from_unix_ms | integer | No | Lower bound of the consumed-at window, Unix milliseconds. 0 (default) is unbounded |
consumed_to_unix_ms | integer | No | Upper bound of the consumed-at window, Unix milliseconds. 0 (default) is unbounded. Must not be before consumed_from_unix_ms |
page_size | integer | No | Page size. Default 25, capped at 200 |
page_token | string | No | Opaque continuation token from a previous page's next_page_token |
op_type,status,client_class,quote_modeandpair_classare the fee service's own enum
constants (e.g.OP_TYPE_TRADE_CRYPTO,CLIENT_CLASS_RETAIL,QUOTE_MODE_SOURCE_FIXED). This API does
not publish a complete list — pass the value exactly as returned by a record you have already read, or as
named by your Wirex account contact, and treat an unrecognized filter value as the400it returns.
Response
{
"records": [
{
"calculation_id": "6f9619ff-8b86-d011-b42d-00c04fc964ff",
"transaction_id": "1f9619ff-8b86-d011-b42d-00c04fc964aa",
"status": "CALCULATION_STATUS_FINALIZED",
"op_type": "OP_TYPE_TRADE_CRYPTO",
"op_currency": "USD",
"client_class": "CLIENT_CLASS_RETAIL",
"quote_mode": "QUOTE_MODE_SOURCE_FIXED",
"subject_address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"src_amount_quoted": { "amount": 100.00, "amount_precise": "100000000", "currency": "USDC", "decimals": 6 },
"dst_amount_quoted": { "amount": 99.50, "amount_precise": "99500000", "currency": "WEUR", "decimals": 6 },
"src_amount_debited": { "amount": 100.00, "amount_precise": "100000000", "currency": "USDC", "decimals": 6 },
"dst_amount_credited": { "amount": 99.48, "amount_precise": "99480000", "currency": "WEUR", "decimals": 6 },
"src_amount_fee_charged": { "amount": 0.02, "amount_precise": "20000000000000000", "currency": "USDC", "decimals": 18 },
"dst_amount_fee_charged": { "amount": 0.00, "amount_precise": "0", "currency": "WEUR", "decimals": 18 },
"mid_rate_calculate_precise": "1000000000000000000",
"operation_rate_precise": "1000000000000000000",
"user_rate_precise": "996400000000000000",
"rate_decimals": 18,
"effective_fx_markup_bps": 36,
"pair_class": "MAJOR_MAJOR",
"config_revision": "41",
"requested_at_unix_ms": 1735689600000,
"consumed_at_unix_ms": 1735689601000,
"finalized_at_unix_ms": 1735689630000
}
],
"next_page_token": ""
}| Field | Description |
|---|---|
records[].calculation_id | Identifier of the calculation |
records[].transaction_id | The transaction the calculation was bound to on Consume. Absent on a PENDING record |
records[].status | Calculation lifecycle stage — see Calculation Lifecycle |
records[].op_type | Operation the fee was priced for |
records[].op_currency | Currency the operation was denominated in |
records[].client_class | Pricing class the subject was resolved to |
records[].quote_mode | Which side of the operation the caller fixed |
records[].subject_address | Wallet the calculation was priced for |
records[].src_amount_quoted / dst_amount_quoted | Source / destination amount at quote time |
records[].fixed_side_amount_usd | USD value of whichever side was fixed |
records[].src_amount_debited / dst_amount_credited | What left the source side / reached the destination side at settlement. Present only once FINALIZED |
records[].src_amount_trade_in / dst_amount_trade_out | The source slice that entered the trade / the destination slice it produced |
records[].src_amount_fee_charged / dst_amount_fee_charged | Fee actually charged on each side. Present only once FINALIZED |
records[].transport_fee_estimated / transport_fee_charged / transport_fee_actual | Network cost quoted / billed (a component of src_amount_fee_charged) / actually incurred at Finalize |
records[].transport_fee_bps | Markup applied over the transport estimate |
records[].mid_rate_calculate_precise | Mid rate held at quote time, in base units scaled by rate_decimals |
records[].operation_rate_precise | Settlement rate, in base units scaled by rate_decimals |
records[].user_rate_precise | Rate the user received after markup, in base units scaled by rate_decimals |
records[].rate_decimals | Fractional digits the *_rate_precise fields are scaled by |
records[].effective_fx_markup_bps | Markup, in basis points, separating user_rate_precise from operation_rate_precise |
records[].pair_class | Markup family the asset pair was classified into |
records[].config_revision | Fee configuration revision that priced the record |
records[].card_format / card_origin_country / card_destination_country / card_delivery_provider / card_delivery_type / card_model_key / card_price_symbol | Present on card operations only |
records[].requested_at_unix_ms | When the calculation was quoted |
records[].consumed_at_unix_ms | When the calculation was bound to a transaction. Absent on a PENDING record |
records[].finalized_at_unix_ms | When settlement amounts were recorded. Absent before FINALIZED |
next_page_token | Continuation token for the next page. Empty on the last page |
Every amount object (src_amount_quoted, dst_amount_credited, src_amount_fee_charged, and so on)
carries the same four fields: amount (display value, 6 fractional digits), amount_precise (exact base
units), currency (asset symbol), and decimals (fractional digits amount_precise is scaled by) —
reconcile against amount_precise, not amount.
const response = await fetch(`${baseUrl}/api/v1/fees/ledger?status=CALCULATION_STATUS_FINALIZED&page_size=50`, {
headers: {
'Authorization': `Bearer ${accessToken}`,
'X-User-Wallet': userEoaAddress,
'X-Chain-Id': chainId
}
});
const { records, next_page_token: nextPageToken } = await response.json();response = requests.get(
f"{base_url}/api/v1/fees/ledger",
params={"status": "CALCULATION_STATUS_FINALIZED", "page_size": 50},
headers={
"Authorization": f"Bearer {access_token}",
"X-User-Wallet": user_eoa_address,
"X-Chain-Id": chain_id
}
)
data = response.json()
records = data["records"]
next_page_token = data.get("next_page_token")req, _ := http.NewRequest("GET", baseURL+"/api/v1/fees/ledger?status=CALCULATION_STATUS_FINALIZED&page_size=50", nil)
req.Header.Set("Authorization", "Bearer "+accessToken)
req.Header.Set("X-User-Wallet", userEoaAddress)
req.Header.Set("X-Chain-Id", chainId)
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
var ledger FeeLedgerResponse
json.NewDecoder(resp.Body).Decode(&ledger)Error Handling
{
"error_reason": "ErrorInvalidField",
"error_description": "Invalid value for op_type",
"error_category": {
"category": "CategoryValidationFailure",
"http_status_code": 400
},
"error_details": [
{ "key": "field", "details": "op_type" },
{ "key": "issue", "details": "invalid_value" }
]
}Validation Errors (400)
| Error Reason | Field | Description |
|---|---|---|
ErrorInvalidField | op_type | Not one of the fee service's operation types |
ErrorInvalidField | status | Not one of the three lifecycle values |
ErrorInvalidField | transaction_id | Not a valid UUID |
ErrorInvalidField | consumed_from_unix_ms / consumed_to_unix_ms | Negative, or consumed_from_unix_ms is after consumed_to_unix_ms |
ErrorInvalidField | page_size | Exceeds 200 |
Updated 17 days ago

