ml-connector
XeroHubSpot

Xero and HubSpot integration

Xero runs your accounting. HubSpot runs your sales and customer data. When the two are connected, new customers added to Xero flow into HubSpot as companies, and Xero invoices appear as HubSpot commerce objects so your sales team can see the complete customer journey including what they owe. Payments logged in Xero update the payment status in HubSpot. ml-connector handles the different OAuth2 flows on each side and keeps both systems in sync without manual re-entry.

How Xero works

Xero exposes invoices, purchase orders, contacts, payments, accounts, credit notes, bank transactions, and manual journals through the Xero Accounting API, a REST interface at https://api.xero.com/api.xro/2.0/. Xero uses OAuth2 Authorization Code flow with 30-minute access tokens and 60-day refresh tokens (using offline_access scope). Each tenant is identified by a Xero-tenant-id header on every call. Xero publishes webhooks for Contact, Invoice, CreditNote, Payment, ManualJournal, PurchaseOrder, and BankTransaction events (CREATE and UPDATE only), but webhook payloads contain metadata only, so a follow-up GET is required to fetch the full record. Webhooks are signed with a separate key obtained from the Developer portal. Xero rate limits are strict: 5 concurrent calls, 60 per minute per tenant, and 5000 per day per tenant. Invoices and bills share the same endpoint and are differentiated by a Type field (ACCREC for AR, ACCPAY for AP).

How HubSpot works

HubSpot exposes contacts, companies, deals, invoices, line items, products, payments, orders, and tickets through REST APIs at https://api.hubapi.com with date-versioned paths. HubSpot supports both Private App Access Tokens (Bearer token, format pat-na1-) for server-to-server integrations and OAuth2 for marketplace apps. Webhook subscriptions require a separate Public App registration; webhook events are signed (v1, v2, or v3) and must be verified. Invoices and commerce objects are in public beta as of January 2026 and require associations to contacts and line items to be valid. HubSpot uses cursor-based pagination with a 200-record limit per page and enforces rate limits by tier (100 per 10 seconds for Free/Starter, 190 per 10 seconds for Professional/Enterprise). The Search API covers up to 10,000 records; larger datasets require the Lists API or CRM Export. Batch operations are capped at 100 records per request.

What moves between them

Contacts flow from Xero into HubSpot as companies. Xero invoices (Type ACCREC, accounts receivable) sync into HubSpot as invoice objects, creating line items from the invoice line details and associating them to the matching HubSpot company. Payments recorded in Xero update the payment status on the corresponding HubSpot invoice. The primary flow is read from Xero and write to HubSpot. Data syncs on a schedule you control, polling both sides to capture changes created outside the integration.

How ml-connector handles it

ml-connector stores Xero OAuth2 credentials (access and refresh tokens) and uses the offline_access scope to keep sessions alive. It presents the Xero-tenant-id header on every call to target the correct organization. On the HubSpot side, ml-connector uses a Private App Access Token (pat-na1-) for authentication. For webhook support, ml-connector verifies Xero webhook signatures using the signing key from the Developer portal, and verifies HubSpot webhooks using the configured webhook secret (v1, v2, or v3 signature format). When polling, ml-connector respects Xero's rate limits (5 concurrent, 60 per minute) and HubSpot's tier-based rate limits (100-190 per 10 seconds) by queuing requests and backing off on 429 responses. Contacts from Xero (with Xero ContactNumber as external ID) map to HubSpot companies; if a matching company exists, the contact is updated, otherwise a new company is created. Xero invoices become HubSpot invoices with line items; the invoice number and Xero InvoiceID provide matching keys for updates. Payment records update the invoice payment status in HubSpot. Webhook events trigger immediate pulls of the affected record to ensure the freshest data reaches HubSpot. Every record carries a full audit trail for replay if an update fails.

A real-world example

A B2B services firm runs Xero for accounting and HubSpot for sales pipeline and customer relationship management. Before the integration, sales reps had no visibility into customer payment status or invoice details inside HubSpot; they tracked invoices in a separate tab or asked finance for updates. Finance team manually entered new customers from Xero into HubSpot, risking duplicates and stale data. With Xero and HubSpot connected, every customer added to Xero appears in HubSpot within minutes, and sales reps see the complete invoice history and payment status for every deal and contact without leaving HubSpot. Reconciliation between the two systems happens automatically, and the manual entry step is eliminated.

What you can do

  • Sync Xero customers (contacts) into HubSpot as companies with matching records updated instead of duplicated.
  • Map Xero invoices into HubSpot commerce objects with line items, pricing, and account associations.
  • Update HubSpot invoice payment status when payments are recorded in Xero.
  • Handle Xero OAuth2 token refresh and HubSpot Private App authentication with webhook signature verification for both systems.
  • Respect rate limits on both sides (Xero 5 concurrent/60 per minute, HubSpot 100-190 per 10 seconds) and poll on your schedule with retries and a full audit trail.

Questions

Which direction does data move between Xero and HubSpot?
The primary direction is Xero to HubSpot. Contacts from Xero become companies in HubSpot, and Xero invoices become HubSpot commerce objects. Payments recorded in Xero update the payment status on HubSpot invoices. Reference data such as account mapping is maintained in both directions so invoices land on the correct accounts. Read-only reference data in HubSpot means ml-connector does not write back to Xero.
How does ml-connector handle Xero's requirement for a Xero-tenant-id header and webhook signing key?
ml-connector stores the Xero tenant ID per customer and includes it on every Xero API request. The webhook signing key is obtained from the Xero Developer portal (separate from the OAuth client secret) and used to verify webhook signatures before processing. Both are stored encrypted in the cell, and ml-connector validates signature format before updating any HubSpot record based on a Xero webhook event.
What happens when HubSpot invoices are in public beta?
HubSpot's commerce invoice objects are new (beta as of January 2026) and require associations to contacts (companies) and line items to be valid. ml-connector creates those associations automatically from Xero line detail, ensuring every invoice can be written. If HubSpot updates the invoice schema or API contract, ml-connector will adapt; in the interim, invoices sync as commerce objects with full line-level detail.

Related integrations

Connect Xero and HubSpot

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

Get started