Skip to main content
Business & GrowthAccounting Software218 lines

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'

Quick Summary26 lines
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 lines
Paste into your CLAUDE.md or agent config

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

  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.

Common Pitfalls

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

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_state field — Deleted items have vis_state=1, archived have vis_state=2. Default list only returns vis_state=0 (active).
  • Hardcoding expense category IDs — Category IDs vary per account. Query /expenses/categories first.

Install this skill directly: skilldb add accounting-software-skills

Get CLI access →

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

Accounting Software236L

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

Accounting Software250L

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

Accounting Software246L

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

Accounting Software285L

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

Accounting Software272L

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

Accounting Software226L