Overview
There are two ways to use the AvrioBooks API.
- Connected apps (OAuth 2.0). For software used by many customers. Each customer approves your app for one organisation. This is the API described in sections 2 to 8, under
/api/v1/. - Direct API (your own sign-in). For your own scripts and tools. You sign in with an AvrioBooks user and call endpoints for businesses you belong to. See Direct API.
All addresses start with https://app.avriobooks.com. Requests and responses are JSON, except file uploads (multipart). Amounts are strings with two decimals, for example "120.00".
Quick start: connect an app
1. Get credentials
Sign in to AvrioBooks, open the developer portal and create an app. You receive a client id and a client secret. The secret is shown once and stored hashed, so keep it on your server only. Choose the redirect addresses and the most permissions your app will ever ask for.
2. Send the customer to AvrioBooks
Use the authorization code flow with PKCE. Generate a random code_verifier and send its SHA-256 as the code_challenge (method S256). PKCE is required.
GET https://app.avriobooks.com/o/authorize/?response_type=code
&client_id=YOUR_CLIENT_ID
&redirect_uri=YOUR_REDIRECT_URI
&scope=master:read documents:write
&state=RANDOM_VALUE
&code_challenge=CHALLENGE&code_challenge_method=S256The customer signs in, picks one organisation and approves. Only the organisation owner and administrators can approve. AvrioBooks then redirects to your redirect address with code and state. Check that state matches what you sent.
3. Exchange the code
Codes last 2 minutes and work once.
curl -X POST https://app.avriobooks.com/o/token/ \
-u CLIENT_ID:CLIENT_SECRET \
-d grant_type=authorization_code -d code=CODE \
-d redirect_uri=YOUR_REDIRECT_URI -d code_verifier=VERIFIERYou receive an access_token (valid for 1 hour) and a refresh_token (valid for 90 days). Refresh tokens rotate: store the new one every time you refresh. A refresh that is retried within 2 minutes still succeeds, so a lost response is safe.
4. Call the API
curl https://app.avriobooks.com/api/v1/organisation/ \
-H "Authorization: Bearer ACCESS_TOKEN"The token works only for the organisation the customer approved. The organisation is never part of the URL, so a token cannot be pointed at another one. On every call AvrioBooks checks that the person who approved is still a member with the permission the call needs, so removing them or lowering their role cuts the connection off immediately.
Refreshing a token
curl -X POST https://app.avriobooks.com/o/token/ \
-u CLIENT_ID:CLIENT_SECRET \
-d grant_type=refresh_token -d refresh_token=REFRESH_TOKENScopes
Your app can only ask for scopes it declared when you registered it. The default scope is master:read.
| Scope | Allows |
|---|---|
master:read | Read the chart of accounts, tax rates, contacts and bank accounts |
documents:write | Create draft bills and invoices and attach files to them |
documents:read | Read back the status of the documents the app created |
The organisation is stored as an org:<id> entry in the token’s scopes. An app cannot ask for it. The consent screen adds it for the organisation the customer chose.
Reading master data
List endpoints accept ?limit= (maximum 500) and &after=<last id>, and return {"results": [...], "next_after": id or null}. Add ?active=1 to leave out inactive rows. There is no “changed since” filter, and these lists are small.
| Endpoint | Scope | Returns |
|---|---|---|
GET /api/v1/organisation/ | any | id, name, slug, base_currency, country, is_uk, scopes, read_only |
GET /api/v1/accounts/ | master:read | id, code, name, type, active, system. Type is ASSET, LIABILITY, EQUITY, REVENUE or EXPENSE. system marks receivable, payable and VAT accounts, which cannot be used on bill lines. |
GET /api/v1/tax-rates/ | master:read | id, name, applies_to, rate, active |
GET /api/v1/contacts/ | master:read | id, name, email, phone, customer, vendor, tax_number, active |
GET /api/v1/bank-accounts/ | master:read | id, name, bank, number, sort_code, currency, kind, active |
Creating a bill or invoice
POST /api/v1/bills/ needs scope documents:write and Purchases edit permission. POST /api/v1/invoices/ needs the same scope and Sales edit permission.
{
"external": {"source": "myapp", "id": "12345"},
"contact": {"name": "Paper Co"},
"number": "PC-1001", "date": "2026-01-10", "due_date": "2026-02-10",
"currency": "GBP", "total": "120.00", "notes": "",
"items": [
{"description": "Printer paper", "quantity": "1", "unit_price": "100.00", "account": 12, "tax_rate": 3}
]
}externalis required. Sending the samesourceandidagain returns the existing document with200and"duplicate": true, so retries are always safe.contactis{"id": n}(must exist) or{"name": "..."}, matched ignoring case. If the name is missing it is created, as a supplier for bills and a customer for invoices, when the connection may create contacts. The response sayscontact_created.totalis optional. When sent it must equal what AvrioBooks calculates including tax, or nothing is created (total_mismatch).accountandtax_rateare checked. An unknown or system account, or an unknown tax rate, is refused, never silently replaced. Omittax_rateto use the contact’s default, or sendnullfor no tax.currencymust be the organisation’s currency, or empty. Foreign-currency documents are not supported yet.- The document is created as a draft. Nothing is posted until a person approves it in AvrioBooks.
A 201 response returns id, kind, number, status, date, due_date, contact, currency, total, attachments, external, url, duplicate, contact_created. The url opens the draft in AvrioBooks.
Validation codes: external_required, external_invalid, contact_required, contact_not_found, contact_invalid, items_required, too_many_items (200 items maximum), item_invalid, account_not_found, tax_rate_not_found, total_invalid, total_mismatch, currency_not_supported.
Attaching the original file
POST /api/v1/documents/<id>/attachments/ with multipart field file. PDF, PNG, JPG and GIF only, and the content must match the extension. The default limit is 10 MB. Uploading the same file again returns 200 with "duplicate": true. You can only attach to documents your app created.
curl -X POST https://app.avriobooks.com/api/v1/documents/42/attachments/ \
-H "Authorization: Bearer ACCESS_TOKEN" \
-F "[email protected]"Reading status back
With scope documents:read:
GET /api/v1/documents/42/
GET /api/v1/documents/?source=myapp&external_id=12345Only documents that came in through the API are visible here. The rest of the organisation’s documents are not.
Rate limits and errors
The API allows 120 requests a minute per connection, then returns 429. The token endpoints (/o/token/ and /o/revoke_token/) allow 30 calls a minute per address. Errors look like:
{"detail": "Message safe to show", "code": "stable_code"}| Status | Code | Meaning |
|---|---|---|
| 401 | Missing, expired or revoked token. Refresh it. | |
| 402 | subscription_ended | The subscription has ended. Reads still work, writes do not (the same rule as the web app). |
| 403 | insufficient_scope | The connection was not given that scope. |
| 403 | forbidden | The person who connected no longer has permission. |
| 403 | organisation_unavailable / no_organisation | They left the organisation, or the organisation is a demo. |
| 409 | number_in_use / external_id_in_use | Document number already used, or the external id belongs to the other kind of document. |
| 413 | file_too_large | The file is over the upload limit. |
| 422 | validation_error and the codes above | The content is not acceptable, for example the books are locked at that date. |
| 429 | Rate limited. Wait and retry. |
Disconnecting and customer control
Customers see each connected app on Organisation settings > Connected apps: who approved it, when, and what it may do. They can disconnect it at any time, which revokes the access and refresh tokens at once, so your next call gets 401 and you cannot refresh. This works even when the subscription has ended. Your app can also disconnect itself:
curl -X POST https://app.avriobooks.com/o/revoke_token/ \
-u CLIENT_ID:CLIENT_SECRET -d token=TOKENEach connection and each document created through the API is written to the organisation’s audit trail and attributed to the person who approved the connection. Bills and invoices from an app appear in the customer’s Document inbox so they can review each one.
Registering an app: rules
- Anyone with an AvrioBooks account can register an app in the developer portal. You can have up to 10 apps and create up to 10 an hour.
- Apps are confidential server apps: authorization code plus PKCE (S256).
- Redirect addresses must be exact:
https, orhttpfor localhost only. You can add up to 5. No wildcards, fragments or user names. - App names cannot imitate AvrioBooks or another app, because customers decide on the name shown on the consent screen.
- New apps are unverified: the consent screen and the customer’s Connected apps page show a notice until AvrioBooks verifies the app. Email [email protected] to ask.
- You can rotate the client secret (the old one stops at once, and existing connections keep working), disconnect every organisation, or delete the app. You see only a count of connected organisations, never which ones.
Direct API (your own sign-in)
For your own scripts, you can sign in with an AvrioBooks user and call the business endpoints directly. The user can only reach businesses they belong to, and the same rules as the web app apply (for example, documents dated in a locked period are refused). Create a dedicated user with only the access your integration needs.
Get a token
curl -X POST https://app.avriobooks.com/api/token/ \
-H "Content-Type: application/json" \
-d '{"email": "[email protected]", "password": "your-password"}'The response has an access token (about 5 minutes) and a refresh token (about a day). Send the access token as Authorization: Bearer <access token>. Refresh with POST /api/token/refresh/ and {"refresh": "<refresh token>"}.
| Endpoint | What it does |
|---|---|
GET /api/businesses/ | The businesses you belong to |
/api/<business-slug>/contacts/ | List, create, update and delete contacts |
/api/<business-slug>/invoices/ | List, create, update and delete sales invoices. Filter with ?type= |
curl https://app.avriobooks.com/api/your-business-slug/invoices/ \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"Your business slug is the part of the address after the domain when you are inside a business. Creating an invoice through the Direct API posts it to your ledger, just as the web app does. See the help article Use the REST API.
Best practice
- Keep client secrets and refresh tokens on your server, in environment variables or a secrets store, never in source code or a browser.
- Always send an
externalid so retries never create duplicates. - Refresh tokens shortly before they expire, and store the new refresh token every time.
- Handle
429by waiting and retrying. Handle401by refreshing, and if that fails, ask the customer to reconnect. - Test against the demo company’s sign-in with the Direct API before writing to real books. Connected-app writes to a demo organisation are refused.
Not in version 1
Bank statements, foreign-currency documents, payments, “changed since” filters and webhooks (poll documents/ for status) are not available yet. The set of endpoints may grow. Contact us if you need something that is not listed.
Support
Questions or feedback on the API? Email [email protected] or use the contact page.