Skip to main content

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).

4. Request aggregate metadata

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

FieldTypeDescription
external_idstringUnique transaction identifier
typestringTransaction type (see TransactionType)
statusstringLifecycle state (see TransactionStatus)
directionstringFund flow relative to the user: in or out
sourcestring or nullFunding source (see TransactionSource)
amountdecimalTransaction amount in the asset’s base units
assetobjectAsset involved (symbol, decimals, chain info)
walletobject or nullWallet data for crypto transactions
accountobject or nullBank account data for bank transactions
cardobject or nullCard data for card transactions
tx_hashstring or nullOn-chain transaction hash (crypto only)
merchant_namestring or nullMerchant name (card and bank transactions)
merchant_logo_urlstring or nullURL to merchant logo image
merchant_category_codestring or null4-digit ISO 18245 MCC
categorystring or nullSpending category (see TransactionCategory)
processor_referencestring or nullExternal processor transaction reference
created_atintegerTransaction creation timestamp (epoch ms)
updated_atintegerLast update timestamp (epoch ms)

Embedded Asset

Every transaction includes an asset object describing the currency or token involved:
FieldTypeDescription
idintegerInternal asset identifier
symbolstringTicker symbol (e.g., ETH, USDC, USD)
namestringHuman-readable name
asset_typestringcrypto or fiat
chain_idinteger or nullEIP-155 chain ID (null for fiat)
contract_addressstring or nullERC-20 contract address (null for native tokens and fiat)
decimalsintegerDecimal precision for formatting

Embedded Card

Present when source is card:
FieldTypeDescription
idintegerInternal card identifier
last_fourstring or nullLast 4 digits of card number
brandstring or nullCard network (visa, mastercard)
card_typestring or nullCard type (debit, credit)

Embedded Account

Present when source is bank_account:
FieldTypeDescription
external_idstringAccount identifier from open banking provider
providerstringBanking provider (plaid, truelayer)
account_typestringAccount type (checking, savings, etc.)
institution_namestringBank or financial institution name
account_namestringAccount name as shown by institution
account_maskstring or nullLast 4 digits of account number
nicknamestring or nullUser-assigned friendly name

Embedded Wallet

Present when source is crypto_wallet:
FieldTypeDescription
idintegerInternal wallet identifier
external_idstring or nullExternal wallet identifier
addressstringBlockchain address (0x-prefixed)
chain_idintegerEIP-155 chain ID
is_primarybooleanWhether this is the user’s primary wallet
is_eoabooleanTrue for externally owned accounts, false for Safe wallets

Filtering & Pagination

Query Parameters

All filters are optional and can be combined. Apply them to GET /v0/transactions.
ParameterTypeDescription
sourcestringFilter by funding source: crypto_wallet, bank_account, card
typestringFilter by transaction type (see TransactionType)
statusstringFilter by status: pending, processing, completed, failed, cancelled
directionstringFilter by direction: in or out
categorystringFilter by spending category. Comma-separated for OR logic (e.g., groceries,restaurants,coffee)
account_idstringFilter by bank account external_id
wallet_idstringFilter by wallet ID
card_idstringFilter by card ID
merchant_namestringFilter by merchant name (case-insensitive partial match)
merchant_category_codestringFilter by 4-digit MCC
amount_mindecimalMinimum transaction amount (inclusive)
amount_maxdecimalMaximum transaction amount (inclusive)
from_datestringStart date — epoch milliseconds or YYYY-MM-DD
to_datestringEnd date — epoch milliseconds or YYYY-MM-DD
offsetintegerPagination offset (default: 0)
limitintegerResults per page, 1-100 (default: 50)
metabooleanInclude 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>"

Pagination

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.

Aggregate Metadata

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": { "..." : "..." }
}
FieldTypeDescription
meta.transaction_countintegerNumber of transactions in the current page
meta.date_rangeobject or nullEarliest and latest dates in the result set (null if empty)
meta.cashflow.gross_indecimalSum of all direction: "in" amounts
meta.cashflow.gross_outdecimalSum of all direction: "out" amounts
meta.cashflow.netdecimalgross_in - gross_out
meta.categoriesarraySpending breakdown by category, sorted by total amount descending
meta.categories[].percentage_of_totaldecimalPercentage 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

GET /v0/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. The single-transaction response includes contextual links based on the transaction source:
LinkPresent WhenDescription
selfAlwaysThis transaction’s detail URL
userAlwaysOwning user’s profile
walletCrypto transactionsAssociated wallet
accountBank transactionsAssociated bank account
cardCard transactionsAssociated card
assetAsset is presentAsset details and pricing
category-transactionsCategory is setList all transactions in the same category

Integration Patterns

Building a Transaction Feed UI

  1. Fetch the first page: GET /v0/transactions?limit=50
  2. Render each transaction using type, direction, and source to select icons and labels
  3. Use merchant_name and merchant_logo_url for card/bank transactions; use asset.symbol and tx_hash for crypto transactions
  4. Implement infinite scroll by following the next link in _links
  5. 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"
    }
  ]
}
StatusError CodeMeaning
400 Bad RequestTXN-400-001Invalid query parameter (see invalid_params for details)
400 Bad RequestTXN-400-002amount_min is greater than amount_max
401 UnauthorizedMissing or invalid authentication token
403 ForbiddenTXN-403-001Transaction belongs to a different user
404 Not FoundTXN-404-001Transaction with the given external_id does not exist
500 Internal Server ErrorTXN-500-001Transaction is missing required asset data (should not occur in normal operation)

Reference Tables

Transaction Types

ValueSourceDescription
depositCryptoIncoming transfer to user’s wallet from external source
withdrawalCryptoOutgoing transfer from user’s wallet to external address
transferCryptoInternal movement between user’s own wallets
swapCryptoToken exchange (e.g., ETH to USDC)
on_rampCryptoFiat-to-crypto conversion via exchange/provider
off_rampCryptoCrypto-to-fiat conversion via exchange/provider
card_purchaseCardDebit card spend at merchant
card_refundCardMerchant-initiated refund to card
bank_transferBankACH/wire transfer between accounts
direct_debitBankRecurring automated payment (bills, subscriptions)
standing_orderBankScheduled fixed payment
bank_paymentBankOne-time outgoing payment
bank_refundBankReturn of funds to bank account
interestBankInterest credit on savings/checking account
feeBankBank service charge or maintenance fee

Transaction Statuses

ValueDescription
pendingCreated but not yet submitted for processing
processingSubmitted to network/provider, awaiting confirmation
completedSuccessfully finalized (on-chain confirmed or bank settled)
failedRejected or reverted (check error details)
cancelledCancelled by user or system before completion

Transaction Directions

ValueDescription
inFunds entering the user’s account (credits, deposits, refunds)
outFunds 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.
ValueDescription
restaurantsFull-service dining establishments
foodGeneral food and beverage (fast food, takeout)
groceriesSupermarkets and grocery stores
coffeeCoffee shops and cafes
shoppingGeneral retail and e-commerce
utilitiesElectric, gas, water, internet services
transportRide-share, public transit, parking, fuel
entertainmentMovies, concerts, streaming services
subscriptionsRecurring digital services and memberships

Transaction Sources

ValueDescription
crypto_walletOn-chain transaction from user’s EOA or Safe wallet
bank_accountACH/wire transfer from linked bank account
cardDebit card purchase or refund

Next Steps