ml-connector
XeroZuora

Xero and Zuora integration

Xero runs your general ledger and accounts. Zuora runs your subscription billing and order-to-cash. Connecting the two keeps your revenue recognized and accounts reconciled without re-keying. Invoices generated by Zuora after each billing run post automatically into Xero, mapped to the correct revenue and AR accounts. Payments received in Zuora update cash accounts in Xero in real time. ml-connector handles the multi-region Zuora URLs, OAuth2 on both sides, and the full record flow from billing to accounting.

How Xero works

Xero Accounting API exposes invoices, purchase orders, payments, contacts, accounts, tracking categories, items, manual journals, credit notes, and bank transactions through REST endpoints at https://api.xero.com/api.xro/2.0/. Authentication uses OAuth2 Authorization Code flow with 30-minute access tokens and 60-day refresh tokens. Xero publishes webhooks for invoices, credit notes, payments, manual journals, purchase orders, and bank transactions on CREATE and UPDATE events. Webhook payloads contain metadata only, requiring a follow-up GET to fetch the full record. All requests require the Xero-tenant-id header to target a specific organization. Rate limits are 5 concurrent calls, 60 per minute per tenant, and 5000 per day per tenant.

How Zuora works

Zuora is a subscription billing platform handling orders, subscriptions, invoices, payments, and revenue recognition through a multi-region REST API. The base URL varies by region (rest.zuora.com, rest.eu.zuora.com, rest.ap.zuora.com, and sandbox variants). Authentication uses OAuth2 Client Credentials grant with one-hour tokens. Zuora publishes Callout Notifications as webhooks for billing events (invoices posted, due, and collected), payment events, subscription lifecycle changes, and account updates. Webhook payloads are minimal and require a callback to fetch full details. Payment notifications fire only for electronic payments, not external or manual entries. Rate limits are 50,000 requests per minute in production, with a fixed 25-second timeout on webhook callbacks.

What moves between them

Invoices created in Zuora post automatically into Xero's general ledger when the Zuora invoice is marked posted. Payments received in Zuora flow into Xero cash and AR accounts in real time. Both directions use the same account and tracking category mappings so revenue recognition and cash reconciliation are accurate from the start. The sync runs on a cadence tied to your billing cycle rather than waiting for individual webhooks, ensuring batch invoice runs post completely into Xero before the next cycle begins.

How ml-connector handles it

ml-connector stores Xero OAuth2 credentials and Zuora's multi-region base URL and client credentials, refreshing each token when a request returns 401 or after the token expiry window. It registers a webhook endpoint with both systems and validates incoming Zuora Callout Notifications with HMAC-SHA256 signatures, discarding invalid or replay requests. When a Zuora invoice or payment arrives, ml-connector maps the Zuora account, product, and amount to the pre-configured Xero accounts and tracking categories, then posts a manual journal or payment into Xero's general ledger. Because Zuora webhook payloads are metadata-only, ml-connector calls back to Zuora to fetch the full invoice or payment record before posting. Invoices and payments are deduplicated by their Zuora identifiers so accidental replays do not create duplicate GL entries. Xero's 30-minute token expiry is handled transparently; failed requests that need a new token are retried without blocking the pipeline. The full trace of every record, from Zuora receipt through Xero GL posting, is stored in the audit log.

A real-world example

A SaaS company with 200 customers runs Zuora for subscription management and Xero for accounting. Before the integration, the finance team received Zuora invoice reports each billing cycle and manually entered revenue and AR transactions into Xero, a process that took two to four hours and frequently introduced errors. With Zuora and Xero connected, subscription invoices and payments flow automatically into Xero's general ledger, allocated to the correct revenue and AR accounts. The finance team now spends the time saved on month-end reconciliation instead of transaction entry, and the trial balance balances the same day billing runs complete.

What you can do

  • Post Zuora subscription invoices into Xero's general ledger automatically, mapped to the correct revenue accounts and tracking categories.
  • Sync Zuora customer payments into Xero cash and AR accounts in real time, keeping your trial balance current.
  • Handle multi-region Zuora URLs and client credentials, and refresh OAuth2 tokens on both sides automatically.
  • Deduplicate Zuora invoices and payments by identifier, so webhook retries and re-deliveries do not create duplicate GL entries.
  • Validate Zuora Callout Notification signatures with HMAC-SHA256 and retry failed Xero postings with a full audit trail.

Questions

Which direction does data flow between Xero and Zuora?
The main flow is Zuora into Xero. Subscription invoices and payments move from Zuora into Xero's general ledger, mapped to revenue and AR accounts. Reference data such as account mappings and tracking categories is configured once and reused for every invoice and payment that flows through.
How does the integration handle Zuora's multi-region URLs and webhook limitations?
ml-connector stores the full Zuora base URL per customer, since each tenant has a region-specific endpoint. It registers a webhook endpoint with Zuora and validates incoming Callout Notifications with HMAC-SHA256 signatures. Because Zuora webhook payloads contain only object IDs, ml-connector calls back to Zuora to fetch the full invoice or payment record before posting to Xero.
What happens if an OAuth2 token expires or a Zuora payment webhook is retried?
ml-connector refreshes Xero's 30-minute access tokens and Zuora's one-hour tokens transparently, retrying the request without blocking the pipeline. Duplicate payments and invoices are blocked by deduplication on the Zuora identifier, so webhook retries and platform retries do not create duplicate GL entries.

Related integrations

Connect Xero and Zuora

Free to use. Add your credentials, ping your real systems, and see if we fit.

Get started