Prompt
How do I write journal entries to Xero from a SaaS app?
Latest observation
To write journal entries into Xero from a SaaS app, you typically use the Xero Accounting API with OAuth 2.0 authentication.
High-level flow
- Register your app in the Xero Developer portal.
- Authenticate the user/company via OAuth 2.0.
- Get an access token and use the tenant ID for the organization.
- POST a journal or accounting transaction to Xero using the appropriate endpoint.
- Store Xero IDs in your app for reconciliation and updates.
Important note
Xero does not generally let third-party apps create arbitrary “general journal entries” the same way a human can in the Xero UI unless you use the supported API endpoints for the specific accounting object. In many cases, integrations use:
- Invoices / Bills / Credit Notes / Bank Transactions if the entry represents a business transaction
- Manual Journals API if you need to create actual journal entries and your app has the required permissions
Typical setup
1) Create a Xero app
In the Xero Developer portal, create an app and note:
- Client ID
- Client Secret
- Redirect URI
2) Request scopes
For journal-related access, your app will need the relevant accounting scopes, commonly:
accounting.transactionsaccounting.journals.readaccounting.journalsif supported for your use case- plus other accounting scopes depending on what you create
Check Xero’s current scope list because exact permissions vary by API/version.
3) OAuth 2.0 authorization
Send the user to Xero’s authorization URL, get an authorization code, then exchange it for:
- access token
- refresh token
4) Get the tenant ID
Xero is multi-tenant. After auth, call the connections endpoint to find the tenantId for the org you want to post to.
5) Create the journal entry
Use the API endpoint for manual journals if available to your app and org.
A manual journal usually looks like this conceptually:
{
"Narration": "Monthly SaaS revenue recognition",
"JournalLines": [
{
"AccountCode": "200",
"Description": "Deferred revenue",
"NetAmount": 100.00,
"TaxType": "NONE"
},
{
"AccountCode": "400",
"Description": "Recognized revenue",
"NetAmount": -100.00,
"TaxType": "NONE"
}
]
}
Example API call pattern
POST https://api.xero.com/api.xro/2.0/ManualJournals
Authorization: Bearer {access_token}
Xero-tenant-id: {tenant_id}
Content-Type: application/json
Important constraints
- Journal lines must balance to zero.
- Account codes must exist in the Xero chart of accounts.
- Some fields may be read-only or restricted depending on the API and organization settings.
- You should make requests idempotent on your side to avoid duplicate journals if retries happen.
- Respect Xero rate limits.
Recommended SaaS design
For a production integration:
- Keep a mapping of your internal objects to Xero IDs
- Queue journal creation jobs
- Retry with backoff on transient failures
- Refresh tokens automatically
- Log request/response IDs for support
If you want, I can provide:
- A Node.js example using Xero OAuth + journal creation
- A Python example
- The exact API payload for manual journals
- Guidance on whether you should use manual journals vs invoices/bank transactions for your use case