Last Updated: February 11, 2026
Base URL: https://api.trupocket.app/v1
Authentication: Personal Access Tokens (PATs) via Bearer header
Response Format: JSON
Currency: Integers in cents (1234 = $12.34)
Timestamps: Unix timestamps (seconds since epoch)
Documentation: Full API Reference | Privacy Policy | Terms of Service
Welcome developers! This guide will help you get started with the Trupocket API.
Authorization header for all API requestsPATs provide long-lived API access for all use cases. Ideal for scripts, CI/CD, server-to-server integrations, and general API usage.
tp_ prefix followed by 64 hexadecimal characterstp_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2Create a PAT from the Trupocket web app settings, or via the API (requires an existing PAT):
POST /v1/users/access-tokens
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
{
"name": "My Integration",
"expiresAt": 1767225600
}
# expiresAt is optional (Unix timestamp). Omit for tokens that never expire.
# Response (201):
{
"tokenID": "2BKHGx7z0pFFRyqPqQqRbCPp9xI",
"name": "My Integration",
"token": "tp_a1b2c3d4e5f6...",
"tokenPrefix": "tp_a1b2c3d4",
"expiresAt": 1767225600,
"createdAt": 1704067200
}
# IMPORTANT: The "token" field is only returned at creation!
# Copy and store it securely - you cannot retrieve it later.
curl -X GET "https://api.trupocket.app/v1/households" \
-H "Authorization: Bearer tp_your_personal_access_token_here"
# List all PATs
GET /v1/users/access-tokens
# Response:
{
"accessTokens": [
{
"tokenID": "2BKHGx7z0pFFRyqPqQqRbCPp9xI",
"name": "My Integration",
"tokenPrefix": "tp_a1b2c3d4",
"isActive": true,
"expiresAt": 1767225600,
"lastUsedAt": 1704153600,
"createdAt": 1704067200
}
],
"total": 1,
"limit": 3
}
# Update a PAT (rename, deactivate, or change expiration)
PATCH /v1/users/access-tokens/{tokenID}
{
"name": "Renamed Integration",
"isActive": false
}
# Delete a PAT
DELETE /v1/users/access-tokens/{tokenID}
GET /v1/users/access-tokensBase URL: https://api.trupocket.app/v1
Response Format: JSON
Date/Time Format: Unix timestamps (seconds since epoch)
Currency Format: Integers in smallest denomination (cents for USD)
| Plan | API Calls/Day | Transactions/Month | Households | Data History | Webhooks |
|---|---|---|---|---|---|
| Free | 20 | 60 | 1 | 90 days | No |
| Premium | 1,000 | Unlimited | Unlimited | 2 years | No |
| Developer | 10,000 | Unlimited | Unlimited | Unlimited | Yes |
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 847
X-RateLimit-Reset: 1699564800
User
└── Household(s)
├── Accounts (checking, savings, credit cards)
├── Categories (for budgeting)
├── Payees (merchants, employers)
├── Hashtags (custom tags)
├── Transactions
│ ├── Transaction Categories (split transactions)
│ └── Transaction Hashtags
└── Scheduled Transactions (recurring transactions)
0 (Detailed Tracking) - Full transaction register with budgeting0 (home) - Personal finances1 (office) - Business finances2 (home_office) - Mixed (sole proprietor, freelancer)chkg - Checking accountsvgs - Savings accountcc - Credit cardexpense - Money outincome - Money intransfer - Between your accountsHashtags are a powerful dynamic categorization tool that goes beyond traditional categories and budgets.
What are Hashtags?
Hashtags allow you to tag transactions with custom labels by including #hashtag in transaction memos. Unlike categories (which are budget-focused), hashtags provide flexible, cross-category grouping for analysis and reporting.
How Hashtags Work:
"Dinner with clients #business #taxdeductible"Categories vs Hashtags:
| Feature | Categories | Hashtags |
|---|---|---|
| Purpose | Budget tracking | Flexible grouping & analysis |
| Setup | Must create before use | Auto-created on first use |
| Per Transaction | 1-5 categories (required) | Unlimited hashtags (optional) |
| Budget Impact | Affects budget calculations | No budget impact |
| Use Cases | Monthly budgets, spending limits | Projects, tax tracking, trips, clients |
Common Use Cases:
#taxdeductible, #business, #charitable#kitchen-remodel, #wedding, #vacation2024#client-acme, #client-techcorp#birthday, #conference, #holiday#roommate, #reimbursable#savingforhouse, #debtpayoffExample Transaction with Hashtags:
{
"payee": "Home Depot",
"categories": [
{
"name": "Home Improvement",
"amount": 25000,
"memo": "Kitchen backsplash materials #kitchen-remodel #taxdeductible",
"dontImpactBudget": false,
"isCleared": true
}
]
}
# This transaction:
# - Budgeted under "Home Improvement" category
# - Tagged for project tracking (#kitchen-remodel)
# - Tagged for tax purposes (#taxdeductible)
# - Can be filtered/reported on by either hashtag
Filtering by Hashtags:
# Get all transactions for kitchen remodel project
GET /v1/households/{householdID}/detailed-tracking/transactions?hashtags=kitchen-remodel
# Get all tax-deductible transactions
GET /v1/households/{householdID}/detailed-tracking/transactions?hashtags=taxdeductible
# Get transactions for multiple projects
GET /v1/households/{householdID}/detailed-tracking/transactions?hashtags=kitchen-remodel,vacation2024
Pro Tips:
#vacation-hawaii-2024 instead of #trip#needreceipt, #verify# 1. Create an account at https://trupocket.app
# 2. Go to Settings > Access Tokens
# 3. Create a new Personal Access Token (PAT)
# 4. Copy and store the token securely - it's only shown once!
# Use your PAT in all API requests:
curl -X GET "https://api.trupocket.app/v1/users/who-am-i" \
-H "Authorization: Bearer tp_your_personal_access_token_here"
# Response:
{
"userID": "2BxFGhvDwSoabBEqf2V5ZgC3ifo",
"firstName": "John",
"email": "john@example.com",
"planID": "free"
}
POST /v1/households
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
{
"name": "Personal Finances",
"style": "dt",
"purpose": "home"
}
# Response:
{
"householdID": "2BKHJyVqwTkR1234567890ABCDE"
}
POST /v1/households/{householdID}/detailed-tracking/accounts
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
{
"type": "chkg",
"name": "Chase Checking",
"balance": 500000
}
# balance: 500000 = $5,000.00
# Response:
{
"accountID": "2BKHLmNpqRsTuvWxYzAbCdEfGhI"
}
POST /v1/households/{householdID}/detailed-tracking/categories
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
{
"name": "Groceries",
"budgetAmount": 40000
}
# budgetAmount: 40000 = $400.00/month
# Response:
{
"categoryID": "2BKHMnOpQrStUvWxYzAbCdEfGhI"
}
POST /v1/households/{householdID}/detailed-tracking/payees
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
{
"name": "Whole Foods"
}
# Response:
{
"payeeID": "2BKHOpQrStUvWxYzAbCdEfGhIjK"
}
POST /v1/households/{householdID}/detailed-tracking/transactions
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
{
"cashflow": "expense",
"type": "debit_credit",
"fromAccountID": "YOUR_ACCOUNT_ID",
"payee": "Whole Foods",
"date": 1699564800,
"categories": [
{
"name": "Groceries",
"amount": 8547,
"memo": "Weekly groceries #organic",
"dontImpactBudget": false,
"isCleared": true
}
]
}
# date: Unix timestamp for transaction date
# amount: 8547 = $85.47
# payee: Payee name (string, not ID)
# categories[].name: Category name (string, not ID)
# dontImpactBudget: false means this WILL impact the budget
# isCleared: true means this transaction has cleared the bank
# Transaction reduces account balance by $85.47
# Transaction reduces budget balance by $85.47
# Response:
{
"transactionID": "2BKHPqRsTuVwXyZaBcDeFgHiJkL",
"totalAmount": {
"currency": "USD",
"amount": 8547
}
}
# When you receive 401 Unauthorized:
# - If using a PAT: check that it hasn't been deactivated or expired
# - Generate a new PAT from the Trupocket web app if needed
# - PATs without an expiration date never expire unless manually deactivated
GET /v1/households/{householdID}
Authorization: Bearer YOUR_ACCESS_TOKEN
# Returns household with accounts, budgets, etc.
GET /v1/households/{householdID}/detailed-tracking/transactions
Authorization: Bearer YOUR_ACCESS_TOKEN
# Optional filters:
# ?accounts={accountID}
# ?categories={categoryID}
# ?fromDate={YYYY-MM-DD}
# ?toDate={YYYY-MM-DD}
GET /v1/households/{householdID}/detailed-tracking/accounts/{accountID}
Authorization: Bearer YOUR_ACCESS_TOKEN
# Returns account with current balance
GET /v1/households/{householdID}/detailed-tracking/categories
Authorization: Bearer YOUR_ACCESS_TOKEN
# Returns all categories with budget details:
# - budget.amount (allocated)
# - budget.balance (remaining)
POST /v1/households/{householdID}/detailed-tracking/scheduled-transactions
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
{
"cashflow": "expense",
"type": "ach",
"fromAccountID": "YOUR_ACCOUNT_ID",
"payee": "Rent Company",
"frequency": 4,
"frequencyDay": 1,
"startDate": 1699564800,
"shouldAutoGenerate": true,
"categories": [
{
"name": "Rent",
"amount": 150000,
"memo": "Monthly rent",
"impactBudget": true
}
]
}
# payee: Payee name (string, not ID)
# frequency: 4 = monthly
# frequencyDay: 1 = 1st of month
# startDate: Unix timestamp for when schedule begins
# shouldAutoGenerate: true = automatically create transactions
# categories[].name: Category name (string, not ID)
# amount: 150000 = $1,500.00
# impactBudget: true = this WILL impact the budget (scheduled uses impactBudget, not dontImpactBudget)
200 - Success201 - Created400 - Bad Request (validation error)401 - Unauthorized (invalid/expired token)403 - Forbidden (insufficient permissions)404 - Not Found429 - Too Many Requests (rate limit exceeded)500 - Internal Server ErrorAll API errors return a flat JSON structure with the following fields:
errorCode - Machine-readable error code (lowercase-kebab-case)errorMessage - Human-readable error descriptionerrorField - Field that caused the error (null if not field-specific){
"errorCode": "validation-error",
"errorMessage": "Invalid email format",
"errorField": "email"
}
| Error Code | Description | Solution |
|---|---|---|
unauthorized |
Invalid or expired token | Check PAT is active and not expired, or generate a new one |
rate-limit-exceeded |
Too many API calls | Wait for rate limit reset or upgrade plan |
validation-error |
Invalid request data | Check field requirements |
not-found |
Resource doesn't exist | Verify IDs are correct |
plan-limit-exceeded |
Exceeded plan limits | Upgrade to higher plan |
The simplest way to use the API is with Personal Access Tokens. No token refresh logic needed.
const axios = require('axios');
const API_BASE = 'https://api.trupocket.app/v1';
const PAT = process.env.TRUPOCKET_PAT; // Store in environment variable
const client = axios.create({
baseURL: API_BASE,
headers: {
'Authorization': `Bearer ${PAT}`,
'Content-Type': 'application/json'
}
});
// List households
const { data } = await client.get('/households');
console.log('Households:', data.households);
// Create a transaction
const transaction = await client.post(
`/households/${householdId}/detailed-tracking/transactions`,
{
cashflow: 'expense',
type: 'debit_credit',
fromAccountID: accountId,
payee: 'Coffee Shop',
date: Math.floor(Date.now() / 1000),
categories: [{ name: 'Food', amount: 500, memo: 'Morning coffee' }]
}
);
console.log('Created:', transaction.data.transactionID);
import os
import requests
import time
API_BASE = 'https://api.trupocket.app/v1'
PAT = os.environ['TRUPOCKET_PAT'] # Store in environment variable
headers = {
'Authorization': f'Bearer {PAT}',
'Content-Type': 'application/json'
}
# List households
response = requests.get(f'{API_BASE}/households', headers=headers)
print('Households:', response.json()['households'])
# Create a transaction
transaction = requests.post(
f'{API_BASE}/households/{household_id}/detailed-tracking/transactions',
headers=headers,
json={
'cashflow': 'expense',
'type': 'debit_credit',
'fromAccountID': account_id,
'payee': 'Coffee Shop',
'date': int(time.time()),
'categories': [{'name': 'Food', 'amount': 500, 'memo': 'Morning coffee'}]
}
)
print('Created:', transaction.json()['transactionID'])
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"time"
)
const APIBase = "https://api.trupocket.app/v1"
type TrupocketClient struct {
PAT string
}
type TransactionRequest struct {
Cashflow string `json:"cashflow"`
Type string `json:"type"`
FromAccountID string `json:"fromAccountID"`
Payee string `json:"payee"`
Date int64 `json:"date"`
Categories []TransactionCategory `json:"categories"`
}
type TransactionCategory struct {
Name string `json:"name"`
Amount int64 `json:"amount"`
Memo string `json:"memo"`
DontImpactBudget bool `json:"dontImpactBudget"`
IsCleared bool `json:"isCleared"`
}
func NewTrupocketClient(pat string) *TrupocketClient {
return &TrupocketClient{PAT: pat}
}
func (c *TrupocketClient) makeRequest(method, endpoint string, body io.Reader) (*http.Response, error) {
req, err := http.NewRequest(method, APIBase+endpoint, body)
if err != nil {
return nil, err
}
req.Header.Set("Authorization", "Bearer "+c.PAT)
req.Header.Set("Content-Type", "application/json")
return (&http.Client{}).Do(req)
}
func (c *TrupocketClient) CreateTransaction(householdID, accountID, categoryName, payeeName string) error {
txn := TransactionRequest{
Cashflow: "expense",
Type: "debit_credit",
FromAccountID: accountID,
Payee: payeeName,
Date: time.Now().Unix(),
Categories: []TransactionCategory{
{
Name: categoryName,
Amount: 5000,
Memo: "Lunch",
DontImpactBudget: false,
IsCleared: true,
},
},
}
body, _ := json.Marshal(txn)
resp, err := c.makeRequest("POST", fmt.Sprintf("/households/%s/detailed-tracking/transactions", householdID), bytes.NewBuffer(body))
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusTooManyRequests {
return fmt.Errorf("rate limit exceeded")
} else if resp.StatusCode != http.StatusCreated {
return fmt.Errorf("unexpected status: %d", resp.StatusCode)
}
fmt.Println("Transaction created successfully")
return nil
}
func main() {
client := NewTrupocketClient(os.Getenv("TRUPOCKET_PAT"))
// List households
resp, err := client.makeRequest("GET", "/households", nil)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println("Status:", resp.StatusCode)
}
Coming Soon: Webhooks will allow you to receive real-time notifications when events occur in Trupocket. The following shows the planned webhook format.
transaction.createdtransaction.updatedtransaction.deletedaccount.updatedbudget.exceededscheduled_transaction.generatedWhen implemented, webhook payloads will follow this structure:
{
"event": "transaction.created",
"timestamp": 1699564800,
"data": {
"householdID": "2BxFGhvDwSoabBEqf2V5ZgC3ifo",
"transactionID": "2BxFGi9K3xyMp6QwVN8ZjR4LaPn",
"amount": 5000,
"cashflow": "expense"
}
}
Math.floor(dollars * 100)cents / 100isCleared field for tracking cleared/pending transactionsX-RateLimit-Remaining header before bulk operationsRecommended Next Steps: