Trupocket

Getting Started Guide

Last Updated: February 11, 2026

🚀 Quick Start

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

Table of Contents

1. Introduction

Welcome developers! This guide will help you get started with the Trupocket API.

What is Trupocket?

Quick Links


2. Authentication

Getting Started

  1. Create an account at trupocket.app
  2. Generate a Personal Access Token (PAT) from your account settings in the web app
  3. Use the PAT in the Authorization header for all API requests

Personal Access Tokens (Recommended)

PATs provide long-lived API access for all use cases. Ideal for scripts, CI/CD, server-to-server integrations, and general API usage.

Token Format

Plan Limits

Creating a PAT

Create a PAT from the Trupocket web app settings, or via the API with an existing unscoped PAT (a scoped token cannot create tokens):

POST /v1/users/access-tokens
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{
  "name": "My Integration",
  "expiresAt": 1767225600,
  "scopes": ["trupocket-api/read", "trupocket-api/write"]
}

# expiresAt is optional (Unix timestamp). Omit for tokens that never expire.
# scopes is optional. Omit it for an unscoped token with full access.

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

Scoped Tokens

Using a PAT

curl -X GET "https://api.trupocket.app/v1/households" \
  -H "Authorization: Bearer tp_your_personal_access_token_here"

Managing PATs

# 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 or deactivate). Expiration is not editable —
# use the regenerate endpoint below to change it.
PATCH /v1/users/access-tokens/{tokenID}
{
  "name": "Renamed Integration",
  "isActive": false
}

# Regenerate a PAT (rotate the secret value; tokenID is preserved)
# The old token is invalidated immediately. The new full token value
# is returned only once in the response — store it before you reload.
# Omit "expiresAt" for no expiration; provide it to set a new one.
POST /v1/users/access-tokens/{tokenID}/regenerate
{
  "expiresAt": 1767225600
}

# Delete a PAT
DELETE /v1/users/access-tokens/{tokenID}

PAT Security Best Practices

Connecting an AI Assistant (MCP & OAuth One-Click)

Trupocket runs a Model Context Protocol (MCP) server so AI assistants (Claude, ChatGPT, Copilot, Gemini CLI, and any MCP-compatible client) can securely read a household's finances — and, on a write-capable plan, record to them. One URL, https://api.trupocket.app/v1/mcp, serves every household the user belongs to: the assistant calls list_households first, and every other tool takes the household_id it returns. There are two ways to connect:

MCP access requires a Premium, Pro, Developer, or Enterprise plan. The read tools are available on every one of those plans. The create, update, and delete tools require a Pro, Developer, or Enterprise plan and a scope grant. The scopes are cumulative: trupocket-api/read covers the read tools, trupocket-api/write the create and update tools, and trupocket-api/delete the destructive delete_* tools. trupocket-api/write and trupocket-api/delete must each be asked for by name, and naming delete grants write along with it; trupocket-api/read is always granted on the OAuth flow whether or not you list it, and is required in a Personal Access Token's scopes array. Write does not imply delete — an assistant granted write can record a transaction but cannot erase an account. The plan is checked per household: a user with a Pro household and a Premium household sees the create and update tools, and a call that targets the Premium household is refused with a message naming the plan it needs.

An OAuth client asks for what it needs by naming the scopes in its authorization request (scope=openid email profile trupocket-api/read trupocket-api/write); leave them out and the token is read-only. An MCP client that discovers Trupocket through the 401 challenge does not leave them out — the challenge names trupocket-api/read trupocket-api/write, so a one-click connection requests write by default and the consent screen says so. The consent screen also offers a Connect read-only option, which restarts the authorization asking for read alone. trupocket-api/delete is never named in the challenge and must always be requested deliberately. A Personal Access Token created without a scopes grant is unscoped and keeps full access to everything the plan permits — the behavior of every token created before scopes existed. A PAT created with a grant is gated on the REST and MCP surfaces exactly like an OAuth token.

Scopes gate ordinary REST calls, not just MCP tools. Over REST the required tier follows the HTTP method — trupocket-api/read for GET, trupocket-api/write for POST, PUT and PATCH, trupocket-api/delete for DELETE — with a handful of operations classified by what they actually do rather than by their method. A call outside the grant is refused with 403 insufficient-scope. Over MCP the same grant instead decides which tools are registered, so a client that fails that gate simply does not see those tools in tools/list. Web sessions and unscoped PATs are subject to neither gate. A handful of account operations — changing the email, billing sessions, household invitations, and token management — accept no scoped token at all and return 403 unscoped-credential-required.

Every write an assistant makes is recorded in a per-household audit trail — what tool ran, what changed, and whether it succeeded — readable at GET /v1/households/{householdID}/detailed-tracking/mcp/activity. See the Assistant Activity specification.


3. API Overview

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)

Rate Limits by Plan

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
Pro 5,000 Unlimited Unlimited Unlimited No
Developer 10,000 Unlimited Unlimited Unlimited Yes

Rate Limit Headers

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 847
X-RateLimit-Reset: 1699564800

4. Core Concepts

Hierarchy

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)

Household Styles

Household Purpose

Account Types

Transaction Cashflow

💡 Hashtags: Dynamic Transaction Grouping

Hashtags 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:

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:

Example 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:


5. Quick Start Tutorial

Step 1: Get Your Access Token

# 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"
}

Step 2: Create a Household

POST /v1/households
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{
  "name": "Personal Finances",
  "style": "dt",
  "purpose": "home"
}

# Response:
{
  "householdID": "2BKHJyVqwTkR1234567890ABCDE"
}

Step 3: Create a Checking Account

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"
}

Step 4: Create a Category

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"
}

Step 5: Create a Payee

POST /v1/households/{householdID}/detailed-tracking/payees
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{
  "name": "Whole Foods"
}

