Last Updated: November 17, 2025
Base URL: https://api.trupocket.app/v1
Authentication: OAuth 2.0 Bearer tokens (1-hour expiration)
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.
Trupocket uses OAuth 2.0 for secure authentication.
/v1/users/register endpoint/v1/users/sign-in endpointAuthorization header401 Unauthorized responsePOST /v1/users/register
Content-Type: application/json
{
"firstName": "John",
"email": "john@example.com",
"password": "SecurePassword123!",
"agreeToTerms": true
}
# Response:
{
"userID": "2BKHGx7z0pFFRyqPqQqRbCPp9xI"
}
# Email verification required before sign-in
POST /v1/users/sign-in
Content-Type: application/json
{
"email": "john@example.com",
"password": "SecurePassword123!"
}
# Response:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expiresIn": 3600
}
curl -X GET "https://api.trupocket.app/v1/households" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN_HERE"
When your access token expires (after 1 hour), you'll receive:
{
"error": {
"code": "UNAUTHORIZED",
"message": "Token expired or invalid"
}
}
Simply sign in again to get a new token:
POST /v1/users/sign-in
Content-Type: application/json
{
"email": "john@example.com",
"password": "SecurePassword123!"
}
Base 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, #verifyPOST /v1/users/register
Content-Type: application/json
{
"firstName": "John",
"email": "john@example.com",
"password": "SecurePassword123!",
"agreeToTerms": true
}
# Response:
{
"userID": "2BxFGhvDwSoabBEqf2V5ZgC3ifo"
}
# Note: Email verification required before sign-in
POST /v1/users/sign-in
Content-Type: application/json
{
"email": "john@example.com",
"password": "SecurePassword123!"
}
# Response:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expiresIn": 3600
}
POST /v1/households
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
{
"name": "Personal Finances",
"style": 0,
"purpose": 0
}
# 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"
}
# When you receive 401 Unauthorized:
POST /v1/users/sign-in
Content-Type: application/json
{
"email": "john@example.com",
"password": "SecurePassword123!"
}
# Get new access_token and continue
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 Error{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request data",
"details": [
{
"field": "email",
"message": "Invalid email format"
}
]
}
}
| Error Code | Description | Solution |
|---|---|---|
UNAUTHORIZED |
Invalid or expired token | Sign in again to get new token |
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 |
const axios = require('axios');
const API_BASE = 'https://api.trupocket.app/v1';
let accessToken = null;
const userEmail = 'john@example.com';
const userPassword = 'SecurePassword123!';
// Sign in and get access token
async function signIn() {
try {
const response = await axios.post(`${API_BASE}/users/sign-in`, {
email: userEmail,
password: userPassword
});
accessToken = response.data.token;
console.log('Signed in successfully');
return accessToken;
} catch (error) {
console.error('Sign in failed:', error.response?.data);
throw error;
}
}
// Create a transaction with automatic re-authentication
async function createTransaction(householdId, accountId, categoryName, payeeName) {
try {
const response = await axios.post(
`${API_BASE}/households/${householdId}/detailed-tracking/transactions`,
{
cashflow: 'expense',
type: 'debit_credit',
fromAccountID: accountId,
payee: payeeName,
date: Math.floor(Date.now() / 1000),
categories: [
{
name: categoryName,
amount: 5000,
memo: 'Lunch',
dontImpactBudget: false,
isCleared: true
}
]
},
{
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
}
}
);
console.log('Transaction created:', response.data);
return response.data;
} catch (error) {
if (error.response?.status === 401) {
// Token expired - sign in again and retry
console.log('Token expired, re-authenticating...');
await signIn();
return createTransaction(householdId, accountId, categoryName, payeeName);
} else if (error.response?.status === 429) {
console.error('Rate limit exceeded');
} else {
console.error('Error:', error.response?.data);
}
throw error;
}
}
// Initialize
signIn().then(() => {
console.log('Ready to make API calls');
});
import requests
import time
API_BASE = 'https://api.trupocket.app/v1'
class TrupocketClient:
def __init__(self, email, password):
self.email = email
self.password = password
self.access_token = None
self.sign_in()
def sign_in(self):
"""Sign in and get access token"""
response = requests.post(
f'{API_BASE}/users/sign-in',
json={
'email': self.email,
'password': self.password
}
)
if response.status_code == 200:
self.access_token = response.json()['token']
print('Signed in successfully')
else:
raise Exception(f'Sign in failed: {response.json()}')
def _make_request(self, method, endpoint, **kwargs):
"""Make API request with automatic re-authentication"""
headers = {
'Authorization': f'Bearer {self.access_token}',
'Content-Type': 'application/json'
}
response = requests.request(
method,
f'{API_BASE}{endpoint}',
headers=headers,
**kwargs
)
# If token expired, re-authenticate and retry
if response.status_code == 401:
print('Token expired, re-authenticating...')
self.sign_in()
headers['Authorization'] = f'Bearer {self.access_token}'
response = requests.request(
method,
f'{API_BASE}{endpoint}',
headers=headers,
**kwargs
)
return response
def create_transaction(self, household_id, account_id, category_name, payee_name):
"""Create a transaction"""
payload = {
'cashflow': 'expense',
'type': 'debit_credit',
'fromAccountID': account_id,
'payee': payee_name,
'date': int(time.time()),
'categories': [
{
'name': category_name,
'amount': 5000,
'memo': 'Lunch',
'dontImpactBudget': False,
'isCleared': True
}
]
}
response = self._make_request('POST', f'/households/{household_id}/detailed-tracking/transactions', json=payload)
if response.status_code == 201:
print('Transaction created:', response.json())
return response.json()
elif response.status_code == 429:
print('Rate limit exceeded')
else:
print('Error:', response.json())
response.raise_for_status()
# Usage
client = TrupocketClient('john@example.com', 'SecurePassword123!')
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
const APIBase = "https://api.trupocket.app/v1"
type TrupocketClient struct {
Email string
Password string
AccessToken string
}
type SignInRequest struct {
Email string `json:"email"`
Password string `json:"password"`
}
type SignInResponse struct {
Token string `json:"token"`
ExpiresIn int `json:"expiresIn"`
}
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(email, password string) (*TrupocketClient, error) {
client := &TrupocketClient{
Email: email,
Password: password,
}
if err := client.SignIn(); err != nil {
return nil, err
}
return client, nil
}
func (c *TrupocketClient) SignIn() error {
req := SignInRequest{
Email: c.Email,
Password: c.Password,
}
body, _ := json.Marshal(req)
resp, err := http.Post(
APIBase+"/users/sign-in",
"application/json",
bytes.NewBuffer(body),
)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("sign in failed: %d", resp.StatusCode)
}
var signInResp SignInResponse
if err := json.NewDecoder(resp.Body).Decode(&signInResp); err != nil {
return err
}
c.AccessToken = signInResp.Token
fmt.Println("Signed in successfully")
return nil
}
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.AccessToken)
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
// If token expired, re-authenticate and retry
if resp.StatusCode == http.StatusUnauthorized {
resp.Body.Close()
fmt.Println("Token expired, re-authenticating...")
if err := c.SignIn(); err != nil {
return nil, err
}
// Retry request with new token
req.Header.Set("Authorization", "Bearer "+c.AccessToken)
return client.Do(req)
}
return resp, nil
}
func (c *TrupocketClient) CreateTransaction(householdID, accountID, categoryName, payeeName string) error {
req := 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(req)
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, err := NewTrupocketClient("john@example.com", "SecurePassword123!")
if err != nil {
panic(err)
}
// Now ready to make API calls
fmt.Println("Ready to make API calls")
}
Coming Soon: Webhooks allow you to receive real-time notifications when events occur in Trupocket.
transaction.createdtransaction.updatedtransaction.deletedaccount.updatedbudget.exceededscheduled_transaction.generated{
"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: