freeagent
Read-only access to the FreeAgent accounting API (contacts, invoices, bills, bank accounts and transactions, expenses, estimates, proformas, projects, timeslips, users, company) for the firm's FreeAgent account. Use when the user asks about FreeAgent data, freeagent.com, pulling invoices/bills/bank transactions from FreeAgent, or anything needing FreeAgent API access. Read-only by construction — this skill never writes.
Source: .opencode/skills/freeagent/SKILL.md — site rebuilt 2026-09-05.
FreeAgent (read-only)¶
Credentials¶
- Source of truth:
FA_CLIENT_ID,FA_CLIENT_SECRETand the OAuth tokens live in opencode's auth store at~/.local/share/opencode/auth.jsonunder thefreeagentkey, exactly likegoogle/mistralare stored there for the OCR skills. - Never print, log or paste the client secret, access token or refresh token. Use the store.
- If the entry is missing, run the one-time setup below. Do not improvise credentials.
One-time setup (run once per machine)¶
- In the FreeAgent developer dashboard (dev.freeagent.com), the app must have:
- Read-only access level — the minimum numeric access level that still covers the data needed (invoices/contacts/bank transactions/expenses sit at low levels; keep the level as low as possible — write endpoints need higher levels, and a low level is effectively read-only). Higher levels slow approval; write access is not wanted here.
- The redirect URI
http://127.0.0.1:8765/callbackregistered on the app (register exactly this string — FreeAgent verifies the redirect URI against the registered one). - Run:
python .opencode/skills/freeagent/tools/oauth_setup.py --client-id <ID> --client-secret <SECRET>(or setFA_CLIENT_ID/FA_CLIENT_SECRETenv vars and omit the flags). The script opens the authorize URL (approve_app) in the browser, catches the callback on localhost, exchanges the code for tokens and writes them intoauth.json. Access tokens expire after ~1 hour; the client auto-refreshes with the long-lived refresh token (~20 years per the API), so this is a one-time handshake.
Usage (read-only)¶
Query via tools/freeagent_client.py (auto-refreshes the access token, only ever issues GETs):
python .opencode/skills/freeagent/tools/freeagent_client.py company
python .opencode/skills/freeagent/tools/freeagent_client.py users
python .opencode/skills/freeagent/tools/freeagent_client.py contacts [--view active|hidden|all] [--search "smith"]
python .opencode/skills/freeagent/tools/freeagent_client.py invoices [--view draft|open|overdue|sent|paid|all] [--from 2025-01-01] [--to 2025-12-31] [--contact-url ...]
python .opencode/skills/freeagent/tools/freeagent_client.py bills [--view draft|open|paid|all] [--from ...] [--to ...]
python .opencode/skills/freeagent/tools/freeagent_client.py bank_accounts
python .opencode/skills/freeagent/tools/freeagent_client.py bank_transactions [--account-url ...] [--from ...] [--to ...]
python .opencode/skills/freeagent/tools/freeagent_client.py expenses [--from ...] [--to ...] [--user-url ...]
python .opencode/skills/freeagent/tools/freeagent_client.py estimates / proformas / projects / timeslips / stock_items / tax_timeline
python .opencode/skills/freeagent/tools/freeagent_client.py get /invoices/<id> # any read path (API base is https://api.freeagent.com/v2)
- FreeAgent wraps responses per-resource (e.g.
{"invoices": [...]}); the client unwraps the single resource key before printing. Use--id <id>on any resource to fetch one record. - Pagination:
--per-page(max 100) and--page; default 25. - The access-level gate applies here as on the portal: the app can only see/read what its access level allows.
Limitations¶
- Read-only by design: the tool rejects anything that is not a GET. No invoice creation, no contact writes, no bank explanation.
- The Accountancy Practice API (multiple client accounts) is a different product and is not this skill; this is the Company API for the firm's own FreeAgent account.