Build Xero where filters safely. Xero's filter is an expression over the record's fields, e.g.

Type=="ACCREC" AND Status=="AUTHORISED" AND Date>=DateTime(2026,01,01)
Contact.ContactID==guid("6d2b51ce-...")

condition checks the field name and operator and writes the value as the right literal: Strs in double quotes, GUIDs with guid(...), dates with DateTime(y,m,d), numbers and Bools bare. Xero documents no escape for a " inside a string, so a Str value containing " or \ is an Err rather than a guess: use the dedicated parameters instead (searchTerm, IDs, ContactIDs, InvoiceNumbers, Statuses), which Xero also recommends because they are indexed and faster on large organisations.

::w ::xero::where

::w/all-of([
  ["Type", "==", "ACCREC"],
  ["Status", "==", "AUTHORISED"],
  ["Date", ">=", ::w/date(2026, 1, 1)],
  ["Contact.ContactID", "==", ::w/guid("6d2b51ce-0a4f-4a8b-9f7a-3c1e2d4b5a69")]
])

Values travel URL-encoded in the where query parameter.

Values

OPERATORS

OPERATORS: Vec [
  "==",
  "!=",
  "<",
  ">",
  "<=",
  ">="
]

Functions

all-of

fn (conditions: Vec): Str

Join conditions with AND (each parenthesised). Each part is a [field, operator, value] Vec or an expression Str; any invalid part makes the result an Err.

::xero::where/all-of([["Type", "==", "ACCREC"], ["AmountDue", ">", 0]])
// (Type=="ACCREC") AND (AmountDue>0)

any-of

fn (conditions: Vec): Str

Join conditions with OR (each parenthesised); parts as for all-of.

clause

fn (part: Any): Str

One part for all-of / any-of: a [field, op, value] Vec becomes condition(field, op, value); a Str (an expression you built) passes through. Anything else is an Err.

combine

fn (parts: Vec, joiner: Str): Str

condition

fn (name: Str, op: Str, value: Any): Str

One comparison: field, an operator (==, !=, <, >, <=, >=) and a value. Returns the expression Str, or an Err for a bad field, operator or value.

::xero::where/condition("AmountDue", ">", 0)   // "AmountDue>0"

date

fn (year: Int, month: Int, day: Int): Map

A DateTime(y,mm,dd) literal (month and day zero-padded), or an Err for an impossible date.

field

fn (name: Str): Str

Check a field path (Status, Contact.ContactID): letters, digits, _ and dots. Returns it, or an Err.

guid

fn (value: Str): Map

A guid("...") literal for an id field (ContactID, InvoiceID, ...), or an Err when the value is not a GUID.

literal

fn (value: Any): Str

The filter literal for a value: a {literal} Map from guid / date / raw as is, Strs quoted (see quote), Ints and Decs bare, Bools true/false. Null is an Err.

pad2

fn (n: Int): Str

quote

fn (value: Str): Str

A double-quoted string literal, or an Err when the value contains " or \ (Xero documents no escape for them).

raw

fn (text: Str): Map

Wrap an expression you have built and checked yourself so condition writes it unchanged.