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
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 OAuth 2.0 authentication. ## Key Points 1. **Use `attributes` parameter** — Filter response fields to reduce payload: `?attributes=name,email,balance`. 2. **Follow HAL `_links`** — Use `$next`, `$prev` links for pagination instead of manually constructing URLs. 3. **Check country-specific tax rates** — Query `/tax_rates` to get valid tax rate IDs for the business's country. 4. **Use `If-Modified-Since`** — Sage supports conditional GET for efficient sync. 5. **Validate ledger account visibility** — Not all accounts are valid for all transaction types. Check `visible_in` field. - **Country parameter in auth URL** — Must match the user's Sage subscription country or auth fails. - **HAL pagination** — Results are in `$items` array, not a top-level array. Total count is in `$total`. - **Tax rate IDs are country-specific** — US, UK, and other countries have different tax rate ID formats. - **Ledger account types** — Using wrong account type for a transaction silently misclassifies it in reports. - **Ignoring `_links` in responses** — Sage provides hypermedia links for a reason. Use them for navigation. - **Hardcoding tax rates** — Tax rates change. Query them dynamically. - **Creating contacts without checking duplicates** — Search by name/email first. ## Quick Example ```bash npm install axios ```
skilldb get accounting-software-skills/Sage Business Cloud Accounting APIFull skill: 226 linesSage 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 OAuth 2.0 authentication.
Core Philosophy
Country-Specific Compliance
Sage adapts its accounting model per country. Tax types, document types, and required fields vary by region. Always check the country of the business before assuming field requirements.
Ledger-Centric Design
Sage exposes the full general ledger. Every transaction posts to specific ledger accounts. Understanding the Chart of Accounts is essential for correct integration.
HAL+JSON Responses
Sage API returns HAL (Hypertext Application Language) formatted JSON with _links for navigation. Use these links for pagination and related resource discovery.
Setup
Dependencies
npm install axios
OAuth 2.0 Flow
import axios from 'axios';
const SAGE_AUTH_URL = 'https://www.sageone.com/oauth2/auth/central';
const SAGE_TOKEN_URL = 'https://oauth.accounting.sage.com/token';
const SAGE_API_URL = 'https://api.accounting.sage.com/v3.1';
function getAuthUrl(): string {
const params = new URLSearchParams({
response_type: 'code',
client_id: process.env.SAGE_CLIENT_ID!,
redirect_uri: 'https://yourapp.com/callback',
scope: 'full_access',
state: 'random-state-value',
country: 'us', // us, gb, ca, etc.
});
return `${SAGE_AUTH_URL}?${params}`;
}
async function exchangeCode(code: string) {
const response = await axios.post(SAGE_TOKEN_URL, new URLSearchParams({
grant_type: 'authorization_code',
client_id: process.env.SAGE_CLIENT_ID!,
client_secret: process.env.SAGE_CLIENT_SECRET!,
code,
redirect_uri: 'https://yourapp.com/callback',
}));
return response.data;
}
const sageApi = axios.create({
baseURL: SAGE_API_URL,
headers: { 'Content-Type': 'application/json' },
});
sageApi.interceptors.request.use((config) => {
config.headers.Authorization = `Bearer ${getAccessToken()}`;
return config;
});
Key Techniques
1. Managing Contacts
async function createContact() {
const response = await sageApi.post('/contacts', {
contact: {
name: 'Acme Corp',
contact_type_ids: ['CUSTOMER'], // CUSTOMER, VENDOR, or both
main_address: {
address_line_1: '123 Main Street',
city: 'San Francisco',
region: 'CA',
postal_code: '94105',
country_id: 'US',
},
email: 'billing@acme.com',
telephone: '+1-555-0100',
tax_number: '12-3456789',
},
});
return response.data;
}
async function listContacts(page = 1) {
const response = await sageApi.get('/contacts', {
params: {
contact_type_id: 'CUSTOMER',
items_per_page: 50,
page,
attributes: 'name,email,balance',
search: 'Acme', // free text search
},
});
return response.data;
}
2. Creating Sales Invoices
async function createSalesInvoice(contactId: string) {
const response = await sageApi.post('/sales_invoices', {
sales_invoice: {
contact_id: contactId,
date: '2026-03-25',
due_date: '2026-04-25',
reference: 'INV-2026-042',
notes: 'March consulting services',
invoice_lines: [
{
description: 'Software consulting',
ledger_account_id: 'revenue-ledger-id',
quantity: 20,
unit_price: 150.00,
tax_rate_id: 'US_STANDARD',
},
],
main_address: {
address_line_1: '123 Main Street',
city: 'San Francisco',
postal_code: '94105',
country_id: 'US',
},
},
});
return response.data;
}
3. Recording Payments
async function createSalesPayment(invoiceId: string, bankAccountId: string) {
const response = await sageApi.post('/contact_payments', {
contact_payment: {
transaction_type_id: 'CUSTOMER_RECEIPT',
contact_id: 'contact-id',
bank_account_id: bankAccountId,
date: '2026-03-25',
total_amount: 3000.00,
reference: 'PAY-2026-042',
allocated_artefacts: [
{
artefact_id: invoiceId,
amount: 3000.00,
},
],
},
});
return response.data;
}
4. Ledger Accounts
async function getChartOfAccounts() {
const response = await sageApi.get('/ledger_accounts', {
params: {
items_per_page: 200,
visible_in: 'sales', // sales, purchases, banking, journals
},
});
return response.data.$items;
}
async function getLedgerEntries(startDate: string, endDate: string) {
const response = await sageApi.get('/ledger_entries', {
params: {
from_date: startDate,
to_date: endDate,
items_per_page: 200,
},
});
return response.data.$items;
}
5. Bank Accounts and Reconciliation
async function listBankAccounts() {
const response = await sageApi.get('/bank_accounts');
return response.data.$items;
}
async function getBankTransactions(bankAccountId: string) {
const response = await sageApi.get('/bank_transactions', {
params: {
bank_account_id: bankAccountId,
from_date: '2026-01-01',
to_date: '2026-03-31',
items_per_page: 100,
},
});
return response.data.$items;
}
Best Practices
- Use
attributesparameter — Filter response fields to reduce payload:?attributes=name,email,balance. - Follow HAL
_links— Use$next,$prevlinks for pagination instead of manually constructing URLs. - Check country-specific tax rates — Query
/tax_ratesto get valid tax rate IDs for the business's country. - Use
If-Modified-Since— Sage supports conditional GET for efficient sync. - Validate ledger account visibility — Not all accounts are valid for all transaction types. Check
visible_infield.
Common Pitfalls
- Country parameter in auth URL — Must match the user's Sage subscription country or auth fails.
- HAL pagination — Results are in
$itemsarray, not a top-level array. Total count is in$total. - Tax rate IDs are country-specific — US, UK, and other countries have different tax rate ID formats.
- Ledger account types — Using wrong account type for a transaction silently misclassifies it in reports.
Anti-Patterns
- Ignoring
_linksin responses — Sage provides hypermedia links for a reason. Use them for navigation. - Hardcoding tax rates — Tax rates change. Query them dynamically.
- Creating contacts without checking duplicates — Search by name/email first.
- Skipping the business settings check — Query
/businessfirst to understand currency, country, and fiscal year settings.
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
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'
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