Configuration
To set up the Xero source, provide the following configuration parameters:
| Key | Description | Sample Value | Required |
|---|
client_id | Client ID issued when you create your Xero app. | abcdefg | ✅ |
client_secret | Client secret generated when you create your Xero app. | abcdefg | ✅ |
tenant_id | Tenant ID associated with your Xero organization. | abcdefg | ✅ |
start_date | The start date for syncing data. Format: YYYY-MM-DDTHH:MM:SSZ. | 2021-01-01T00:00:00Z | ✅ |
refresh_token | OAuth refresh token (required if refresh_token_secret_name is not provided). | abcdefg | ⚠️ |
refresh_token_secret_name | Name of the Mage secret containing the refresh token (recommended for production). | XERO_REFRESH_TOKEN | ⚠️ |
You must provide either refresh_token or refresh_token_secret_name. Using refresh_token_secret_name is recommended because Xero uses rotating refresh tokens (each token can only be used once), and this option automatically persists the new token after each refresh.
Option 1: Direct Refresh Token
client_id: YOUR_CLIENT_ID
client_secret: YOUR_CLIENT_SECRET
tenant_id: YOUR_TENANT_ID
start_date: "2021-01-01T00:00:00Z"
refresh_token: YOUR_REFRESH_TOKEN
Xero refresh tokens are single-use. Each time the token is refreshed, a new one is issued and the old one is invalidated. With this option, the new token is only stored in memory during the sync, so subsequent pipeline runs may fail if the token has been rotated.
Option 2: Mage Secret (Recommended)
client_id: YOUR_CLIENT_ID
client_secret: YOUR_CLIENT_SECRET
tenant_id: YOUR_TENANT_ID
start_date: "2021-01-01T00:00:00Z"
refresh_token_secret_name: XERO_REFRESH_TOKEN
First, create a secret in Mage. You can choose any name for your secret:
- Open a pipeline edit page
- Expand the right side panel
- Click the “Secrets” tab
- Click “Add new secret”
- Enter your chosen secret name (e.g.,
XERO_REFRESH_TOKEN) and your initial refresh token as the value
- Copy the secret name to your Xero config’s
refresh_token_secret_name field
The tap will automatically update the secret with the new refresh token after each sync, ensuring reliable long-term operation.
Supported Streams
The Xero source supports the following streams:
Incremental Streams
These streams support incremental syncing based on the start_date configuration and bookmark state:
| Stream | Primary Key | Replication Key |
|---|
accounts | AccountID | UpdatedDateUTC |
bank_transactions | BankTransactionID | UpdatedDateUTC |
bank_transfers | BankTransferID | CreatedDateUTC |
contacts | ContactID | UpdatedDateUTC |
credit_notes | CreditNoteID | UpdatedDateUTC |
employees | EmployeeID | UpdatedDateUTC |
expense_claims | ExpenseClaimID | UpdatedDateUTC |
invoices | InvoiceID | UpdatedDateUTC |
items | ItemID | UpdatedDateUTC |
journals | JournalID | JournalNumber |
linked_transactions | LinkedTransactionID | UpdatedDateUTC |
manual_journals | ManualJournalID | UpdatedDateUTC |
overpayments | OverpaymentID | UpdatedDateUTC |
payments | PaymentID | UpdatedDateUTC |
prepayments | PrepaymentID | UpdatedDateUTC |
purchase_orders | PurchaseOrderID | UpdatedDateUTC |
quotes | QuoteID | UpdatedDateUTC |
receipts | ReceiptID | UpdatedDateUTC |
users | UserID | UpdatedDateUTC |
Full Table Streams
These streams are fully synced on each run (no incremental support):
| Stream | Primary Key |
|---|
branding_themes | BrandingThemeID |
contact_groups | ContactGroupID |
currencies | Code |
organisations | OrganisationID |
repeating_invoices | RepeatingInvoiceID |
tax_rates | TaxType |
tracking_categories | TrackingCategoryID |
How to Generate Credentials
To use this source, you need to create a Xero OAuth app and complete the OAuth flow.
1. Create a Xero App
Go to the Xero Developer Portal and create a new app. Note down your Client ID and Client Secret.
When setting up your Xero app, grant the following OAuth2 scopes:
| Scope | Required For |
|---|
accounting.settings.read | Organisation settings, currencies, etc. |
accounting.transactions.read | Invoices, bank transactions, payments |
accounting.contacts.read | Contacts |
accounting.reports.read | Reports |
accounting.journals.read | Journals |
accounting.attachments.read | Attachments |
offline_access | Long-lived access via refresh tokens |
- The minimum scope required for discovery is
accounting.settings.read.
- You only need scopes for the streams you plan to sync.
- Missing scopes for a selected stream will result in
401 or 403 errors.
Example Scope String:
accounting.settings.read accounting.transactions.read accounting.contacts.read accounting.reports.read accounting.journals.read accounting.attachments.read offline_access
3. Complete the OAuth2 Authorization Flow
Follow Xero’s OAuth2 Auth Flow Guide to obtain your initial access_token and refresh_token.
Make sure to request the offline_access scope to receive a refresh token.
4. Get Your Tenant ID
The tenant_id uniquely identifies your Xero organization. After completing OAuth authentication:
- Call the connections endpoint:
curl -X GET "https://api.xero.com/connections" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json"
- Extract the
tenantId from the response:
[
{
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"tenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"tenantType": "ORGANISATION",
"tenantName": "Your Company Name"
}
]
If your app is connected to multiple Xero organizations, the response will contain multiple entries. Choose the tenantId for the organization you want to sync data from.
| Key | Description | Sample Value | Required |
|---|
access_token | OAuth access token used to authenticate API requests. | abcdefg | ✅ |
id_token | Token containing user identity details (if OpenID Connect scopes are requested). | abcdefg | ✅ |
start_date | The start date for syncing data. Format: YYYY-MM-DDTHH:MM:SSZ. | 2021-01-01T00:00:00Z | ✅ |
client_id | Client ID issued when you create your Xero app. | abcdefg | ✅ |
client_secret | Client secret generated when you create your Xero app. | abcdefg | ✅ |
tenant_id | Tenant ID associated with your Xero organization. | abcdefg | ✅ |
refresh_token | Refresh token used to renew the access token after expiration (requires offline_access scope). | abcdefg | ✅ |
Required Xero OAuth2 Scopes
To use this source, you must grant your Xero app the following OAuth2 scopes.
Minimum Scope for Discovery
accounting.settings.read
Required for the /Currencies endpoint, which is called during discovery to verify:
- Your
access_token is valid
- Your
tenant_id is authorised
- The app has the correct scopes
If this scope is missing, discovery will fail before any sync begins.
Scopes for Syncing All Streams
To sync all available streams, grant the following scopes:
| Scope | Required For |
|---|
accounting.settings.read | Organisation settings, currencies, etc. |
accounting.transactions.read | Invoices, bank transactions, payments |
accounting.contacts.read | Contacts |
accounting.reports.read | Reports |
accounting.journals.read | Journals |
accounting.attachments.read | Attachments |
offline_access | Long-lived access via refresh tokens |
Note:
- You only need scopes for the streams you plan to sync.
- Missing scopes for a selected stream will result in
401 or 403 errors.
Example Scope String
accounting.settings.read
accounting.transactions.read
accounting.contacts.read
accounting.reports.read
accounting.journals.read
accounting.attachments.read
offline_access
How to Generate Credentials
Follow Xero’s OAuth 2.0 Authentication Flow guide to generate the required credentials:
- Register a new Xero app to get your
client_id and client_secret.
- Set up the OAuth scopes your app requires.
- Complete the OAuth 2.0 authorization flow to obtain your
access_token, refresh_token, id_token, and tenant_id.
- Store these securely in your configuration.
Additional Notes
- The
start_date determines how far back data will be synced.
- Ensure that the
offline_access scope is enabled to receive a refresh_token.
- Tokens expire after a set period; use the
refresh_token to obtain new access_token and id_token values automatically.
- During setup, the connector calls the
/Currencies endpoint to validate platform access before syncing.