Xero Purchase Orders SQL Template

SQL table creation template for syncing Xero purchase order data to your PostgreSQL database.

Updated: 9 Feb 2026

Xero Purchase Orders SQL Template

Create a database table to store Xero purchase order data including contact details, amounts, delivery dates, and status tracking.

What Data is Synced?

The Xero Purchase Orders sync captures purchase order information from your Xero account:

  • Purchase Order ID: Unique Xero purchase order identifier
  • Tenant ID: Xero organization ID for multi-org support
  • Purchase Order Number: User-facing purchase order number
  • Contact Details: Contact ID and name linked to the purchase order
  • Purchase Order Date: Date the purchase order was created
  • Delivery Date: Expected delivery date
  • Status: DRAFT, SUBMITTED, AUTHORISED, BILLED, or DELETED
  • Reference: User-defined reference text
  • Amounts: Subtotal, total tax, and total
  • Currency: Three-letter currency code
  • Sent to Contact: Whether the PO has been sent to the contact
  • Complete Data: Full Xero purchase order object stored as JSONB
  • Sync Tracking: Timestamp of when CLS last synced this record

SQL Table Template

Table Schema Explanation

Here's what each column in the table represents:

ColumnTypeDescription
idTEXTXero purchase order ID. Part of composite primary key.
tenant_idTEXTXero organization ID. Part of composite primary key.
purchase_order_numberTEXTUser-facing purchase order number.
contact_idTEXTXero contact ID linked to this purchase order.
contact_nameTEXTContact display name at time of purchase order.
purchase_order_dateDATEDate the purchase order was created.
delivery_dateDATEExpected delivery date.
statusTEXTPurchase order status: DRAFT, SUBMITTED, AUTHORISED, BILLED, or DELETED.
referenceTEXTUser-defined reference text.
subtotalNUMERIC(15,2)Purchase order subtotal before tax.
total_taxNUMERIC(15,2)Total tax amount.
totalNUMERIC(15,2)Total purchase order amount including tax.
currency_codeTEXTThree-letter ISO currency code (e.g., GBP, USD).
sent_to_contactBOOLEANWhether the purchase order has been sent to the contact.
dataJSONBComplete Xero purchase order object stored as JSON.
livemodeBOOLEANWhether this is production data.
updated_date_utcTIMESTAMPTZTimestamp when purchase order was last modified in Xero.
synced_atTIMESTAMPTZTimestamp when CLS last synced this purchase order record. Auto-updated.

The table uses a composite primary key (id, tenant_id) to support syncing purchase orders from multiple Xero organizations to the same table.

Usage Examples

After syncing, you can query your purchase order data using standard SQL:

-- Get all authorised purchase orders
SELECT id, purchase_order_number, contact_name, total, status
FROM xero_purchase_orders
WHERE status = 'AUTHORISED'
ORDER BY purchase_order_date DESC;

-- Purchase orders by contact
SELECT contact_name, COUNT(*) AS count, SUM(total) AS total_amount
FROM xero_purchase_orders
WHERE status IN ('AUTHORISED', 'BILLED')
GROUP BY contact_name
ORDER BY total_amount DESC;

-- Upcoming deliveries
SELECT purchase_order_number, contact_name, delivery_date, total
FROM xero_purchase_orders
WHERE delivery_date >= CURRENT_DATE AND status = 'AUTHORISED'
ORDER BY delivery_date ASC;

-- Overdue deliveries
SELECT purchase_order_number, contact_name, delivery_date, total
FROM xero_purchase_orders
WHERE delivery_date < CURRENT_DATE AND status = 'AUTHORISED'
ORDER BY delivery_date ASC;

-- Monthly purchase order summary
SELECT
  DATE_TRUNC('month', purchase_order_date) AS month,
  COUNT(*) AS count,
  SUM(total) AS total_amount
FROM xero_purchase_orders
WHERE status IN ('AUTHORISED', 'BILLED')
GROUP BY DATE_TRUNC('month', purchase_order_date)
ORDER BY month DESC;

-- Status distribution
SELECT status, COUNT(*) AS count, SUM(total) AS total_amount
FROM xero_purchase_orders
GROUP BY status
ORDER BY count DESC;

-- Purchase orders by currency
SELECT currency_code, COUNT(*) AS count, SUM(total) AS total
FROM xero_purchase_orders
WHERE status IN ('AUTHORISED', 'BILLED')
GROUP BY currency_code;

-- Purchase orders not yet sent to contact
SELECT purchase_order_number, contact_name, total, status
FROM xero_purchase_orders
WHERE sent_to_contact = false AND status = 'AUTHORISED'
ORDER BY purchase_order_date DESC;

Common Customizations

The template includes performance indexes for tenant_id, purchase_order_number, contact_id, status, purchase_order_date, delivery_date, livemode, and updated_date_utc columns. You can add additional table-specific customizations:

Add Index for Currency-Based Queries

CREATE INDEX idx_xero_purchase_orders_currency
ON xero_purchase_orders(currency_code);

Add Compound Index for Contact Date Range Queries

CREATE INDEX idx_xero_purchase_orders_contact_date
ON xero_purchase_orders(contact_id, purchase_order_date)
WHERE status IN ('AUTHORISED', 'BILLED');

Add Index for Upcoming Deliveries

CREATE INDEX idx_xero_purchase_orders_delivery_pending
ON xero_purchase_orders(delivery_date)
WHERE status = 'AUTHORISED';