List a wallet's transactions
The wallets.transactions.list operation: GET /api/v1/wallets/{id}/transactions in the REST API and the wallets_transactions_list tool in the MCP server.
/api/v1/wallets/{id}/transactionsLists the ledger transactions that moved the wallet, newest first: top-ups, grants, reservations, captures,
releases and expiries. Each shows the signed change of available, promo and reserved and of the
balance (reserving and releasing move credits inside the wallet, so they don't change the balance), with
the reservation, grant or payment it belongs to.
Paginate with limit (1–100, default 10) and starting_after (a txn_… ID).
At a glance
- REST:
GET /api/v1/wallets/{id}/transactions - MCP tool:
wallets_transactions_list - Operation ID:
wallets.transactions.list - Scope: Brand
- Permission:
wallets:read - Risk tier:
read - Dry run: Not supported
- Idempotency: Not needed (read only)
- Modes: Test and live
- Pagination:
limit(at most 100) andstarting_after - Authentication: API key with the
wallets:readscope - Since: M6
Request
Path parameters
| Field | Type | Description |
|---|---|---|
id | wal_… ID | The wallet (wal_…). |
Query parameters
| Field | Type | Required | Description |
|---|---|---|---|
limit | integer (1 to 100) | No | |
starting_after | txn_… ID | No |
Response
200 OK with a JSON object, a page of the list (newest first):
| Field | Type | Description |
|---|---|---|
object | "list" | |
data | array of object | |
data[].id | txn_… ID | |
data[].object | "wallet_transaction" | |
data[].walletId | wal_… ID | |
data[].kind | one of 19 values, e.g. topup, sale, grant (all in the OpenAPI document) | topup, grant, reservation, capture, release, expiry, … (the ledger transaction's kind). |
data[].status | one of pending, posted, voided | |
data[].memo | string | |
data[].available | money | Signed change of available (credits in are positive). |
data[].promo | money | Signed change of promo. |
data[].reserved | money | Signed change of reserved. |
data[].balance | money | Signed change of the balance; reserving and releasing change none. |
data[].reservationId | string or null | |
data[].grantId | string or null | |
data[].paymentId | string or null | |
data[].effectiveAt | date-time | |
data[].createdAt | date-time | |
has_more | boolean | |
next_cursor | string or null |
Examples
A top-up, then a capture
GET /api/v1/wallets/wal_01m4ty7w2a5qx7mhd9k8w6s0b1/transactions?limit=2
Authorization: Bearer or_test_…
Response (200):
{
"object": "list",
"data": [
{
"id": "txn_01m4ty7w2a5qx7mhd9k8w6s0b8",
"object": "wallet_transaction",
"walletId": "wal_01m4ty7w2a5qx7mhd9k8w6s0b1",
"kind": "capture",
"status": "posted",
"memo": "Usage capture",
"available": {
"amount": "0",
"currency": "EUR"
},
"promo": {
"amount": "0",
"currency": "EUR"
},
"reserved": {
"amount": "-1250000",
"currency": "EUR"
},
"balance": {
"amount": "-1250000",
"currency": "EUR"
},
"reservationId": "res_01m4ty7w2a5qx7mhd9k8w6s0b4",
"grantId": null,
"paymentId": null,
"effectiveAt": "2026-10-16T10:16:00.000Z",
"createdAt": "2026-10-16T10:16:00.000Z"
},
{
"id": "txn_01m4ty7w2a5qx7mhd9k8w6s0b7",
"object": "wallet_transaction",
"walletId": "wal_01m4ty7w2a5qx7mhd9k8w6s0b1",
"kind": "topup",
"status": "posted",
"memo": "Credit top-up",
"available": {
"amount": "80000000",
"currency": "EUR"
},
"promo": {
"amount": "0",
"currency": "EUR"
},
"reserved": {
"amount": "0",
"currency": "EUR"
},
"balance": {
"amount": "80000000",
"currency": "EUR"
},
"reservationId": null,
"grantId": "grant_01m4ty7w2a5qx7mhd9k8w6s0b2",
"paymentId": "pay_01m4ty7w2a5qx7mhd9k8w6s0b5",
"effectiveAt": "2026-10-14T09:00:00.000Z",
"createdAt": "2026-10-14T09:00:00.000Z"
}
],
"has_more": false,
"next_cursor": null
}
Errors
| Code | HTTP status | When | What to do |
|---|---|---|---|
validation_failed | 400 | id isn't a wallet ID, or a pagination value is invalid. | Fix the fields listed in details.issues and send the request again. |
resource_not_found | 404 | This brand has no such wallet in this mode (wallets belong to one brand and one mode). | Check the ID and that your credentials are scoped to the right organization, entity, brand and mode. |
scope_required | 400 | The request names no brand (an org or entity key without Ownrecord-Brand). | Call the operation with credentials or a target at its level: an organization, a legal entity, a brand or the platform (details.required_scope). |
permission_denied | 403 | You can't read this brand's wallets (wallets:read). | Ask an organization owner or admin for a role or scope that allows this action. |
livemode_not_allowed | 403 | You have no live-mode access, so you can't use live wallets. | Use test mode, or credentials for the target's mode. Developers need live access granted by an organization owner or admin. |
It can also return these common errors: api_version_unsupported, authentication_required, api_key_invalid, dry_run_not_supported, rate_limited, internal_error.