ml-connector
XeroProcore

Xero and Procore integration

Xero keeps your accounting records. Procore tracks your project costs and commitments. When a purchase order is created in Xero, contractors and materials should already be reflected in Procore's project budget. ml-connector moves purchase orders and invoices from Xero into Procore as requisitions and committed costs, so your project budgets stay aligned with what you are actually buying. Invoices post to the right cost code, vendors are matched by name, and the amounts flow into Procore's budget tracking without re-keying.

How Xero works

Xero is a cloud-based accounting platform with REST APIs for invoices, purchase orders, contacts, accounts, payments, and manual journals. It uses OAuth2 authorization code flow with access tokens that expire in 30 minutes and refresh tokens good for 60 days. Xero requires a tenant ID header on every request and publishes webhook events for invoice, purchase order, payment, and manual journal creates and updates, although the webhook payload contains only metadata and requires a follow-up GET to fetch the full record. Xero also supports polling via If-Modified-Since headers. It enforces a 5 concurrent call limit, 60 calls per minute per tenant, and 5000 per day per tenant.

How Procore works

Procore is a construction management platform tracking projects, costs, budgets, vendors, purchase order contracts, requisitions, and change orders through REST APIs. It uses OAuth2 client credentials with tokens expiring in 1.5 hours, and every endpoint requires a company ID and most project-scoped calls require a project ID. Procore has no standalone general ledger accounts; cost codes and cost types serve as the budget dimension. It publishes webhooks for commitments, requisitions, direct costs, budget changes, and vendors, with security enforced via custom headers rather than HMAC signatures. Webhooks must respond with 2xx status within 5 seconds. Procore does not use OAuth scopes; access is controlled by tool permissions on the developer managed service account.

What moves between them

The main flow is Xero to Procore. Purchase orders created in Xero flow into Procore as requisitions or commitment line items, with the vendor matched to an existing Procore vendor record by name or created if new. The invoice line items map to Procore cost codes based on account number and item type. Approved invoices in Xero trigger payment applications in Procore to move the commitment toward paid status. Contact records in Xero sync to Procore vendors if not already present. Tracking categories in Xero are mapped to Procore budget line item codes so cost allocations land on the right cost center within each project.

How ml-connector handles it

ml-connector stores both credential sets encrypted and refreshes the Xero OAuth token every 20 minutes before the 30-minute expiry, and the Procore client credentials token at 1 hour to avoid errors. On the Xero side it subscribes to purchase order and invoice webhooks but also polls on a daily schedule using If-Modified-Since to catch any changes the webhooks may have missed, since Xero webhook delivery is not guaranteed. When a purchase order arrives, ml-connector looks up the vendor contact in Xero by name and searches Procore for a matching vendor; if no match is found it creates a new vendor record in Procore with the contact address and phone from Xero. Line items are mapped to Procore cost codes via a lookup table keyed by the Xero account code and item category. Each purchase order becomes a Procore requisition with the line items, and the total is checked against the project budget in Procore; if it exceeds the budget, ml-connector flags the record in the audit log and waits for manual approval before posting. Invoices follow the same path and become payment applications in Procore once they are marked paid in Xero. Xero tenant ID is required per customer, so ml-connector stores it encrypted per tenant and validates it on every request.

A real-world example

A mid-sized construction general contractor uses Xero for accounting and Procore for project tracking. Before the integration, the accounting team issued purchase orders in Xero but the construction managers had to manually enter each commitment into Procore, often with data entry errors and a lag of one to two days. Invoices would arrive, be coded in Xero, and then the amounts would have to be re-entered into Procore to track project cost against budget. With Xero and Procore connected, each purchase order appears in Procore within minutes as a requisition, matched to the right cost code and vendor, and invoices automatically flow through as payment applications so the project manager can see real-time spend against budget without waiting for the accounting team to update the system manually.

What you can do

  • Sync purchase orders from Xero into Procore as requisitions with vendors and cost codes matched to existing data.
  • Convert approved Xero invoices into Procore payment applications to track committed spend and budget consumption per project.
  • Create new vendor records in Procore from Xero contacts when a vendor in a purchase order does not match an existing Procore vendor.
  • Map Xero accounts and item categories to Procore cost codes based on your account numbering scheme and cost structure.
  • Refresh OAuth2 credentials automatically and poll Xero daily to catch changes beyond webhook delivery, with a full audit trail on every record.

Questions

Which direction does data move between Xero and Procore?
The main flow is Xero to Procore. Purchase orders and approved invoices from Xero are written to Procore as requisitions and payment applications. Vendor and project cost code reference data flows both directions so requisitions and invoices are matched to the right Procore budget line items. Procore does not write back to Xero; the accounting system is the source of truth.
How does the integration handle Xero's per-tenant authentication and webhook metadata?
ml-connector stores the Xero tenant ID encrypted per customer and includes it on every API call. Xero webhook events contain only metadata and resource IDs, so ml-connector immediately fetches the full purchase order or invoice record via a follow-up GET call to have complete data for the Procore write. It also polls Xero daily using If-Modified-Since headers to catch any changes webhooks may have missed.
What happens if a vendor in a Xero purchase order does not exist in Procore?
ml-connector searches Procore vendors by name first. If no match is found, it creates a new vendor record in Procore with the contact address and phone from Xero. A lookup table maps Xero account codes to Procore cost codes, so line items are written to the right budget dimension even if the vendor is new.

Related integrations

Connect Xero and Procore

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

Get started