Overview
Every request to the Beeswax API is authenticated with a Bearer token in the Authorization header. Tokens are created in the web app under Account Settings → API Tokens and carry three things: the account they are bound to, the user who created them, and a list of scopes.
Authorization: Bearer YOUR_API_TOKEN
The header is the only supported way to authenticate. Tokens in the query string are not accepted, and there is no cookie or session authentication on the API.
The token
| Property | Detail |
|---|---|
| Format | 43 characters, URL-safe base64. Treat it as opaque. |
| Shown | Once, immediately after creation. Copy it then. |
| Bound to | One account, permanently. |
| Acts as | The user who created it, with that user's role on the account. |
| Scopes | A fixed list chosen at creation; editable later in the web app. |
| Expiry | Optional date. Expired tokens return 401. |
| Revocation | Immediate. Revoked tokens return 401 but stay listed for audit. |
| Subscription | Tokens stop working (401) while the account's subscription is not active, and resume when it is. |
| Membership | Tokens stop working (401) as soon as their user no longer belongs to the account. Removing a person also revokes their tokens for it, so adding them back later does not revive them. |
| Last used | Recorded on every successful request and shown in the token list. |
Who can manage tokens: Owners and Super Admins of the account. Managers, Accountants, Basic users, Contractors and Clients cannot see the API Tokens page. Token management is on every plan, including Free.
Account binding
A token can act on exactly one account, chosen when it is created, and the account is never a request parameter. This is the whole tenancy model:
- A bookkeeper who looks after six clients creates six tokens, one per account, and names them accordingly.
- A user who belongs to several accounts can only create a token for an account they are a member of, and the token works only while they remain one. Beeswax refuses to issue anything else.
- The
/accountsendpoint lists the accounts the token's user can see, but the token itself still only reads and writes its own account.
Switching accounts
POST /accounts/switch (requires the all scope) revokes the calling token and returns a fresh token bound to the target account. It exists for first-party clients that log a person in and let them move between accounts. For an integration, create one token per account instead; it is simpler, and a revoked token is a support ticket waiting to happen.
First-party login
POST /sessions exchanges an email and password for an all-scope token. It is reserved for Beeswax's own apps. Do not collect Beeswax passwords in your integration. Ask the account owner for a scoped token instead; it can be revoked without changing anyone's password, and it never grants more than it says on the tin.
Scopes
Scopes are resource:read or resource:write. A :write scope implies the matching :read, and all grants every scope. A request outside the token's scopes returns:
HTTP 403
{ "error": "Insufficient permissions. Required scope: invoices:write" }
Grant the narrowest set that does the job. A reporting sync needs :read scopes only; a system that raises invoices needs invoices:write plus the read scopes it uses to look up clients, accounts and taxes.
Financial
| Scope | Grants |
|---|---|
invoices:read |
List and view invoices, their lines, postings, files and version history |
invoices:write |
Create, edit, finalise and void invoices; edit sections and lines; attach files; restore versions |
expenses:read |
List and view expenses (bills), their lines, postings, files and versions; the expense inbox |
expenses:write |
Create, edit, finalise and void expenses; attach files; upload documents to the inbox; assign inbox items |
quotes:read |
List and view quotes and their lines |
quotes:write |
Create, edit, finalise and delete quotes; edit sections and lines; attach files |
payments:read |
List and view payments and what each one settles |
payments:write |
Apply a payment to invoices or expenses; remove a payment |
transactions:read |
Read ledger postings under any document, and the per-account ledger |
journal_entries:read |
List and view manual (general) journals |
journal_entries:write |
Create, post and delete draft manual journals |
transaction_accounts:read |
Chart of accounts, default accounts, tax codes, and (with transactions:read) the per-account ledger |
reconciliations:read |
Bank reconciliations (statement checks): periods, rows, processed statement lines, the possible-duplicates report |
reconciliations:write |
Create reconciliations, upload statement PDFs, tick and untick rows, tie statement lines to rows |
transaction_templates:read |
Products & services catalogue |
transaction_templates:write |
Create, update and delete products & services |
tax_returns:read |
Tax returns, field transactions, notes and conversation (Australian accounts) |
tax_returns:write |
Create returns, override fields, add notes, confirm sections, request review, finalise |
Contacts, projects and work
| Scope | Grants |
|---|---|
companies:read |
Clients and suppliers with their contact people |
companies:write |
Create and update clients and suppliers and their people |
projects:read |
Projects and their milestones |
projects:write |
Create and update projects |
project_documents:read |
Project documents and their version history |
project_documents:write |
Create and edit freeform documents; restore versions |
tasks:read |
Tasks, comments and files |
tasks:write |
Create, update, transition and comment on tasks; timers; files |
time_entries:read |
Time entries |
time_entries:write |
Log time |
milestones:read |
Milestones (read only) |
events:read |
Calendar events visible to the token's user (read only) |
Account
| Scope | Grants |
|---|---|
users:read |
Members of the account |
accounts:read |
The accounts the token's user can see |
themes:read |
Document themes and the theme specification |
themes:write |
Create, validate, preview and activate custom document themes |
all |
Everything above, plus POST /accounts/switch and the untyped /journal_entries reader for long-tail types (payrolls, credits, bank transfers) |
Endpoints that need no scope
GET /meta and GET /users/me answer any usable token. They reveal only the token holder's own identity, the bound account, the scopes granted and the server clock. Use /meta as your connection check.
Scopes that travel together
Some writes cannot be done without looking things up first:
- Creating an invoice, quote or expense needs
companies:read(to pick the client or supplier),projects:readif you attach it to a project, andtransaction_accounts:read(accounts and tax codes for the lines). Addtransaction_templates:readto price lines from your catalogue. - Recording a payment needs
transaction_accounts:read(to find the bank account) andinvoices:readorexpenses:read(to find what is owed). - Reconciling a bank account against its statement needs
reconciliations:readto read the statement check andreconciliations:writeto tick rows; addtransaction_accounts:readandtransactions:readfor the per-account ledger, andexpenses:writeorpayments:writeto record what the statement shows is missing. - Posting a manual journal needs
transaction_accounts:readfor the account ids.
Scopes and roles
Scopes are a ceiling, not a grant. Every request, read or write, is also checked against the creating user's role on the bound account, with the same rules the web app applies. So:
- A token created by an Accountant with
invoices:writecan raise invoices, because Accountants can in the app. - A token created by a Basic user with
invoices:writegets403 {"error":"Your role does not permit creating or editing invoice documents"}. - Reads return what the role sees in the app, no more. A Client's token lists the invoices and quotes of the projects visible to them. A Basic user's token lists the tasks that are theirs and the projects visible to them.
- A resource the role cannot see at all answers
403, for example{"error":"Your role does not permit reading expenses"}for a Basic user. A single record the role cannot see answers404, the same as one that does not exist. - Plan features apply too. Inbox endpoints on an account whose plan lacks the expenses feature return
403 {"error":"This feature is not available on your current plan."}.
If a token needs to do something its creator cannot, the fix is a token created by an Owner or Super Admin, not a wider scope.
Managing tokens over time
Naming. Name a token after the system and purpose: "Warehouse sync (read)", "Zapier: new invoice → Slack". The list shows the name, masked token, scopes, last used and created dates.
Editing. Name, scopes and expiry can be changed at any time; changes take effect on the next request. The token string itself never changes.
Rotation. There is no in-place rotate. Create the new token, deploy it, confirm the old token's last used stops moving, then revoke the old one. Keep both live during the switch so nothing breaks.
Revoking versus deleting. Revoke when a token may have leaked or a system is decommissioned; the row stays for audit. Delete when you want it gone from the list.
Expiry. Set an expiry on anything temporary: a consultant's access, a migration script, a proof of concept. An expired token fails closed with a 401.
Compromise. If a token is exposed (committed to a repository, pasted in a ticket), revoke it immediately in the web app. Revocation is instant and does not affect other tokens.
Storing tokens in your application
- Keep tokens server-side in a secrets manager or encrypted configuration. Never ship one in a browser, a mobile app binary, a spreadsheet macro or a shared document.
- One token per environment (development, staging, production), each bound to the right Beeswax account.
- Log the token id or name, never the value. Beeswax shows the masked token in the list so you can match logs to tokens.
- Handle 401 as stop and alert, not retry: the token has been revoked, has expired, the account's subscription has lapsed, or the person it belongs to has left the account. Retrying will not help and the account owner needs to know.