Skip to content

Xero Integration Module

Synchronize invoices with Xero accounting software.

Field Value
Technical Name xero_integration
Version 15.0.1.0.0
Category Accounting
Dependencies account, sale
Python Dependencies xero_python, psycopg2

Overview

This module provides:

  • OAuth 2.0 connection to Xero
  • Automatic invoice sync when posted (non-blocking)
  • Contact auto-creation/matching in Xero
  • Payment sync via webhook + cron polling
  • Support for deposit, final, and regular invoices
  • Multi-company support
  • Sync logging for troubleshooting

Invoice Types

Deposit Invoice

Detected when down payment line has positive quantity (+1.00):

Odoo:                          Xero (Account 835):
------------------------       ------------------------
Downpayment (50%)  $2,700  ->  "Deposit for SO-001"
                               Qty: 1 | Amount: $2,700

Final Invoice

Detected when down payment line has negative quantity (-1.00):

Odoo:                          Xero (2 lines):
------------------------       ------------------------
Products        $5,400         Line 1: "SO-001 - Product - Customer" (400)
                                        Amount: $5,400
Downpayment    -$2,700         Line 2: "Less: Deposit Paid" (835)
                                        Amount: -$2,700
------------------------       ------------------------
Total Due:      $2,700         Total Due: $2,700

Regular Invoice

No down payment line present:

Odoo:                          Xero (Account 400):
------------------------       ------------------------
Products        $5,400    ->   "SO-001 - Product - Customer"
                               Qty: 1 | Amount: $5,400

Xero Accounts

Code Name Used For
400 Sales (default) Regular and final invoice project totals
835 Customer Deposits (default) Deposit invoice + deposit deduction

Account codes are configurable in the Xero connection settings.

Data Models

xero.account

Stores Xero OAuth connection and configuration.

Field Type Description
name Char Connection name
company_id Many2one Link to res.company
client_id Char Xero app client ID
client_secret Char Xero app client secret
redirect_uri Char OAuth redirect URI
webhook_key Char Webhook signature verification key
access_token Text Current access token
refresh_token Text Refresh token
token_expires Datetime Token expiration time
tenant_id Char Xero organization ID
tenant_name Char Xero organization name
downpayment_product_id Many2one Down payment product for detection
payment_journal_id Many2one Journal for incoming payments
sales_account_code Char Xero sales account (default: 400)
deposit_account_code Char Xero deposit account (default: 835)
connection_status Selection disconnected / connected / error
last_sync Datetime Last invoice sync
last_payment_sync Datetime Last payment sync

xero.sync.log

Logs all sync operations for troubleshooting.

Field Type Description
name Char Log entry name
model Char Related model (account.move, etc.)
res_id Integer Related record ID
direction Selection inbound / outbound
status Selection success / error
error_message Text Error details
response_data Text API response data (JSON)

Extended Fields

res.partner:

Field Type Description
xero_contact_id Char Xero contact GUID
xero_sync_date Datetime Last sync timestamp

account.move:

Field Type Description
xero_invoice_id Char Xero invoice GUID
xero_sync_status Selection pending / synced / error
xero_sync_date Datetime Last sync timestamp
xero_sync_error Text Error message

Configuration

1. Xero Developer Portal

  1. Create app at https://developer.xero.com
  2. App type: Web app
  3. Set redirect URI: https://your-odoo-domain.com/xero/callback
  4. Copy Client ID and Client Secret
  5. For webhooks, note your Webhook Key

2. Odoo Setup

Navigate to Accounting > Configuration > Xero Connections:

  1. Click Create
  2. Fill in connection details:
Field Description Example
Connection Name Display name "Production Xero"
Company Odoo company Your Company
Client ID From Xero portal ABC123...
Client Secret From Xero portal secret...
Redirect URI OAuth callback https://odoo.example.com/xero/callback
Webhook Key For signature verification webhook-key...
Down Payment Product Product for DP detection "Down Payment"
Payment Journal Bank/cash journal "Bank"
Sales Account Code Xero sales account "400"
Deposit Account Code Xero deposit account "835"
  1. Click Connect to Xero button
  2. Authorize access in Xero popup
  3. Verify connection shows Connected

