Xero
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.
- Sign in to the Xero Developer Portal and create a new app of type Web app.
- Copy the Redirect URI shown in the AFI Xero settings tab and paste it into the app’s allowed redirect URIs.
- Note the Client ID and Client Secret.
- The app needs these scopes at minimum:
accounting.contacts,accounting.transactions, andoffline_access. AFI also requestsopenid profile emailautomatically.
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
- In WordPress, go to AFI → Settings and open the Xero tab.
- Click Add New Account, fill in Client ID and Client Secret, and give the account a name.
- Click Save & Authorize. You’ll be redirected to Xero to grant consent.
- 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
- Go to AFI → Add New.
- Give the integration a name, for example
Quote form to Xero. - Under Trigger, pick the form plugin and the specific form you want to listen on.
- Under Action → Platform, select Xero.
- In Task, choose Create / Update Contact or Create Invoice.
- Pick the saved account in the Xero Account dropdown.
- Pick the Organisation (tenant) to write to.
- Map your form fields onto the Xero fields listed below.
- Optional: open Conditional Logic to limit which submissions are sent.
- 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.