Statements
Generate a full account statement for a period, with opening and closing balances per currency.
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 |
| Activity History | Activity types, directions and subjects |
Overview
A statement is a point-in-time document, not a feed page. It covers a fixed period and returns
everything needed to render or export an account statement in one response: the user's identity and
legal address, their bank accounts, opening and closing balances per currency, and every transaction
in the window with its per-operation running balance.
Use the activity feed for browsing and reconciliation. Use this
endpoint when the output is a document — a monthly statement, a tax export, an audit pack.
Generate a Statement
POST /api/v1/activity/statement/full
Request
{
"start": 1640995200,
"end": 1672531199,
"token_addresses": [
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
]
}| Field | Type | Required | Description |
|---|---|---|---|
start | integer | Yes | Period start, Unix timestamp in seconds. Must be positive |
end | integer | Yes | Period end, Unix timestamp in seconds. Must be positive and greater than start |
token_addresses | string[] | No | Restrict the statement to these tokens. Each entry must be a valid address. Omit for all tokens |
The period cannot exceed 6 months. A wider range is refused outright — split a year into two
calls rather than retrying.
Response
{
"owner": "0x742d35Cc6634C0532925a3b8D400631C6D5d1234",
"user_address": "0x742d35Cc6634C0532925a3b8D400631C6D5d1234",
"chain_id": 8453,
"created_at": 1672531200,
"period": {
"start": 1640995200,
"end": 1672531199
},
"balances": [
{
"currency": "USDC",
"opening": 1000.50,
"closing": 1250.75,
"debit": 500.25,
"credit": 750.50
}
],
"user_data": {
"name": "Alex Gray",
"legal_address_data": "123 Business Street, Suite 400, New York, NY 10001, USA"
},
"user_bank_accounts": {},
"transactions": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"type": "Card",
"direction": "Outbound",
"amount": 95.50,
"currency": "USDC",
"created_at": 1672531200,
"updated_at": 1672531200,
"operations": [
{
"hash": "0x1a2b3c4d5e6f7890abcdef1234567890abcdef12",
"token_address": "0xA0b86a33E6441c58126c96ceb5A7e4E0e9473c1C",
"account_address": "0x742d35Cc6634C0532925a3b8D400631C6D5d1234",
"wallet_address": "0x742d35Cc6634C0532925a3b8D400631C6D5d1234",
"amount": 50.25,
"token_symbol": "USDC",
"created_at": 1672531200,
"resulting_balance": 1050.75
}
]
}
]
}| Field | Description |
|---|---|
owner | Owner address the statement was produced for |
user_address | User's wallet address |
chain_id | Chain the statement covers |
created_at | When the statement was generated (Unix seconds) |
period.start | Period start, echoing the request |
period.end | Period end, echoing the request |
balances[].currency | Currency or token symbol |
balances[].opening | Balance at period.start |
balances[].closing | Balance at period.end |
balances[].debit | Total debited during the period |
balances[].credit | Total credited during the period |
user_data.name | Statement holder's name |
user_data.legal_address_data | Legal address as a single formatted string |
user_bank_accounts | The user's bank accounts, in the same shape as the accounts API |
transactions[].id | Activity identifier. Matches id in the activity feed |
transactions[].type | Activity type — see Activity Types |
transactions[].direction | Inbound or Outbound |
transactions[].amount | Transaction amount |
transactions[].currency | Transaction currency |
transactions[].created_at | Creation time (Unix seconds) |
transactions[].updated_at | Last update time (Unix seconds) |
transactions[].source | Counterparty the funds came from. Omitted when not applicable |
transactions[].destination | Counterparty the funds went to. Omitted when not applicable |
transactions[].operations[].hash | On-chain transaction hash for the operation |
transactions[].operations[].token_address | Token contract address |
transactions[].operations[].account_address | Account the operation moved value on |
transactions[].operations[].wallet_address | Wallet the operation belongs to |
transactions[].operations[].amount | Operation amount |
transactions[].operations[].token_symbol | Token symbol |
transactions[].operations[].created_at | Operation time (Unix seconds) |
transactions[].operations[].resulting_balance | Running balance after this operation |
resulting_balance is what makes this a statement rather than a list — it is the balance after the
operation, so a rendered statement needs no client-side accumulation.
Code Examples
const statement = await fetch(`${baseUrl}/api/v1/activity/statement/full`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'X-User-Wallet': userEoaAddress,
'X-Chain-Id': chainId,
'Content-Type': 'application/json'
},
body: JSON.stringify({
start: 1640995200,
end: 1672531199
})
}).then(r => r.json());statement = requests.post(
f"{base_url}/api/v1/activity/statement/full",
headers={
"Authorization": f"Bearer {access_token}",
"X-User-Wallet": user_eoa_address,
"X-Chain-Id": chain_id,
"Content-Type": "application/json"
},
json={"start": 1640995200, "end": 1672531199}
).json()body, _ := json.Marshal(map[string]int64{
"start": 1640995200,
"end": 1672531199,
})
req, _ := http.NewRequest("POST", baseURL+"/api/v1/activity/statement/full", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+accessToken)
req.Header.Set("X-User-Wallet", userEoaAddress)
req.Header.Set("X-Chain-Id", chainId)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
var statement ActivityFullStatementResponse
json.NewDecoder(resp.Body).Decode(&statement)Limitations
- 6-month maximum period. Longer ranges are rejected at validation. Split them client-side.
- Not paginated. The full transaction set for the period is returned in one response, so a busy
account over a long window produces a large payload. - Timestamps are Unix seconds, not the ISO 8601 strings used elsewhere in the API.
token_addressesfilters, it does not aggregate. Excluded tokens are absent from both
transactionsandbalances, so a filtered statement does not reconcile to the account total.
Error Handling
Validation Errors (400)
| Error Details | Description | Resolution |
|---|---|---|
start: Start time must be a positive Unix timestamp | Missing, zero or negative | Send a positive timestamp in seconds |
end: End time must be a positive Unix timestamp | Missing, zero or negative | Send a positive timestamp in seconds |
start: Start time must be less than end time | Range inverted or empty | Order the bounds correctly |
end: End time must be within 6 months from start time | Period too wide | Split into ranges of 6 months or less |
token_addresses: each token address must be a valid address | An entry is not a valid address | Send valid contract addresses |
Each error also carries field and issue details — issue values here are invalid_value,
invalid_range, range_exceeds_6_months and invalid_format.
Example Error Response
{
"error_reason": "ErrorInvalidField",
"error_description": "Request failed validation",
"error_category": {
"category": "CategoryValidationFailure",
"http_status_code": 400
},
"error_details": [
{ "key": "field", "details": "end" },
{ "key": "issue", "details": "range_exceeds_6_months" },
{ "key": "end", "details": "End time must be within 6 months from start time" }
]
}Updated 20 days ago