3. Python Dependencies

# Install required packages
docker compose exec odoo pip install xero-python

Contact Matching

When syncing an invoice, contacts are matched in this order:

  1. Use existing xero_contact_id if already linked
  2. Search Xero by email (exact match)
  3. Search Xero by name (exact match)
  4. Create new contact in Xero

Invoice Sync

Automatic Sync

Invoices are automatically synced to Xero when posted:

  • Sync is non-blocking - invoice posts even if Xero sync fails
  • Errors are logged and can be retried manually
  • Only customer invoices (out_invoice) and credit notes (out_refund) are synced

Manual Sync

For failed syncs, use the Sync to Xero button on the invoice form.

Invoice Type Detection

The module detects invoice type by checking for down payment lines:

# Down payment detection (in order):
1. Product ID matches configured downpayment_product_id
2. Product name contains: "down payment", "downpayment", "deposit", "advance"

# Type determination:
- No DP line      -> Regular invoice
- DP qty > 0      -> Deposit invoice
- DP qty < 0      -> Final invoice (with deposit deduction)

Payment Sync

Webhook (Real-time)

Configure webhook in Xero developer portal:

  1. URL: https://your-odoo-domain.com/xero/webhook
  2. Events: Invoice payments

Cron Polling (Backup)

Scheduled job runs every 15 minutes:

  • Queries Xero for invoices with status "PAID"
  • Creates payment records in Odoo
  • Reconciles with invoice

Payment processing is idempotent - safe to process the same payment multiple times.

Module Structure

xero_integration/
├── __manifest__.py
├── __init__.py
├── webhook_middleware.py       # WSGI middleware for webhooks
├── controllers/
│   ├── __init__.py
│   ├── oauth.py               # OAuth callback handler
│   └── webhook.py             # Payment webhook handler
├── models/
│   ├── __init__.py
│   ├── xero_account.py        # OAuth connection & config
│   ├── xero_sync_log.py       # Sync logging
│   ├── account_move.py        # Invoice extension
│   └── res_partner.py         # Contact extension
├── views/
│   ├── oauth_templates.xml    # OAuth success/error pages
│   ├── xero_account_views.xml
│   ├── xero_sync_log_views.xml
│   ├── account_move_views.xml
│   └── res_partner_views.xml
├── security/
│   └── ir.model.access.csv
└── data/
    └── ir_cron.xml            # Payment sync cron job

OAuth Scopes

Required Xero OAuth scopes:

Scope Purpose
offline_access Refresh token support
accounting.transactions Create/read invoices
accounting.contacts Create/read contacts
accounting.settings Read account settings

Development Setup

For local development with ngrok:

# Start Odoo
docker compose up -d

# Start ngrok tunnel
ngrok http 8015

# Copy ngrok URL (e.g., https://abc123.ngrok.io)
# Update in Xero Developer Portal:
#   - Redirect URI: https://abc123.ngrok.io/xero/callback
#   - Webhook URL: https://abc123.ngrok.io/xero/webhook

Troubleshooting

Connection Failed

  1. Verify Client ID and Secret are correct
  2. Check redirect URI matches exactly (including https)
  3. Ensure Odoo is accessible from internet for OAuth callback

Invoice Sync Failed

  1. Check sync log: Accounting > Configuration > Xero Sync Log
  2. Verify Xero connection is active
  3. Use Sync to Xero button to retry
  4. Check Odoo logs for detailed error

Payment Not Syncing

  1. Verify webhook is configured in Xero
  2. Check payment journal is configured
  3. Run manual sync: Accounting > Configuration > Xero Connections > Poll Payments
  4. Check cron job is running (every 15 minutes)

Token Expired

Token refresh is automatic. If issues persist:

  1. Click Disconnect in Xero connection
  2. Click Connect to Xero to re-authorize

API Reference

Xero API Endpoints

Endpoint Method Purpose
login.xero.com/identity/connect/authorize GET OAuth authorization
identity.xero.com/connect/token POST Token exchange/refresh
api.xero.com/connections GET Get tenant info
api.xero.com/api.xro/2.0/Invoices POST Create invoice
api.xero.com/api.xro/2.0/Contacts GET/POST Contact operations