# Response:
{
  "payeeID": "2BKHOpQrStUvWxYzAbCdEfGhIjK"
}

Step 6: Create a Transaction

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
  }
}

6. Common Workflows

Handle Expired or Invalid Token

# 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 Household Summary

GET /v1/households/{householdID}
Authorization: Bearer YOUR_ACCESS_TOKEN

# Returns household with accounts, budgets, etc.

List All Transactions

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 Account Balance

GET /v1/households/{householdID}/detailed-tracking/accounts/{accountID}
Authorization: Bearer YOUR_ACCESS_TOKEN

# Returns account with current balance

Get Budget Status

GET /v1/households/{householdID}/detailed-tracking/categories
Authorization: Bearer YOUR_ACCESS_TOKEN

# Returns all categories with budget details:
# - budget.amount (allocated)
# - budget.balance (remaining)

Create Scheduled Transaction (Recurring Bill)

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": "monthly",
  "frequencyDay": 1,
  "startDate": 1699564800,
  "shouldAutoGenerate": true,
  "categories": [
    {
      "name": "Rent",
      "amount": 150000,
      "memo": "Monthly rent",
      "impactBudget": true
    }
  ]
}

# payee: Payee name (string, not ID)
# frequency: string enum, not a number (one_time, weekly, bi_weekly, twice_monthly,
#            monthly, quarterly, bi_annually, annually, every_n_days)
# frequencyDay: 1 = 1st of month
# startDate: Unix timestamp for when schedule begins
# shouldAutoGenerate: true = automatically create transactions (omit and it defaults to false)
# categories[].name: Category name (string, not ID)
# amount: 150000 = $1,500.00
# impactBudget: true = this WILL impact the budget (scheduled uses impactBudget, not dontImpactBudget)

7. Error Handling

HTTP Status Codes

Error Response Format

All API errors return a flat JSON structure with the following fields:

For example, POST /v1/households without a name returns 400 with:

{
  "errorCode": "no-name-provided",
  "errorMessage": "Please specify the name of your household",
  "errorField": "name"
}

Common Errors

Error Code Description Solution
no-authorization-header 401 - No Authorization header was sent Send Authorization: Bearer YOUR_ACCESS_TOKEN with every authenticated request
invalid-token 401 - The OAuth token is invalid or expired, or the header is not a Bearer credential Sign in again for a fresh token, and check the header reads Bearer <token>
invalid-access-token, access-token-inactive, access-token-expired 401 - The personal access token is not recognized, has been deactivated, or has expired Check the PAT is active and not expired, or generate a new one
rate-limit-exceeded 429 - Too many API calls On authenticated endpoints, wait for the rate limit reset or upgrade your plan. On the unauthenticated OAuth endpoints (/oauth/register, /oauth/authorize) this is the 20/day per-IP cap - wait for midnight UTC or authenticate; upgrading your plan does not raise it
invalid-request-body 400 - The request body is empty or invalid: it is not valid JSON, or a value has the wrong type or is not one of the allowed values Check the body against the operation's schema in the API reference. Field-level validation failures return their own codes, with errorField naming the field
household-not-found 404 - The household does not exist, or you are not a member of it. Other resources return their own codes, such as account-not-found Verify the IDs are correct; GET /v1/households lists the households you can use
plan-limit-exceeded 402 - Exceeded plan limits Upgrade to higher plan
insufficient-scope 403 - A scoped token lacks the scope this operation needs Re-authorize, or create a new token, with the required scope
unscoped-credential-required 403 - The operation accepts no scoped token (account email, billing, invitations, token management) Use the web app or a PAT created without scopes

8. Code Examples

Quick Start with PATs (Recommended)

The simplest way to use the API is with Personal Access Tokens. No token refresh logic needed.

JavaScript/Node.js with PAT

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

Python with PAT

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'])

Go

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

9. Webhooks (Developer Plan)

Coming Soon: Webhooks will allow you to receive real-time notifications when events occur in Trupocket. The following shows the planned webhook format.

Planned Webhook Events

Planned Webhook Payload Format

When implemented, webhook payloads will follow this structure:

{
  "event": "transaction.created",
  "timestamp": 1699564800,
  "data": {
    "householdID": "2BxFGhvDwSoabBEqf2V5ZgC3ifo",
    "transactionID": "2BxFGi9K3xyMp6QwVN8ZjR4LaPn",
    "amount": 5000,
    "cashflow": "expense"
  }
}

10. Best Practices

1. Authentication & Token Management

2. Currency Handling

3. Timezone Handling

4. Transaction Balancing

5. Rate Limiting

6. Error Recovery

7. Security

8. Data Validation

9. Performance


11. Testing & Development

Testing Checklist

Debugging Tips


12. API Limits & Quotas

Free Plan

Premium Plan ($2.99/mo)

Pro Plan ($9.99/mo)

Developer Plan ($29.99/mo)

Exceeding Limits

Response Compression

Responses support gzip and zstd compression, which materially shrinks large payloads (e.g. reports). Send an Accept-Encoding: gzip or Accept-Encoding: zstd header to opt in; the server negotiates automatically and only compresses responses large enough to benefit. Most HTTP clients (browsers, fetch, requests) advertise this and decode it transparently — no extra work. If you set Accept-Encoding by hand on a raw client, you must decode the response body yourself; with curl, prefer curl --compressed.


13. Support & Resources

Documentation

Support

Stay Updated

What's Next?

Recommended Next Steps:

  1. Review full API documentation at /docs
  2. Create an account at trupocket.app and generate a PAT
  3. Build a simple integration following the Quick Start Tutorial
  4. Explore scheduled transactions for recurring bills
  5. Implement webhooks (Developer plan)

Need Help?