AFI AFI

Xero

Estimated reading: 6 minutes Updated August 1, 2026

Xero is a cloud accounting platform for small and medium businesses. Advanced Form Integration creates and updates contacts and invoices in Xero from your WordPress form submissions, so every quote request, customer sign-up, or WooCommerce order can flow straight into your books without retyping.

What you’ll need

  • A Xero account (a free trial works for testing).
  • A Xero OAuth2 app (see below).
  • The Advanced Form Integration plugin installed and activated.

Create a Xero OAuth2 app

Xero uses OAuth2 for all API access. You need to register an app in the Xero Developer Portal to get a Client ID and Client Secret.

  1. Sign in to the Xero Developer Portal and create a new app of type Web app.
  2. Copy the Redirect URI shown in the AFI Xero settings tab and paste it into the app’s allowed redirect URIs.
  3. Note the Client ID and Client Secret.
  4. The app needs these scopes at minimum: accounting.contacts, accounting.transactions, and offline_access. AFI also requests openid profile email automatically.

The offline_access scope is what lets AFI keep working after the first hour. Xero access tokens expire after 30 minutes; the refresh token (granted by this scope) lets AFI renew them silently. Without it, the connection dies within an hour and you have to re-authorize manually.

Connect Xero to AFI

  1. In WordPress, go to AFI → Settings and open the Xero tab.
  2. Click Add New Account, fill in Client ID and Client Secret, and give the account a name.
  3. Click Save & Authorize. You’ll be redirected to Xero to grant consent.
  4. After consent, AFI fetches the list of Xero organisations your token has access to. Pick the one this integration should write to.

A single Xero token can cover multiple organisations (tenants). AFI caches the organisation list for one hour, so it may take a moment to refresh after you add a new org in Xero.

Create the integration

  1. Go to AFI → Add New.
  2. Give the integration a name, for example Quote form to Xero.
  3. Under Trigger, pick the form plugin and the specific form you want to listen on.
  4. Under Action → Platform, select Xero.
  5. In Task, choose Create / Update Contact or Create Invoice.
  6. Pick the saved account in the Xero Account dropdown.
  7. Pick the Organisation (tenant) to write to.
  8. Map your form fields onto the Xero fields listed below.
  9. Optional: open Conditional Logic to limit which submissions are sent.
  10. Click Save Integration.

Tasks supported

Create / Update Contact

Creates a contact in Xero via POST /Contacts. If you map an existing Contact ID, or AFI finds a match by Contact Number or Email Address, the existing record is updated instead of duplicated. This upsert behavior means a returning customer on the same email updates their own contact record, not a clone.

Field Field key Required Notes
Existing Contact ID contact_id No Skip creation, update directly
Contact Number contact_number No Stable external ID; used for upsert
Name name Yes* Falls back to “First Last”
First Name first_name No
Last Name last_name No
Email Address email_address No Also used for upsert lookup
Phone (Default) phone_default No
Phone (Mobile) phone_mobile No
Billing Address Line 1 address_line1 No
Billing Address Line 2 address_line2 No
City city No
Region / State region No
Postal / ZIP Code postal_code No
Country country No
Tax Number tax_number No
Company Number company_number No

* Name is required by Xero when no Contact ID is provided. If you leave it blank but fill in First Name and Last Name, AFI joins them automatically.

Create Invoice

Creates an accounts-receivable invoice (Type: ACCREC) in Xero via POST /Invoices. If a Contact ID is provided, the invoice is attached to that contact. Otherwise AFI creates or upserts the contact from the mapped contact fields first, then creates the invoice against it.

Invoice line items must be supplied as a JSON array in the Line Items field. Each line needs Description, Quantity, UnitAmount, and AccountCode:

[{"Description":"Consulting service","Quantity":1,"UnitAmount":150.00,"AccountCode":"200"}]

Field Field key Required Notes
Existing Contact ID contact_id No If empty, contact is created from mapped fields
Reference reference No Shows on the invoice in Xero
Invoice Number invoice_number No Overrides Xero auto-numbering
Invoice Date date No YYYY-MM-DD
Due Date due_date No YYYY-MM-DD
Currency Code currency_code No ISO 4217, e.g. USD, GBP, AUD
Status status No DRAFT (default), SUBMITTED, or AUTHORISED
Line Amount Types line_amount_types No Exclusive, Inclusive, or NoTax
Line Items (JSON) lines_json Yes JSON array of line item objects
Send Email send_email No true/false; only works on AUTHORISED invoices

Pro features

The Pro integration adds WooCommerce auto-fill, so WooCommerce orders can create Xero contacts and invoices without manual field mapping. Pro uses the same connection and tasks as the free version.

WooCommerce contact auto-fill

When the trigger is a WooCommerce order, enable Auto-fill contact from billing fields and AFI maps billing_first_name, billing_last_name, billing_company, billing_email, billing_phone, and the billing address fields onto the Xero contact body automatically. It also sets ContactNumber to wc-{user_id} (or a hash of the billing email for guest checkouts), so repeat orders update the same Xero contact instead of creating duplicates.

WooCommerce invoice line items

Enable Build invoice lines from WC items and AFI creates one Xero LineItem per cart item, pulling the product name, quantity, line total, and SKU from the order. A Default Account Code (e.g. 200 for Sales) is required because every Xero line item needs one. Optionally set a Default Tax Type (e.g. OUTPUT) applied to every auto-built line.

Shipping line

Enable Add shipping line and AFI appends a “Shipping” line item using the order’s shipping_total when it is non-zero. It uses the same Default Account Code.

Feature comparison

Feature Free Pro
Create / update contact
Create invoice
Contact upsert by email / number
Send invoice email after create
WooCommerce contact auto-fill No
Build invoice lines from WC cart No
Add shipping line from WC No

Conditional logic example

Only create a Xero invoice when the form’s order_total field is greater than 0, so test submissions or zero-amount quotes do not create empty invoices. Add a condition: Order Total greater than 0.

Troubleshooting

Connection lost after an hour

The OAuth2 app is missing the offline_access scope, so AFI has no refresh token and the access token expires. Edit the app in the Xero Developer Portal, add offline_access, then re-authorize in AFI.

Organisation dropdown is empty

The token was issued but no Xero organisation is connected to it. Make sure you selected at least one organisation during the Xero consent screen. You can re-authorize from AFI → Settings → Xero to re-grant access to the right orgs.

Invoice created as DRAFT, not emailed

Xero only emails invoices with status AUTHORISED. If Status is left blank or set to DRAFT, the invoice is created but the email step is skipped. Set Status to AUTHORISED and Send Email to true if you want Xero to email the customer.

Line items error

The Line Items field expects valid JSON. A missing bracket or unescaped quote causes Xero to reject the invoice. Validate your JSON at a linter, and make sure each line has AccountCode set to a code that exists in your Xero chart of accounts.

Related docs