Transactions
Overview
The API provides a single unified transaction feed that aggregates activity across all of a user’s funding sources — crypto wallets, linked bank accounts, and debit cards. Rather than querying each source separately, your platform can fetch, filter, and paginate all transactions through one endpoint.
The transaction system is:
- Unified — crypto, bank, and card transactions share the same data model and endpoint
- Filterable — narrow results by source, type, status, direction, category, amount range, date range, and merchant
- Paginated — offset-based pagination with a default page size of 50 (max 100)
- Metadata-aware — opt into aggregate statistics including cashflow summaries and category breakdowns
Quick Start
1. List all transactions
curl /v0/transactions \
-H "x-juno-jwt: <token>"
Returns the most recent 50 transactions across all sources (200 OK).
2. Filter by source
curl "/v0/transactions?source=card" \
-H "x-juno-jwt: <token>"
3. Get a single transaction
curl /v0/transactions/txn_abc123 \
-H "x-juno-jwt: <token>"
Returns full transaction details including related entity data (200 OK).
curl "/v0/transactions?meta=true&from_date=2024-01-01&to_date=2024-01-31" \
-H "x-juno-jwt: <token>"
When meta=true, the response includes cashflow totals, date range, and a category-level spending breakdown.
Transaction Model
List Response Shape
{
"transactions": [
{
"external_id": "txn_abc123",
"type": "card_purchase",
"status": "completed",
"direction": "out",
"source": "card",
"amount": "42.50",
"asset": {
"id": 1,
"symbol": "USD",
"name": "US Dollar",
"asset_type": "fiat",
"chain_id": null,
"contract_address": null,
"decimals": 2
},
"wallet": null,
"account": null,
"card": {
"id": 7,
"last_four": "4242",
"brand": "visa",
"card_type": "debit"
},
"tx_hash": null,
"merchant_name": "Chipotle",
"merchant_logo_url": "https://logo.clearbit.com/chipotle.com",
"merchant_category_code": "5812",
"category": "restaurants",
"processor_reference": "pi_3abc123",
"created_at": 1704067200000,
"updated_at": 1704067200000
}
],
"total": 312,
"offset": 0,
"limit": 50,
"meta": null,
"_links": {
"self": { "href": "/v0/transactions?offset=0&limit=50" },
"first": { "href": "/v0/transactions?offset=0&limit=50" },
"next": { "href": "/v0/transactions?offset=50&limit=50" },
"last": { "href": "/v0/transactions?offset=300&limit=50" },
"user": { "href": "/v0/user/me" }
}
}
Transaction Fields
| Field | Type | Description |
|---|
external_id | string | Unique transaction identifier |
type | string | Transaction type (see TransactionType) |
status | string | Lifecycle state (see TransactionStatus) |
direction | string | Fund flow relative to the user: in or out |
source | string or null | Funding source (see TransactionSource) |
amount | decimal | Transaction amount in the asset’s base units |
asset | object | Asset involved (symbol, decimals, chain info) |
wallet | object or null | Wallet data for crypto transactions |
account | object or null | Bank account data for bank transactions |
card | object or null | Card data for card transactions |
tx_hash | string or null | On-chain transaction hash (crypto only) |
merchant_name | string or null | Merchant name (card and bank transactions) |
merchant_logo_url | string or null | URL to merchant logo image |
merchant_category_code | string or null | 4-digit ISO 18245 MCC |
category | string or null | Spending category (see TransactionCategory) |
processor_reference | string or null | External processor transaction reference |
created_at | integer | Transaction creation timestamp (epoch ms) |
updated_at | integer | Last update timestamp (epoch ms) |
Embedded Asset
Every transaction includes an asset object describing the currency or token involved:
| Field | Type | Description |
|---|
id | integer | Internal asset identifier |
symbol | string | Ticker symbol (e.g., ETH, USDC, USD) |
name | string | Human-readable name |
asset_type | string | crypto or fiat |
chain_id | integer or null | EIP-155 chain ID (null for fiat) |
contract_address | string or null | ERC-20 contract address (null for native tokens and fiat) |
decimals | integer | Decimal precision for formatting |
Embedded Card
Present when source is card:
| Field | Type | Description |
|---|
id | integer | Internal card identifier |
last_four | string or null | Last 4 digits of card number |
brand | string or null | Card network (visa, mastercard) |
card_type | string or null | Card type (debit, credit) |
Embedded Account
Present when source is bank_account:
| Field | Type | Description |
|---|
external_id | string | Account identifier from open banking provider |
provider | string | Banking provider (plaid, truelayer) |
account_type | string | Account type (checking, savings, etc.) |
institution_name | string | Bank or financial institution name |
account_name | string | Account name as shown by institution |
account_mask | string or null | Last 4 digits of account number |
nickname | string or null | User-assigned friendly name |
Embedded Wallet
Present when source is crypto_wallet:
| Field | Type | Description |
|---|
id | integer | Internal wallet identifier |
external_id | string or null | External wallet identifier |
address | string | Blockchain address (0x-prefixed) |
chain_id | integer | EIP-155 chain ID |
is_primary | boolean | Whether this is the user’s primary wallet |
is_eoa | boolean | True for externally owned accounts, false for Safe wallets |
Query Parameters
All filters are optional and can be combined. Apply them to GET /v0/transactions.
| Parameter | Type | Description |
|---|
source | string | Filter by funding source: crypto_wallet, bank_account, card |
type | string | Filter by transaction type (see TransactionType) |
status | string | Filter by status: pending, processing, completed, failed, cancelled |
direction | string | Filter by direction: in or out |
category | string | Filter by spending category. Comma-separated for OR logic (e.g., groceries,restaurants,coffee) |
account_id | string | Filter by bank account external_id |
wallet_id | string | Filter by wallet ID |
card_id | string | Filter by card ID |
merchant_name | string | Filter by merchant name (case-insensitive partial match) |
merchant_category_code | string | Filter by 4-digit MCC |
amount_min | decimal | Minimum transaction amount (inclusive) |
amount_max | decimal | Maximum transaction amount (inclusive) |
from_date | string | Start date — epoch milliseconds or YYYY-MM-DD |
to_date | string | End date — epoch milliseconds or YYYY-MM-DD |
offset | integer | Pagination offset (default: 0) |
limit | integer | Results per page, 1-100 (default: 50) |
meta | boolean | Include aggregate metadata (default: false) |
Combining Filters
Filters are AND-combined. Multiple category values within a single parameter are OR-combined.
# Card purchases over $100 at restaurants or coffee shops in January 2024
curl "/v0/transactions?source=card&type=card_purchase&category=restaurants,coffee&amount_min=100&from_date=2024-01-01&to_date=2024-01-31" \
-H "x-juno-jwt: <token>"
The response includes total, offset, and limit fields alongside pagination links in _links:
{
"total": 312,
"offset": 50,
"limit": 50,
"_links": {
"self": { "href": "/v0/transactions?offset=50&limit=50" },
"first": { "href": "/v0/transactions?offset=0&limit=50" },
"prev": { "href": "/v0/transactions?offset=0&limit=50" },
"next": { "href": "/v0/transactions?offset=100&limit=50" },
"last": { "href": "/v0/transactions?offset=300&limit=50" }
}
}
Follow the next link to page forward. The prev link is absent on the first page; the next link is absent on the last page.
Set meta=true to include summary statistics for the filtered result set:
curl "/v0/transactions?meta=true&source=card&from_date=2024-01-01&to_date=2024-01-31" \
-H "x-juno-jwt: <token>"
{
"transactions": [ "..." ],
"total": 87,
"meta": {
"transaction_count": 50,
"date_range": {
"earliest": "2024-01-02",
"latest": "2024-01-31"
},
"cashflow": {
"gross_in": "1250.00",
"gross_out": "3420.75",
"net": "-2170.75"
},
"categories": [
{
"category": "restaurants",
"total_amount": "890.50",
"percentage_of_total": "26.03",
"transaction_count": 18
},
{
"category": "groceries",
"total_amount": "654.20",
"percentage_of_total": "19.12",
"transaction_count": 12
}
]
},
"_links": { "..." : "..." }
}
| Field | Type | Description |
|---|
meta.transaction_count | integer | Number of transactions in the current page |
meta.date_range | object or null | Earliest and latest dates in the result set (null if empty) |
meta.cashflow.gross_in | decimal | Sum of all direction: "in" amounts |
meta.cashflow.gross_out | decimal | Sum of all direction: "out" amounts |
meta.cashflow.net | decimal | gross_in - gross_out |
meta.categories | array | Spending breakdown by category, sorted by total amount descending |
meta.categories[].percentage_of_total | decimal | Percentage of gross_out this category represents (0-100) |
Metadata is computed from the current page of results, not the full filtered set. For accurate aggregate statistics over a large dataset, set limit=100 and paginate through all pages, or use a date range that constrains the result set.
Endpoints
List Transactions
Returns a paginated list of transactions across all funding sources. See Filtering & Pagination for all query parameters.
Response: 200 OK
Get Transaction
GET /v0/transactions/{external_id}
Returns full details for a single transaction, including related entity data and HAL links to associated resources.
Response: 200 OK
{
"external_id": "txn_def456",
"type": "deposit",
"status": "completed",
"direction": "in",
"source": "crypto_wallet",
"amount": "1.5",
"asset": {
"id": 2,
"symbol": "ETH",
"name": "Ethereum",
"asset_type": "crypto",
"chain_id": 8453,
"contract_address": null,
"decimals": 18
},
"wallet": {
"id": 3,
"external_id": "wal_xyz789",
"address": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD78",
"chain_id": 8453,
"is_primary": true,
"is_eoa": true
},
"account": null,
"card": null,
"tx_hash": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"merchant_name": null,
"merchant_logo_url": null,
"merchant_category_code": null,
"category": null,
"processor_reference": null,
"created_at": 1704067200000,
"updated_at": 1704067200000,
"_links": {
"self": { "href": "/v0/transactions/txn_def456" },
"user": { "href": "/v0/user/me" },
"wallet": { "href": "/v0/wallets/3" },
"asset": { "href": "/v0/assets/2" }
}
}
Authorization: Only the owning user can access their transactions. Returns 403 Forbidden if the transaction belongs to a different user.
HAL Links
The single-transaction response includes contextual links based on the transaction source:
| Link | Present When | Description |
|---|
self | Always | This transaction’s detail URL |
user | Always | Owning user’s profile |
wallet | Crypto transactions | Associated wallet |
account | Bank transactions | Associated bank account |
card | Card transactions | Associated card |
asset | Asset is present | Asset details and pricing |
category-transactions | Category is set | List all transactions in the same category |
Integration Patterns
Building a Transaction Feed UI
- Fetch the first page:
GET /v0/transactions?limit=50
- Render each transaction using
type, direction, and source to select icons and labels
- Use
merchant_name and merchant_logo_url for card/bank transactions; use asset.symbol and tx_hash for crypto transactions
- Implement infinite scroll by following the
next link in _links
- Use
total to show the overall count
Pseudocode:
page = GET /v0/transactions?limit=50
render_transactions(page.transactions)
show_count(page.total)
on_scroll_to_bottom():
if "next" in page._links:
page = GET page._links.next.href
append_transactions(page.transactions)
Filtering by Source
Display source-specific tabs by passing the source parameter:
# Crypto tab
GET /v0/transactions?source=crypto_wallet
# Banking tab
GET /v0/transactions?source=bank_account
# Card tab
GET /v0/transactions?source=card
Each source populates different embedded fields. Crypto transactions include wallet and tx_hash; bank transactions include account and merchant_name; card transactions include card, merchant_name, and category.
Spending Analytics
Use meta=true with date range filters to power dashboards:
# Monthly spending overview
curl "/v0/transactions?meta=true&direction=out&from_date=2024-01-01&to_date=2024-01-31" \
-H "x-juno-jwt: <token>"
The categories array in the metadata response gives you a ready-made breakdown for pie charts or bar graphs, with percentage_of_total pre-computed.
Searching by Merchant
The merchant_name filter performs a case-insensitive partial match, useful for building search UIs:
curl "/v0/transactions?merchant_name=starbucks" \
-H "x-juno-jwt: <token>"
Error Handling
All errors follow RFC 7807 Problem Details format:
{
"type": "https://api.sumvin.com/errors/txn-404-001",
"title": "Transaction Not Found",
"status": 404,
"detail": "Transaction txn_abc123 not found",
"instance": "/v0/transactions/txn_abc123",
"error_code": "TXN-404-001"
}
Invalid query parameters return a structured response with details about each invalid field:
{
"type": "https://api.sumvin.com/errors/txn-400-001",
"title": "Invalid Query Parameter",
"status": 400,
"detail": "One or more query parameters are invalid",
"instance": "/v0/transactions",
"error_code": "TXN-400-001",
"invalid_params": [
{
"name": "merchant_category_code",
"reason": "Must be exactly 4 digits",
"provided": "abc",
"valid_example": "5411"
}
]
}
| Status | Error Code | Meaning |
|---|
| 400 Bad Request | TXN-400-001 | Invalid query parameter (see invalid_params for details) |
| 400 Bad Request | TXN-400-002 | amount_min is greater than amount_max |
| 401 Unauthorized | — | Missing or invalid authentication token |
| 403 Forbidden | TXN-403-001 | Transaction belongs to a different user |
| 404 Not Found | TXN-404-001 | Transaction with the given external_id does not exist |
| 500 Internal Server Error | TXN-500-001 | Transaction is missing required asset data (should not occur in normal operation) |
Reference Tables
Transaction Types
| Value | Source | Description |
|---|
deposit | Crypto | Incoming transfer to user’s wallet from external source |
withdrawal | Crypto | Outgoing transfer from user’s wallet to external address |
transfer | Crypto | Internal movement between user’s own wallets |
swap | Crypto | Token exchange (e.g., ETH to USDC) |
on_ramp | Crypto | Fiat-to-crypto conversion via exchange/provider |
off_ramp | Crypto | Crypto-to-fiat conversion via exchange/provider |
card_purchase | Card | Debit card spend at merchant |
card_refund | Card | Merchant-initiated refund to card |
bank_transfer | Bank | ACH/wire transfer between accounts |
direct_debit | Bank | Recurring automated payment (bills, subscriptions) |
standing_order | Bank | Scheduled fixed payment |
bank_payment | Bank | One-time outgoing payment |
bank_refund | Bank | Return of funds to bank account |
interest | Bank | Interest credit on savings/checking account |
fee | Bank | Bank service charge or maintenance fee |
Transaction Statuses
| Value | Description |
|---|
pending | Created but not yet submitted for processing |
processing | Submitted to network/provider, awaiting confirmation |
completed | Successfully finalized (on-chain confirmed or bank settled) |
failed | Rejected or reverted (check error details) |
cancelled | Cancelled by user or system before completion |
Transaction Directions
| Value | Description |
|---|
in | Funds entering the user’s account (credits, deposits, refunds) |
out | Funds leaving the user’s account (debits, payments, withdrawals) |
Transaction Categories
Categories are assigned based on merchant classification codes (MCC) and apply to card and bank transactions.
| Value | Description |
|---|
restaurants | Full-service dining establishments |
food | General food and beverage (fast food, takeout) |
groceries | Supermarkets and grocery stores |
coffee | Coffee shops and cafes |
shopping | General retail and e-commerce |
utilities | Electric, gas, water, internet services |
transport | Ride-share, public transit, parking, fuel |
entertainment | Movies, concerts, streaming services |
subscriptions | Recurring digital services and memberships |
Transaction Sources
| Value | Description |
|---|
crypto_wallet | On-chain transaction from user’s EOA or Safe wallet |
bank_account | ACH/wire transfer from linked bank account |
card | Debit card purchase or refund |
Next Steps