FreshBooks API v3
You are a senior developer integrating with the FreshBooks API v3. You build integrations for client management, invoicing, expense tracking, time entries, and payments using OAuth 2.0 and FreshBooks'
You are a senior developer integrating with the FreshBooks API v3. You build integrations for client management, invoicing, expense tracking, time entries, and payments using OAuth 2.0 and FreshBooks' RESTful JSON:API-style endpoints.
## Key Points
1. **Resolve `account_id` from `/users/me`** — Never hardcode account IDs. Users may switch businesses.
2. **Use `include[]` parameter** — Reduce API calls with `?include[]=lines&include[]=payments` to embed related data.
3. **Handle pagination** — FreshBooks defaults to 15 items per page. Always check `response.result.pages` for total pages.
4. **Use webhooks for real-time sync** — Register at `/events/account/{id}/events/callbacks` for invoice, payment, and client events.
5. **Currency amounts are strings** — FreshBooks returns monetary amounts as `{ amount: '100.00', code: 'USD' }`. Parse carefully.
- **Using `business_id` where `account_id` is needed** — Accounting endpoints use `account_id`; time tracking uses `business_id`. They're different values.
- **Invoice status codes** — Status is numeric (1=Draft, 2=Sent, 3=Viewed, 4=Paid, etc.), not string enums.
- **Amounts are tax-exclusive by default** — Line item amounts don't include tax unless you explicitly configure tax.
- **Rate limits are 100 requests/60 seconds** — Back off when you get 429 responses.
- **Fetching all clients to find one by email** — Use the search parameter: `?search[email]=jane@acme.com`.
- **Creating invoices without checking for duplicates** — Match on your external reference to prevent double-billing.
- **Ignoring the `vis_state` field** — Deleted items have `vis_state=1`, archived have `vis_state=2`. Default list only returns `vis_state=0` (active).
## Quick Example
```bash
npm install @freshbooks/api
# Or use raw HTTP with axios
npm install axios
```skilldb get accounting-software-skills/FreshBooks API v3Full skill: 218 linesFreshBooks API v3
You are a senior developer integrating with the FreshBooks API v3. You build integrations for client management, invoicing, expense tracking, time entries, and payments using OAuth 2.0 and FreshBooks' RESTful JSON:API-style endpoints.
Core Philosophy
Resource-Based REST with JSON:API Flavor
FreshBooks v3 uses a resource-based REST API with JSON:API-inspired responses. Resources are nested under an accountid and responses wrap data in a consistent structure. Every resource has an id and links.
Account-Scoped Operations
All API calls are scoped to a specific FreshBooks account (business). A user can own or be a member of multiple accounts. Always resolve the correct account_id from the user's profile.
Idempotency Through References
Use your own external IDs or reference numbers to prevent duplicate creation. FreshBooks doesn't enforce uniqueness on most fields, so your integration must handle deduplication.
Setup
Dependencies
npm install @freshbooks/api
# Or use raw HTTP with axios
npm install axios
OAuth 2.0 Flow
import axios from 'axios';
const FB_AUTH_URL = 'https://auth.freshbooks.com/oauth/authorize';
const FB_TOKEN_URL = 'https://api.freshbooks.com/auth/oauth/token';
const FB_API_URL = 'https://api.freshbooks.com';
function getAuthUrl(): string {
const params = new URLSearchParams({
client_id: process.env.FB_CLIENT_ID!,
response_type: 'code',
redirect_uri: 'https://yourapp.com/callback',
scope: 'user:profile:read user:clients:read user:invoices:read user:invoices:write',
});
return `${FB_AUTH_URL}?${params}`;
}
async function exchangeCode(code: string) {
const response = await axios.post(FB_TOKEN_URL, {
grant_type: 'authorization_code',
client_id: process.env.FB_CLIENT_ID!,
client_secret: process.env.FB_CLIENT_SECRET!,
code,
redirect_uri: 'https://yourapp.com/callback',
});
return response.data; // { access_token, refresh_token, expires_in }
}
async function getCurrentUser(accessToken: string) {
const response = await axios.get(`${FB_API_URL}/auth/api/v1/users/me`, {
headers: { Authorization: `Bearer ${accessToken}` },
});
const user = response.data.response;
const accountId = user.business_memberships[0].business.account_id;
return { user, accountId };
}
Key Techniques
1. Managing Clients
async function createClient(accountId: string, accessToken: string) {
const response = await axios.post(
`${FB_API_URL}/accounting/account/${accountId}/users/clients`,
{
client: {
fname: 'Jane',
lname: 'Smith',
email: 'jane@acme.com',
organization: 'Acme Corp',
p_street: '123 Business Ave',
p_city: 'Austin',
p_province: 'Texas',
p_code: '73301',
p_country: 'United States',
},
},
{ headers: { Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/json' } }
);
return response.data.response.result.client;
}
async function listClients(accountId: string, accessToken: string, page = 1) {
const response = await axios.get(
`${FB_API_URL}/accounting/account/${accountId}/users/clients?page=${page}&per_page=100`,
{ headers: { Authorization: `Bearer ${accessToken}` } }
);
return response.data.response.result;
}
2. Creating Invoices
async function createInvoice(accountId: string, accessToken: string, clientId: number) {
const response = await axios.post(
`${FB_API_URL}/accounting/account/${accountId}/invoices/invoices`,
{
invoice: {
customerid: clientId,
create_date: '2026-03-25',
due_offset_days: 30,
lines: [
{
type: 0, // 0 = normal line, 1 = rebilling
name: 'Web Development',
description: 'Frontend development — March 2026',
qty: 40,
unit_cost: { amount: '125.00', code: 'USD' },
taxName1: 'Tax',
taxAmount1: 0,
},
],
notes: 'Thank you for your business!',
terms: 'Net 30',
status: 2, // 1=draft, 2=sent
},
},
{ headers: { Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/json' } }
);
return response.data.response.result.invoice;
}
3. Expense Tracking
async function createExpense(accountId: string, accessToken: string) {
const response = await axios.post(
`${FB_API_URL}/accounting/account/${accountId}/expenses/expenses`,
{
expense: {
amount: { amount: '49.99', code: 'USD' },
categoryid: 123, // expense category ID
date: '2026-03-25',
vendor: 'AWS',
notes: 'Monthly hosting costs',
staffid: 1,
},
},
{ headers: { Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/json' } }
);
return response.data.response.result.expense;
}
4. Time Entries
async function createTimeEntry(businessId: string, accessToken: string) {
const response = await axios.post(
`${FB_API_URL}/timetracking/business/${businessId}/time_entries`,
{
time_entry: {
client_id: 12345,
project_id: 678,
duration: 7200, // seconds
started_at: '2026-03-25T09:00:00Z',
note: 'API integration work',
is_logged: true,
billable: true,
},
},
{ headers: { Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/json' } }
);
return response.data.response.result.time_entry;
}
5. Recording Payments
async function recordPayment(accountId: string, accessToken: string, invoiceId: number) {
const response = await axios.post(
`${FB_API_URL}/accounting/account/${accountId}/payments/payments`,
{
payment: {
invoiceid: invoiceId,
amount: { amount: '5000.00' },
date: '2026-03-25',
type: 'Credit Card',
note: 'Payment received via Stripe',
},
},
{ headers: { Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/json' } }
);
return response.data.response.result.payment;
}
Best Practices
- Resolve
account_idfrom/users/me— Never hardcode account IDs. Users may switch businesses. - Use
include[]parameter — Reduce API calls with?include[]=lines&include[]=paymentsto embed related data. - Handle pagination — FreshBooks defaults to 15 items per page. Always check
response.result.pagesfor total pages. - Use webhooks for real-time sync — Register at
/events/account/{id}/events/callbacksfor invoice, payment, and client events. - Currency amounts are strings — FreshBooks returns monetary amounts as
{ amount: '100.00', code: 'USD' }. Parse carefully.
Common Pitfalls
- Using
business_idwhereaccount_idis needed — Accounting endpoints useaccount_id; time tracking usesbusiness_id. They're different values. - Invoice status codes — Status is numeric (1=Draft, 2=Sent, 3=Viewed, 4=Paid, etc.), not string enums.
- Amounts are tax-exclusive by default — Line item amounts don't include tax unless you explicitly configure tax.
- Rate limits are 100 requests/60 seconds — Back off when you get 429 responses.
Anti-Patterns
- Fetching all clients to find one by email — Use the search parameter:
?search[email]=jane@acme.com. - Creating invoices without checking for duplicates — Match on your external reference to prevent double-billing.
- Ignoring the
vis_statefield — Deleted items havevis_state=1, archived havevis_state=2. Default list only returnsvis_state=0(active). - Hardcoding expense category IDs — Category IDs vary per account. Query
/expenses/categoriesfirst.
Install this skill directly: skilldb add accounting-software-skills
Related Skills
FreeAgent API v2
You are a senior developer integrating with the FreeAgent API v2. You build integrations for UK freelancers and small businesses covering contacts, invoices, expenses, bank transactions, timeslips, an
KashFlow API
You are a senior developer integrating with the KashFlow API. You build integrations for UK small businesses covering customers, invoices, receipts, payments, bank accounts, and VAT returns using Kash
MYOB AccountRight API
You are a senior developer integrating with the MYOB AccountRight Live API. You build integrations for Australian/New Zealand businesses covering company files, contacts, invoices, payments, general j
Odoo Accounting XML-RPC / JSON-RPC API
You are a senior developer integrating with Odoo Accounting via its XML-RPC and JSON-RPC APIs. You build integrations for partners, invoices, payments, journal entries, reconciliation, and chart of ac
QuickBooks Online REST API v3
You are a senior developer integrating with the Intuit QuickBooks Online REST API v3. You build robust accounting integrations that create invoices, sync payments, manage customers/vendors, pull finan
Sage Business Cloud Accounting API
You are a senior developer integrating with the Sage Business Cloud Accounting API. You build integrations for contacts, invoices, payments, ledger accounts, and banking using Sage's RESTful API with