A reference guide for building AI agents: every method, how to authenticate, and the permissions each one needs.
The Xero API is how an app or AI agent works with a Xero organisation: raising an invoice, recording a payment, adding a contact, reconciling a bank transaction, or pulling a Profit and Loss report. Access is granted through an OAuth 2.0 access token and a set of scopes, like accounting.transactions or accounting.contacts, that decide which areas a call can read or write, and each request names the one organisation it acts on. Xero can also push an event when an invoice, contact, or credit note is created or updated, so an integration learns about changes without polling.
How an app or AI agent connects to Xero determines what it can reach. There is a main API for reading and writing accounting data, a hosted server that exposes Xero tools to agents, and a route for receiving events, and each is governed by the access token behind it and the permissions that token carries.
The Accounting API answers at https://api.xero.com/api.xro/2.0 and works with JSON or XML. A call carries an OAuth 2.0 access token and a Xero-tenant-id header that names which connected organisation it acts on. A GET reads, a PUT creates new records, and a POST creates or updates records.
Xero publishes a first-party Model Context Protocol server, @xeroapi/xero-mcp-server, run locally through npx. It exposes tools such as list-contacts, list-invoices, list-accounts, list-payments, create-invoice, create-contact, and create-payment. It authenticates either with a Custom Connection (a client id and secret tied to one organisation) or with a bearer token supplied at runtime.
Xero POSTs a small JSON payload to a registered HTTPS endpoint when invoices, contacts, or credit notes are created or updated. The payload names the resource and event, and the receiver re-fetches full detail from the API. Each delivery carries an x-xero-signature header, an HMAC-SHA256 hash of the body keyed with the webhook signing key, which the receiver verifies. A new endpoint must first pass an 'intent to receive' validation.
The standard authorization-code flow has a user sign in to Xero and consent to the requested scopes, after which the app exchanges a code for an access token and a refresh token. The access token lasts 30 minutes; the offline_access scope is needed to receive a refresh token and keep the connection alive. The token can act on every organisation the user connected, each named by the Xero-tenant-id header.
A Custom Connection uses the OAuth 2.0 client-credentials flow to connect a single organisation with no user sign-in, which suits a private machine-to-machine integration. It is tied to one organisation chosen when the connection is set up, and its scopes are fixed in the app settings.
The authorization-code flow with PKCE (Proof Key for Code Exchange) suits a mobile or single-page app that cannot keep a client secret. It adds a one-time code challenge and verifier so the code exchange is safe without a stored secret.
The Xero Accounting API is split into areas an agent can act on, such as invoices, contacts, payments, bank transactions, and reports. Each area has its own methods, and writes in some areas record money owed, money received, or changes to the chart of accounts.
List, read, create, and update sales invoices and purchase bills.
List, read, create, and update the customers and suppliers in an organisation.
List, read, create, update, and delete the accounts that make up the chart of accounts.
List and read payments against invoices and credit notes, create a payment, and delete one.
List, read, create, and update spent and received money transactions.
List, read, create, update, and delete the inventory and service items in an organisation.
List, read, create, and update credit notes.
Read accounting reports such as Profit and Loss, Balance Sheet, Trial Balance, and aged receivables and payables.
Filter by method, access, or permission, or search any path. Select a row for version detail, rate limits, the related webhook event, and the source.
| Method | Endpoint | What it does | Access | Permission | Version | |
|---|---|---|---|---|---|---|
InvoicesList, read, create, and update sales invoices and purchase bills.4 | ||||||
| GET | /Invoices | Retrieve sales invoices or purchase bills. | read | accounting.transactions | Current | |
Read-only access can use accounting.transactions.read instead of the read-write accounting.transactions. Acts oninvoice Permission (capability) accounting.transactionsVersionAvailable since the API’s base version Webhook event invoiceRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /Invoices/{InvoiceID} | Retrieve a specific sales invoice or purchase bill by its unique invoice Id. | read | accounting.transactions | Current | |
Read-only access can use accounting.transactions.read. Acts oninvoice Permission (capability) accounting.transactionsVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PUT | /Invoices | Create one or more sales invoices or purchase bills. | write | accounting.transactions | Current | |
A PUT creates new records only; the read-only accounting.transactions.read scope cannot call it. Acts oninvoice Permission (capability) accounting.transactionsVersionAvailable since the API’s base version Webhook event invoiceRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /Invoices | Update existing invoices, or create new ones, in a single call. | write | accounting.transactions | Current | |
A POST to the collection updates or creates; matching is by InvoiceID or InvoiceNumber. Acts oninvoice Permission (capability) accounting.transactionsVersionAvailable since the API’s base version Webhook event invoiceRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
ContactsList, read, create, and update the customers and suppliers in an organisation.4 | ||||||
| GET | /Contacts | Retrieve all contacts in an organisation. | read | accounting.contacts | Current | |
Read-only access can use accounting.contacts.read. Acts oncontact Permission (capability) accounting.contactsVersionAvailable since the API’s base version Webhook event contactRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /Contacts/{ContactID} | Retrieve a specific contact by its unique contact Id. | read | accounting.contacts | Current | |
Read-only access can use accounting.contacts.read. Acts oncontact Permission (capability) accounting.contactsVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PUT | /Contacts | Create one or more contacts in an organisation. | write | accounting.contacts | Current | |
A PUT creates new contacts only. Acts oncontact Permission (capability) accounting.contactsVersionAvailable since the API’s base version Webhook event contactRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /Contacts | Update existing contacts, or create new ones, in a single call. | write | accounting.contacts | Current | |
A POST to the collection updates or creates; matching is by ContactID or Name. Acts oncontact Permission (capability) accounting.contactsVersionAvailable since the API’s base version Webhook event contactRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
Accounts (chart of accounts)List, read, create, update, and delete the accounts that make up the chart of accounts.5 | ||||||
| GET | /Accounts | Retrieve the full chart of accounts. | read | accounting.settings | Current | |
Read-only access can use accounting.settings.read. Acts onaccount Permission (capability) accounting.settingsVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /Accounts/{AccountID} | Retrieve a single account from the chart of accounts by its unique Id. | read | accounting.settings | Current | |
Read-only access can use accounting.settings.read. Acts onaccount Permission (capability) accounting.settingsVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PUT | /Accounts | Create a new account in the chart of accounts. | write | accounting.settings | Current | |
Chart-of-accounts changes need the read-write accounting.settings scope. Acts onaccount Permission (capability) accounting.settingsVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /Accounts/{AccountID} | Update an account in the chart of accounts. | write | accounting.settings | Current | |
Needs the read-write accounting.settings scope. Acts onaccount Permission (capability) accounting.settingsVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| DELETE | /Accounts/{AccountID} | Delete an account from the chart of accounts. | write | accounting.settings | Current | |
Only accounts with no transactions can be deleted; needs accounting.settings. Acts onaccount Permission (capability) accounting.settingsVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
PaymentsList and read payments against invoices and credit notes, create a payment, and delete one.4 | ||||||
| GET | /Payments | Retrieve payments made against invoices and credit notes. | read | accounting.transactions | Current | |
Read-only access can use accounting.transactions.read. Acts onpayment Permission (capability) accounting.transactionsVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /Payments/{PaymentID} | Retrieve a specific payment by its unique payment Id. | read | accounting.transactions | Current | |
Read-only access can use accounting.transactions.read. Acts onpayment Permission (capability) accounting.transactionsVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PUT | /Payments | Create one or more payments against invoices or credit notes. | write | accounting.transactions | Current | |
A PUT creates new payments; needs the read-write accounting.transactions scope. Acts onpayment Permission (capability) accounting.transactionsVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /Payments/{PaymentID} | Delete a payment by setting its status to DELETED. | write | accounting.transactions | Current | |
Xero deletes a payment through a POST that sets Status to DELETED; needs accounting.transactions. Acts onpayment Permission (capability) accounting.transactionsVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
Bank transactionsList, read, create, and update spent and received money transactions.4 | ||||||
| GET | /BankTransactions | Retrieve any spent or received money transactions. | read | accounting.transactions | Current | |
Read-only access can use accounting.transactions.read. Acts onbank transaction Permission (capability) accounting.transactionsVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /BankTransactions/{BankTransactionID} | Retrieve a single spent or received money transaction by its unique Id. | read | accounting.transactions | Current | |
Read-only access can use accounting.transactions.read. Acts onbank transaction Permission (capability) accounting.transactionsVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PUT | /BankTransactions | Create one or more spent or received money transactions. | write | accounting.transactions | Current | |
A PUT creates new transactions; needs the read-write accounting.transactions scope. Acts onbank transaction Permission (capability) accounting.transactionsVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /BankTransactions | Update existing bank transactions, or create new ones, in a single call. | write | accounting.transactions | Current | |
A POST to the collection updates or creates; matching is by BankTransactionID. Acts onbank transaction Permission (capability) accounting.transactionsVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
ItemsList, read, create, update, and delete the inventory and service items in an organisation.4 | ||||||
| GET | /Items | Retrieve the inventory and service items in an organisation. | read | accounting.settings | Current | |
Read-only access can use accounting.settings.read. Acts onitem Permission (capability) accounting.settingsVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PUT | /Items | Create one or more items. | write | accounting.settings | Current | |
A PUT creates new items; needs the read-write accounting.settings scope. Acts onitem Permission (capability) accounting.settingsVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /Items/{ItemID} | Update a specific item by its unique Id. | write | accounting.settings | Current | |
Needs the read-write accounting.settings scope. Acts onitem Permission (capability) accounting.settingsVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| DELETE | /Items/{ItemID} | Delete a specific item by its unique Id. | write | accounting.settings | Current | |
Needs the read-write accounting.settings scope. Acts onitem Permission (capability) accounting.settingsVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
Credit notesList, read, create, and update credit notes.4 | ||||||
| GET | /CreditNotes | Retrieve any credit notes. | read | accounting.transactions | Current | |
Read-only access can use accounting.transactions.read. Acts oncredit note Permission (capability) accounting.transactionsVersionAvailable since the API’s base version Webhook event creditnoteRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /CreditNotes/{CreditNoteID} | Retrieve a specific credit note by its unique credit note Id. | read | accounting.transactions | Current | |
Read-only access can use accounting.transactions.read. Acts oncredit note Permission (capability) accounting.transactionsVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PUT | /CreditNotes | Create one or more credit notes. | write | accounting.transactions | Current | |
A PUT creates new credit notes; needs the read-write accounting.transactions scope. Acts oncredit note Permission (capability) accounting.transactionsVersionAvailable since the API’s base version Webhook event creditnoteRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /CreditNotes | Update existing credit notes, or create new ones, in a single call. | write | accounting.transactions | Current | |
A POST to the collection updates or creates; matching is by CreditNoteID. Acts oncredit note Permission (capability) accounting.transactionsVersionAvailable since the API’s base version Webhook event creditnoteRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
ReportsRead accounting reports such as Profit and Loss, Balance Sheet, Trial Balance, and aged receivables and payables.4 | ||||||
| GET | /Reports/ProfitAndLoss | Retrieve the Profit and Loss report for a date range. | read | accounting.reports.read | Current | |
All report endpoints are read-only and need accounting.reports.read. Acts onreport Permission (capability) accounting.reports.readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /Reports/BalanceSheet | Retrieve the Balance Sheet report as at a date. | read | accounting.reports.read | Current | |
Read-only; needs accounting.reports.read. Acts onreport Permission (capability) accounting.reports.readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /Reports/TrialBalance | Retrieve the Trial Balance report as at a date. | read | accounting.reports.read | Current | |
Read-only; needs accounting.reports.read. Acts onreport Permission (capability) accounting.reports.readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /Reports/AgedReceivablesByContact | Retrieve the aged receivables report for a contact. | read | accounting.reports.read | Current | |
Requires a contactID parameter. Read-only; needs accounting.reports.read. Acts onreport Permission (capability) accounting.reports.readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
Xero can notify an app or AI agent when something changes in an organisation, like an invoice or a contact being created or updated. It posts a small payload naming what changed, so an integration learns about activity without polling.
| Event | What it signals | Triggered by |
|---|---|---|
INVOICE (CREATE / UPDATE) | Fires when a sales invoice or purchase bill is created or updated. The payload names the resource and event, and the receiver re-fetches the invoice from the API. | /Invoices/Invoices/Invoices |
CONTACT (CREATE / UPDATE) | Fires when a contact is created or updated. The payload names the resource and event, and the receiver re-fetches the contact from the API. | /Contacts/Contacts/Contacts |
CREDITNOTE (CREATE / UPDATE) | Fires when a credit note is created or updated. Credit note events are generally available and have their own payload schema. | /CreditNotes/CreditNotes/CreditNotes |
Xero limits how fast and how much an app or AI agent can call, through a per-minute and per-day quota counted separately for each connected organisation, plus a separate app-wide minute quota and a cap on how many requests run at once.
Xero counts calls against three limits at once. Each connected organisation may make 60 calls per minute and 5,000 calls per day, and across all the organisations connected to one app there is a 10,000-calls-per-minute app-wide limit. A separate concurrency limit caps an app at 5 requests running at once against a single organisation. Every response carries X-MinLimit-Remaining, X-DayLimit-Remaining, and X-AppMinLimit-Remaining headers reporting what is left against each. Going over returns HTTP 429 with an X-Rate-Limit-Problem header naming which limit was hit and a Retry-After header giving the seconds to wait.
List endpoints page through results with a page query parameter, returning up to 100 records per page, so an integration increments page until a short page comes back. Many endpoints also accept a modifiedAfter parameter (sent as the If-Modified-Since header) to fetch only records changed since a given time, which keeps a sync within the daily limit.
A page returns at most 100 records. The minute and daily counts reset on rolling windows per organisation, and the access token from an authorization-code flow lasts 30 minutes before it must be refreshed.
The status codes an agent should handle, and what to do about each.
| Status | Code | Meaning | What to do |
|---|---|---|---|
| 400 | ValidationException / Bad Request | The request failed validation. The body holds an ApiException element with an ErrorNumber, a Type such as ValidationException, and per-element error messages. | Read the validation messages, correct the named fields, and resend. The request is not retryable as-is. |
| 401 | Unauthorized | The access token is missing, expired, or revoked, often because a user disconnected the app from inside Xero. | Refresh the token, or send the user back through authorization to reconnect. |
| 403 | Forbidden | The token is valid but the requested scope is missing, or the connection is not permitted to reach the resource. | Add the missing scope to the connection and reauthorize, then retry. |
| 404 | Not Found | The resource does not exist, or it is not visible to the connected organisation named by Xero-tenant-id. | Verify the resource Id and that the call targets the correct organisation. |
| 429 | Too Many Requests | A rate limit was exceeded. The X-Rate-Limit-Problem header names which limit was hit (minute, daily, or app-wide minute), and a Retry-After header gives the seconds to wait. | Wait the number of seconds in Retry-After, then retry, and smooth the request rate to stay under the per-minute limit. |
| 500 | Internal Server Error | An error on Xero's side. It is rare and not caused by the request. | Retry with backoff, and contact Xero support if it persists. |
| 503 | Service Unavailable | Either the specific organisation is temporarily offline, or a rate limit returned 503 on older endpoints. An offline organisation can last several minutes while the API itself stays up. | Wait and retry after about five minutes for an offline organisation, or honour the Retry-After header for a rate limit. |
Xero pins the Accounting API at version 2.0 in the request path and ships changes through dated release notes and a changelog rather than minting a new path version.
The Accounting API is pinned at 2.0 in the request path at https://api.xero.com/api.xro/2.0. The path version is stable, so it does not change as features are added; changes ship through dated release notes and the developer changelog rather than a new path version. The two changes below are the most notable recent ones.
Credit note webhook events became generally available on 4 March 2026, the first new event on Xero's Horizon eventing platform. An app can now receive a notification when a credit note is created or updated, rather than polling, alongside the existing invoice and contact events.
Xero replaced the two broad accounting scopes with a set of finer per-resource scopes, so an app can request access to just invoices, just bank transactions, or a single report rather than a whole area. Apps created on or after 2 March 2026 can only use the granular scopes; apps created before that date keep the broad scopes until September 2027, when they must have migrated.
The 2.0 path version is stable; track the changelog for additive changes and scope deprecations.
Xero developer changelog ↗Bollard AI sits between a team's AI agents and Xero. Grant each agent exactly the access it needs, read or write, resource by resource, and every call is checked and logged.