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
| Operator | Example |
|---|---|
= (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.
| Operator | string | number | boolean | date | time | id | string[] | array |
|---|---|---|---|---|---|---|---|---|
= | Y | Y | Y | Y | Y | Y | Y | Y |
!= | Y | Y | Y | Y | Y | Y | Y | β |
< > <= >= | β | Y | β | Y | Y | β | β | β |
in | Y | Y | β | β | β | Y | Y | β |
between | β | Y | β | Y | Y | β | β | β |
like | Y | β | β | β | β | β | β | β |
is / is not (null) | Y | Y | Y | Y | Y | Y | β | 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:datefield that covers the whole day; on a:timefield 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.