OQL

Operators

OQL operator reference. Comparison, ranges, membership, pattern matching, and null checks.

Last updated Jul 16, 2026

OQL operators live inside where clauses. A bare value means equality; operators are only required for everything else.

"where": {
  "status": "won",                          // implicit =
  "amount": { ">": 1000 },                  // explicit operator
  "owner_id": { "in": ["abc...", "def..."] }
}

Reference

OperatorExample
= (implicit){ "status": "active" }
= (explicit){ "status": { "=": "active" } }
!={ "status": { "!=": "lost" } }
<, >, <=, >={ "amount": { ">": 1000 } }
in{ "status": { "in": ["won", "lost"] } }
between{ "amount": { "between": [100, 500] } }
like{ "first_name": { "like": "Al%" } }
is (null check){ "owner_id": { "is": null } }
is not (null check){ "owner_id": { "is not": null } }

Type compatibility

Not every operator works on every type. OQL enforces these rules and rejects incompatible combinations with a clear error.

Operatorstringnumberbooleandatetimeidstring[]array
=YYYYYYYY
!=YYYYYYYβ€”
< > <= >=β€”Yβ€”YYβ€”β€”β€”
inYYβ€”β€”β€”YYβ€”
betweenβ€”Yβ€”YYβ€”β€”β€”
likeYβ€”β€”β€”β€”β€”β€”β€”
is / is not (null)YYYYYYβ€”Y

array covers embedded arrays such as emails, phones, and urls on contacts. Each exposes string subfields you can filter against; see below.

Notes per operator

Equality

Bare values imply =. The two forms below are equivalent.

// bare value
{ "status": "won" }

// explicit operator
{ "status": { "=": "won" } }

!= keeps null and missing

!= excludes records where the field equals the given value, but it keeps records where the field is null or missing β€” an absent value counts as β€œnot equal” to anything. So != is not the same as β€œhas some other value.” When you also need the field present, add a null check:

{ "company_id": { "!=": "507f..." } }   // not that company β€” also matches contacts with no company
{ "company_id": { "is not": null } }    // linked to some company
{ "company_id": { "is": null } }        // no linked company

between

Lower bound inclusive. The upper bound depends on what you pass:

  • A literal upper bound is taken exactly and inclusively (<= the value given). On a :date field that covers the whole day; on a :time field it’s that precise instant β€” pass an explicit end instant if you want a full day.
  • A date-function upper bound (e.g. TODAY()) uses that period’s half-open range, so it stops just before the first instant after the period. See Functions.

Keeping literal bounds exact stops sub-day ranges from over-returning, while calendar ranges stay natural.

{ "amount": { "between": [100, 500] } }                          // 100–500 inclusive
{ "close_date": { "between": ["2026-01-01", "2026-03-31"] } }    // Q1, both days included
{ "call_time": { "between": [{ "DAYS_AGO": [30] }, "TODAY()"] } } // last 30 days, through end of today

like

String-only pattern match. Use % for any-length wildcard and _ for a single character. Anchored on both ends. Case insensitive.

{ "first_name": { "like": "Al%" } }      // starts with "Al"
{ "company":    { "like": "%Ltd" } }     // ends with "Ltd"
{ "phones.number": { "like": "+353%" } } // Irish phone numbers

Constraints:

  • Maximum 3 wildcards (% or _) per pattern.
  • Maximum 100 characters per pattern.
  • Empty patterns are rejected; use = "" or {"is": null} instead.

in

Membership against a list. The list must be non-empty.

{ "status":  { "in": ["won", "pending"] } }
{ "tags":    { "in": ["VIP", "Hot"] } }   // matches if any tag overlaps

is null / is not null

Explicit null checks, separate from !=. For embedded array fields (emails, phones, urls), is null matches records with an empty or missing array; is not null matches records with at least one element.

{ "owner_id": { "is": null } }
{ "emails":   { "is not": null } }

Filtering on embedded arrays

emails, phones, and urls on contacts are arrays of objects. Filter using dotted subfield syntax. The match is satisfied if any element matches.

{ "emails.address": "alice@example.com" }
{ "phones.number":  { "like": "+353%" } }
{ "urls.type":      "linkedin" }

Each entity page lists the subfields available on its array fields. Filtering by the bare field name (without subfield) only works with is null / is not null.