Skip to main content

Filter

Filter inputs select which Records are returned from an App. The same filter object is used in two places:

Anything documented here applies to both, unchanged. Multiple filters can be provided; they are combined with the boolean AND operator (there is no OR) — a Record is returned only if it matches every filter.

Each field filter is a JSON object with:

KeyDescription
field_idThe id of the field to filter on. Required.
field_typeThe field's type, e.g. single_text, status, single_date (see the sections below). Required for view filters; optional for record filtering, where the field is identified by field_id (sending it is still recommended).
typeThe legacy data-type discriminator that goes with the field type, e.g. text, status, date. Required — a filter without it returns a 400.
match_typeThe operator, e.g. contains, equal, before. The operators each field type accepts are listed per section below.
valuesThe operand(s), as an array of { "value": … } objects. Omitted for the empty / not_empty operators.

Some field types accept additional optional operand keys (for relative dates, weekdays, the "@me" flag, checklist sub-properties, …). These are documented under Operand keys.

The following example matches all records whose field 1 contains the text "John" and whose field 2 (a status field) references option 123:

➡️ Combined Filter
{
"filters": [
{
"field_id": "1",
"field_type": "single_text",
"match_type": "contains",
"values": [{ "value": "John" }],
"type": "text"
},
{
"field_id": "2",
"field_type": "status",
"match_type": "equal",
"values": [{ "value": 123 }],
"type": "status"
}
]
}

Tape also supports a few field-less metadata filters — by creation date, modification date, or record id — that need no field on the App.

Single Text

This is an example on how to filter records by a single_text field:

➡️ Single Text Filter
{
"filters": [
{
"field_id": "1",
"field_type": "single_text",
"match_type": "contains",
"values": [{ "value": "John" }],
"type": "text"
}
]
}

contains, not_contains, starts_with and ends_with compare case-insensitively; equal and not_equal are case-sensitive exact matches. Leading and trailing whitespace in the match value is trimmed for every operator. The empty and not_empty match types take no values.

The following match_type values are supported for single_text fields:

Match typeDescription
equalMatches all records whose field value is equal to the match value.
not_equalMatches all records whose field value is not equal to the match value.
containsMatches all records whose field value contains the match value.
not_containsMatches all records whose field value does not contain the match value.
starts_withMatches all records whose field value starts with the match value.
ends_withMatches all records whose field value ends with the match value.
emptyMatches all records whose field value is empty.
not_emptyMatches all records whose field value is not empty.

Multi Text

This is an example on how to filter records by a multi_text field:

➡️ Multi Text Filter
{
"filters": [
{
"field_id": "1",
"field_type": "multi_text",
"match_type": "contains",
"values": [{ "value": "John" }],
"type": "text"
}
]
}

multi_text filters match against the field's unformatted (plain-text) value. contains, not_contains, starts_with and ends_with compare case-insensitively; equal and not_equal are case-sensitive exact matches. Leading and trailing whitespace is trimmed for every operator. The empty and not_empty match types take no values.

The following match_type values are supported for multi_text fields:

Match typeDescription
equalMatches all records whose unformatted field value is equal to the match value.
not_equalMatches all records whose unformatted field value is not equal to the match value.
containsMatches all records whose unformatted field value contains the match value.
not_containsMatches all records whose unformatted field value does not contain the match value.
starts_withMatches all records whose unformatted field value starts with the match value.
ends_withMatches all records whose unformatted field value ends with the match value.
emptyMatches all records whose field value is empty.
not_emptyMatches all records whose field value is not empty.

Number

This is an example on how to filter records by a number field:

➡️ Number Filter
{
"filters": [
{
"field_id": "1",
"field_type": "number",
"match_type": "smaller",
"values": [{ "value": 12.34 }],
"type": "number"
}
]
}

Provide the number to compare against as a bare numeric scalar in values[0].value. Omit values entirely for empty / not_empty.

The following match_type values are supported for number fields:

Match typeDescription
equalMatches all records whose field value is equal to the provided match value
not_equalMatches all records whose field value is not equal to the provided match value
smallerMatches all records whose field value is smaller than the provided match value
smaller_or_equalMatches all records whose field value is smaller than or equal to the match value
largerMatches all records whose field value is larger than the provided match value
larger_or_equalMatches all records whose field value is larger than or equal to the match value
emptyMatches all records whose field value is empty
not_emptyMatches all records whose field value is not empty

Unique ID

This is an example on how to filter records by a unique_id field:

➡️ Unique ID Filter
{
"filters": [
{
"field_id": "1",
"field_type": "unique_id",
"match_type": "larger_or_equal",
"values": [{ "value": 1000 }],
"type": "number"
}
]
}

A Unique ID field surfaces a record's auto-generated, App-specific record number (its app_record_id — the first record created in an App is 1, the second 2, and so on). The match value is a bare numeric scalar with no prefix, and unique_id filters compare on the underlying number, so this field uses the numeric type discriminator "number" (not "unique_id"). Omit values for empty / not_empty — though, because every record always has an App-specific number, empty matches no records and not_empty matches every record.

note

To filter by the record number on an App that has no Unique ID field, use the field-less app_record_id metadata filter instead — it targets the same underlying value without requiring a field.

The following match_type values are supported for unique_id fields (identical to the number set):

Match typeDescription
equalMatches the record whose ID is equal to the provided match value
not_equalMatches all records whose ID is not equal to the provided match value
smallerMatches all records whose ID is smaller than the provided match value
smaller_or_equalMatches all records whose ID is smaller than or equal to the provided match value
largerMatches all records whose ID is larger than the provided match value
larger_or_equalMatches all records whose ID is larger than or equal to the provided match value
emptyMatches all records whose field value is empty
not_emptyMatches all records whose field value is not empty

Single Category

This is an example on how to filter records by a single_category field:

➡️ Single Category Filter
{
"filters": [
{
"field_id": "1",
"field_type": "single_category",
"match_type": "any",
"values": [{ "value": 1 }, { "value": "Not Started" }],
"type": "category"
}
]
}

Provide either the numeric id of a category option or its label as the match value. Label matching is case-insensitive and ignores leading and trailing whitespace; if a label matches more than one option the request is rejected — use the id in that case. On read, operands are always returned as option ids. The empty and not_empty match types take no values.

The following match_type values are supported for single_category fields:

Match typeDescription
equalMatches all records whose field value references the option specified.
not_equalMatches all records whose field value does not reference the option specified.
anyMatches all records whose field value references any of the options specified.
noneMatches all records whose field value references none of the options specified.
emptyMatches all records whose field value is empty.
not_emptyMatches all records whose field value is not empty.

Multi Category

This is an example on how to filter records by a multi_category field:

➡️ Multi Category Filter
{
"filters": [
{
"field_id": "1",
"field_type": "multi_category",
"match_type": "contains",
"values": [{ "value": 1 }, { "value": "Not Started" }],
"type": "category"
}
]
}

A multi_category field holds a set of options, so the match types compare sets: equal requires the field's set to be exactly the given options (order ignored), contains requires the field to include all of the given options (it may hold more), while any and none test for overlap with the given options. Provide either the numeric id of an option or its label; label matching is case-insensitive and ignores leading and trailing whitespace (an ambiguous label is rejected — use the id). On read, operands are always returned as option ids. The empty and not_empty match types take no values.

The following match_type values are supported for multi_category fields:

Match typeDescription
equalMatches all records whose field value references exactly the options specified and no others.
containsMatches all records whose field value references all of the options specified (and may reference more).
anyMatches all records whose field value references at least one of the options specified.
noneMatches all records whose field value references none of the options specified.
emptyMatches all records whose field value is empty.
not_emptyMatches all records whose field value is not empty.

Status

This is an example on how to filter records by a status field:

➡️ Status Filter
{
"filters": [
{
"field_id": "1",
"field_type": "status",
"match_type": "any",
"values": [{ "value": 1 }, { "value": "Not Started" }],
"type": "status"
}
]
}

Provide either the numeric id of a status option or its label as the match value. Label matching is case-insensitive and ignores leading and trailing whitespace (an ambiguous label is rejected — use the id). On read, operands are always returned as option ids. The completed, incomplete, empty and not_empty match types take no valuescompleted/incomplete test the completion state of the record's currently referenced status option.

The following match_type values are supported for status fields:

Match typeDescription
equalMatches all records whose field value references the status option specified.
not_equalMatches all records whose field value does not reference the status option specified.
anyMatches all records whose field value references any of the status options specified.
noneMatches all records whose field value references none of the status options specified.
emptyMatches all records whose field value is empty.
not_emptyMatches all records whose field value is not empty.
completedMatches all records whose referenced status option is marked as completed.
incompleteMatches all records whose referenced status option is not marked as completed.

Single Relation

This is an example on how to filter records by a single_relation field:

➡️ Single Relation Filter
{
"filters": [
{
"field_id": "1",
"field_type": "single_relation",
"match_type": "any",
"values": [{ "value": 1 }],
"type": "app"
}
]
}

Provide the related record ids as match values. On read, operands are always returned as record ids. The empty and not_empty match types take no values.

The following match_type values are supported for single_relation fields:

Match typeDescription
equalMatches all records whose field value references the record specified.
not_equalMatches all records whose field value does not reference the record specified.
anyMatches all records whose field value references any of the records specified.
noneMatches all records whose field value references none of the records specified.
emptyMatches all records whose field value is empty.
not_emptyMatches all records whose field value is not empty.

Multi Relation

This is an example on how to filter records by a multi_relation field:

➡️ Multi Relation Filter
{
"filters": [
{
"field_id": "1",
"field_type": "multi_relation",
"match_type": "contains",
"values": [{ "value": 1 }, { "value": 2 }],
"type": "app"
}
]
}

A multi_relation field holds a set of related records, so the match types compare sets: equal requires the field's set to be exactly the given records (order ignored), contains requires the field to include all of the given records (it may hold more), while any and none test for overlap. Provide the related record ids as match values. On read, operands are always returned as record ids. The empty and not_empty match types take no values.

The following match_type values are supported for multi_relation fields:

Match typeDescription
equalMatches all records whose field value references exactly the records specified and no others.
containsMatches all records whose field value references all of the records specified (and may reference more).
anyMatches all records whose field value references at least one of the records specified.
noneMatches all records whose field value references none of the records specified.
emptyMatches all records whose field value is empty.
not_emptyMatches all records whose field value is not empty.

Single User

This is an example on how to filter records by a single_user field:

➡️ Single User Filter
{
"filters": [
{
"field_id": "1",
"field_type": "single_user",
"match_type": "any",
"values": [{ "value": 1 }],
"type": "contact"
}
]
}

Provide the user ids to filter by. The acting user can be added to the filter's referenced users with the include_active_user operand (the "@me" reference) — see Operand keys. On read, operands are always returned as user ids. The empty and not_empty match types take no values (and cannot be combined with include_active_user).

The following match_type values are supported for single_user fields:

Match typeDescription
equalMatches all records whose field value references the user specified.
not_equalMatches all records whose field value does not reference the user specified.
anyMatches all records whose field value references any of the users specified.
noneMatches all records whose field value references none of the users specified.
emptyMatches all records whose field value is empty.
not_emptyMatches all records whose field value is not empty.

Multi User

This is an example on how to filter records by a multi_user field:

➡️ Multi User Filter
{
"filters": [
{
"field_id": "1",
"field_type": "multi_user",
"match_type": "contains",
"values": [{ "value": 1 }, { "value": 2 }],
"type": "contact"
}
]
}

A multi_user field holds a set of users, so the match types compare sets: equal requires the field's set to be exactly the given users (order ignored), contains requires the field to include all of the given users (it may hold more), while any and none test for overlap. Provide the user ids to filter by. The acting user can be added with the include_active_user operand (the "@me" reference) — see Operand keys. On read, operands are always returned as user ids. The empty and not_empty match types take no values (and cannot be combined with include_active_user).

The following match_type values are supported for multi_user fields:

Match typeDescription
equalMatches all records whose field value references exactly the users specified and no others.
containsMatches all records whose field value references all of the users specified (and may reference more).
anyMatches all records whose field value references at least one of the users specified.
noneMatches all records whose field value references none of the users specified.
emptyMatches all records whose field value is empty.
not_emptyMatches all records whose field value is not empty.

Created By

This is an example on how to filter records by a created_by field:

➡️ Created By Filter
{
"filters": [
{
"field_id": "1",
"field_type": "created_by",
"match_type": "any",
"values": [{ "value": 1 }],
"type": "contact"
}
]
}

A created_by field references the user who created the record. Provide the user ids to filter by. The acting user can be added with the include_active_user operand (the "@me" reference) — see Operand keys — so any with include_active_user selects the records you created. On read, operands are always returned as user ids. Note the type discriminator is contact (the same as a user field), not created_by. The empty and not_empty match types take no values (and cannot be combined with include_active_user).

The following match_type values are supported for created_by fields:

Match typeDescription
equalMatches all records created by the user specified.
not_equalMatches all records not created by the user specified.
anyMatches all records created by any of the users specified.
noneMatches all records created by none of the users specified.
emptyMatches all records whose field value is empty.
not_emptyMatches all records whose field value is not empty.

Last Modified By

This is an example on how to filter records by a last_modified_by field:

➡️ Last Modified By Filter
{
"filters": [
{
"field_id": "1",
"field_type": "last_modified_by",
"match_type": "any",
"values": [{ "value": 1 }],
"type": "contact"
}
]
}

A last_modified_by field references the user who last modified the record. Provide the user ids to filter by. The acting user can be added with the include_active_user operand (the "@me" reference) — see Operand keys — so any with include_active_user selects the records you last modified. On read, operands are always returned as user ids. Note the type discriminator is contact (the same as a user field), not last_modified_by. The empty and not_empty match types take no values (and cannot be combined with include_active_user).

The following match_type values are supported for last_modified_by fields:

Match typeDescription
equalMatches all records last modified by the user specified.
not_equalMatches all records not last modified by the user specified.
anyMatches all records last modified by any of the users specified.
noneMatches all records last modified by none of the users specified.
emptyMatches all records whose field value is empty.
not_emptyMatches all records whose field value is not empty.

Single Date

This is an example on how to filter records by a single_date field:

➡️ Single Date Filter
{
"filters": [
{
"field_id": "1",
"field_type": "single_date",
"match_type": "before",
"relative_date_type": "exact_date",
"values": [{ "value": { "date": "2020-01-01T00:00:00.000Z" } }],
"type": "date"
}
]
}

The date operand is nested: the target date is values[0].value.date (an ISO-8601 string), with an optional integer values[0].value.offset_amount used by the relative num_* types. A bare scalar (values[0].value: "2020-01-01") is also accepted on input, but the nested object is the canonical form a GET emits and re-accepts. Omit values for empty / not_empty.

The date actually matched against is computed from values[0].value.date, the relative_date_type, and — for the num_days_* / num_weeks_* / num_months_* types — values[0].value.offset_amount. For example, relative_date_type: "num_days_before" with an offset of 1 and a date of 2020-01-01 resolves to 2019-12-31. The zero-argument relative types (today, tomorrow, yesterday) need no value at all. See Operand keys for the full list of relative_date_type values.

Four operators select a period rather than a single day and read a dedicated operand key (values enumerated under Operand keys):

  • within — pairs with relative_date_range_type to match a named or bounded range (e.g. current_week, past_num_days, exact_range). For exact_range, supply the window start via values[0].value.date and the window end via the top-level end_date; for next_num_days / past_num_days, supply the count via offset_amount.
  • on_weekday — pairs with weekday (mondaysunday).
  • in_quarter_of_year — pairs with quarter_of_year (q1q4).
  • in_month_of_year — pairs with month_of_year (januarydecember).
Date field filters are day-granular

The supplied date is expanded to a full day — [start of day, end of day] in the caller's timezone — and the time of day in the value is ignored. As a result the boundary operators are not all inclusive: before matches strictly before the start of the target day and after strictly after its end (both exclude the day itself), while on_or_before includes the whole day through its end and on_or_after includes it from its start. equal matches the whole target day; not_equal matches everything outside it.

The following match_type values are supported for single_date fields:

Match typeDescription
equalMatches all records whose field date falls on the target day
not_equalMatches all records whose field date does not fall on the target day
beforeMatches all records whose field date is before the start of the target day (day excluded)
on_or_beforeMatches all records whose field date is on or before the target day (whole day included)
afterMatches all records whose field date is after the end of the target day (day excluded)
on_or_afterMatches all records whose field date is on or after the target day (whole day included)
withinMatches all records whose field date falls within the range selected by relative_date_range_type
on_weekdayMatches all records whose field date falls on the supplied weekday
in_quarter_of_yearMatches all records whose field date falls in the supplied quarter_of_year
in_month_of_yearMatches all records whose field date falls in the supplied month_of_year
emptyMatches all records whose field value is empty
not_emptyMatches all records whose field value is not empty

Range Date

This is an example on how to filter records by a range_date field:

➡️ Range Date Filter
{
"filters": [
{
"field_id": "1",
"field_type": "range_date",
"match_type": "within",
"relative_date_range_type": "exact_range",
"values": [{ "value": { "date": "2020-01-01T00:00:00.000Z" } }],
"end_date": "2020-12-31T00:00:00.000Z",
"type": "date"
}
]
}

A Range Date field stores a start date and an end date, so its operators test that interval for overlap with the target day or window rather than testing point equality. It otherwise accepts exactly the same operand shape, operators and operand keys as Single Date above — the nested values[0].value.date (+ optional offset_amount), relative_date_type, relative_date_range_type, weekday, quarter_of_year and month_of_year (see Operand keys). The distinctive combination is within + relative_date_range_type: "exact_range", which tests the stored range against an explicit window whose bounds are values[0].value.date (start) and the top-level end_date (end). Omit values for empty / not_empty.

Range operators use interval-overlap semantics

Each supplied date is expanded to a full day ([start of day, end of day] in the caller's timezone; the time of day is ignored). A range operator then tests the stored [start, end] interval against the target day or window: equal and within match any range that overlaps it (not only ranges that equal it or sit inside it), while before / after / on_or_before / on_or_after compare the range's endpoints to the day boundary.

The following match_type values are supported for range_date fields:

Match typeDescription
equalMatches all records whose range overlaps the target day
not_equalMatches all records whose range does not overlap the target day
beforeMatches all records whose range starts before the start of the target day
on_or_beforeMatches all records whose range falls on or before the target day
afterMatches all records whose range falls after the end of the target day
on_or_afterMatches all records whose range falls on or after the target day
withinMatches all records whose range overlaps the range selected by relative_date_range_type
on_weekdayMatches all records whose range falls on the supplied weekday
in_quarter_of_yearMatches all records whose range falls in the supplied quarter_of_year
in_month_of_yearMatches all records whose range falls in the supplied month_of_year
emptyMatches all records whose field value is empty
not_emptyMatches all records whose field value is not empty

Created At

Filtering without a Created-At field

This filter targets an App that has a dedicated Created-At field (it references a field_id). To filter by a record's creation time on any App — including those without such a field — use the field-less created_at metadata filter instead.

This is an example on how to filter records by a created_on field:

➡️ Created At Filter
{
"filters": [
{
"field_id": "1",
"field_type": "created_on",
"match_type": "on_or_after",
"relative_date_type": "exact_date",
"values": [{ "value": { "date": "2020-01-01T00:00:00.000Z" } }],
"type": "date"
}
]
}

This filters the record's creation date. Note the field_type is created_on (and the type discriminator is date). It uses the identical operand shape and operators as Single Date: the nested values[0].value.date (+ optional offset_amount), relative_date_type, and the within / on_weekday / in_quarter_of_year / in_month_of_year operators with their relative_date_range_type / weekday / quarter_of_year / month_of_year operands (see Operand keys). Omit values for empty / not_empty.

Day-granular, and distinct from the metadata filter

The supplied date is expanded to a full day in the caller's timezone (time of day ignored), so before / after are strict at the day boundary (excluding the target day) while on_or_before / on_or_after include the whole day. This differs from the field-less created_at metadata filter, which is instant-based (it compares exact timestamps) and treats all four bounds as inclusive.

The following match_type values are supported for created_on fields:

Match typeDescription
equalMatches all records whose creation date falls on the target day
not_equalMatches all records whose creation date does not fall on the target day
beforeMatches all records created before the start of the target day (day excluded)
on_or_beforeMatches all records created on or before the target day (whole day included)
afterMatches all records created after the end of the target day (day excluded)
on_or_afterMatches all records created on or after the target day (whole day included)
withinMatches all records whose creation date falls within the range selected by relative_date_range_type
on_weekdayMatches all records whose creation date falls on the supplied weekday
in_quarter_of_yearMatches all records whose creation date falls in the supplied quarter_of_year
in_month_of_yearMatches all records whose creation date falls in the supplied month_of_year
emptyMatches all records with no creation date
not_emptyMatches all records that have a creation date

Last Modified At

Filtering without a Last-Modified field

This filter targets an App that has a dedicated Last-Modified field (it references a field_id). To filter by a record's last-modified time on any App — including those without such a field — use the field-less last_modified_at metadata filter instead.

This is an example on how to filter records by a last_modified_on field:

➡️ Last Modified At Filter
{
"filters": [
{
"field_id": "1",
"field_type": "last_modified_on",
"match_type": "on_or_after",
"relative_date_type": "num_weeks_before",
"values": [{ "value": { "offset_amount": 1 } }],
"type": "date"
}
]
}

This filters the record's last-modified date. Note the field_type is last_modified_on (and the type discriminator is date). The example above uses a relative date: num_weeks_before with offset_amount: 1 resolves to "one week ago". It uses the identical operand shape and operators as Single Date — nested values[0].value.date (+ optional offset_amount), relative_date_type, and the within / on_weekday / in_quarter_of_year / in_month_of_year operands (see Operand keys). Omit values for empty / not_empty.

Day-granular, and distinct from the metadata filter

The supplied date is expanded to a full day in the caller's timezone (time of day ignored), so before / after are strict at the day boundary (excluding the target day) while on_or_before / on_or_after include the whole day. This differs from the field-less last_modified_at metadata filter, which is instant-based (it compares exact timestamps) and treats all four bounds as inclusive.

The following match_type values are supported for last_modified_on fields:

Match typeDescription
equalMatches all records whose last-modified date falls on the target day
not_equalMatches all records whose last-modified date does not fall on the target day
beforeMatches all records last modified before the start of the target day (day excluded)
on_or_beforeMatches all records last modified on or before the target day (whole day included)
afterMatches all records last modified after the end of the target day (day excluded)
on_or_afterMatches all records last modified on or after the target day (whole day included)
withinMatches all records whose last-modified date falls within the range selected by relative_date_range_type
on_weekdayMatches all records whose last-modified date falls on the supplied weekday
in_quarter_of_yearMatches all records whose last-modified date falls in the supplied quarter_of_year
in_month_of_yearMatches all records whose last-modified date falls in the supplied month_of_year
emptyMatches all records with no last-modified date
not_emptyMatches all records that have a last-modified date

Calculation

This is an example on how to filter records by a calculation field:

➡️ Calculation Filter
{
"filters": [
{
"field_id": "1",
"field_type": "calculation",
"match_type": "smaller",
"values": [{ "value": 12.34 }],
"type": "calculation"
}
]
}

A calculation field is polymorphic: depending on its script, it yields a text, a number, or a date result. Which match types are meaningful therefore depends on the calculation's result type, and you supply the same operand shape as the corresponding scalar field type:

  • Number result — use the numeric comparison operators with a bare numeric values[0].value, exactly as for a Number field.
  • Text result — use the text operators with a string values[0].value, exactly as for a Single Text field.
  • Date result — use the date operators with the nested values[0].value.date (+ optional offset_amount) and the temporal operand keys, exactly as for a Single Date field (see Operand keys).

empty / not_empty apply to every result type (omit values). The calendar operators (within, on_weekday, in_quarter_of_year, in_month_of_year) and the zero-argument relative dates (today, tomorrow, yesterday) are only valid when the calculation returns a date — using them against a text- or number-typed calculation returns a 400.

The following match_type values are supported for calculation fields (the union across all result types):

Match typeApplies toDescription
emptyanyMatches all records whose field value is empty
not_emptyanyMatches all records whose field value is not empty
equalnumber, text, dateMatches all records whose field value is equal to the provided match value (day-granular for a date result)
not_equalnumber, text, dateMatches all records whose field value is not equal to the provided match value
smallernumberMatches all records whose field value is smaller than the provided match value
smaller_or_equalnumberMatches all records whose field value is smaller than or equal to the match value
largernumberMatches all records whose field value is larger than the provided match value
larger_or_equalnumberMatches all records whose field value is larger than or equal to the match value
containstextMatches all records whose field value contains the provided match value
not_containstextMatches all records whose field value does not contain the provided match value
starts_withtextMatches all records whose field value starts with the provided match value
ends_withtextMatches all records whose field value ends with the provided match value
beforedateMatches all records whose field date is before the start of the target day (day excluded)
on_or_beforedateMatches all records whose field date is on or before the target day (whole day included)
afterdateMatches all records whose field date is after the end of the target day (day excluded)
on_or_afterdateMatches all records whose field date is on or after the target day (whole day included)
withindateMatches all records whose field date falls within the range selected by relative_date_range_type
on_weekdaydateMatches all records whose field date falls on the supplied weekday
in_quarter_of_yeardateMatches all records whose field date falls in the supplied quarter_of_year
in_month_of_yeardateMatches all records whose field date falls in the supplied month_of_year

Multi Email

This is an example on how to filter records by a multi_email field:

➡️ Multi Email Filter
{
"filters": [
{
"field_id": "1",
"field_type": "multi_email",
"match_type": "fully_includes",
"values": [{ "value": "[email protected]" }],
"type": "email"
}
]
}

An email field can hold several addresses. Most match types quantify over those entries — a record matches when at least one email entry satisfies the criterion (not_contains matches when no entry contains the value; empty when there are no entries). Comparison is case insensitive and leading/trailing whitespace in the match value is ignored.

The following match_type values are supported for multi_email fields:

Match typeDescription
fully_includesMatches records that have at least one email entry equal to the match value in full.
containsMatches records that have at least one email entry containing the match value.
not_containsMatches records where none of the email entries contain the match value.
starts_withMatches records that have at least one email entry starting with the match value.
ends_withMatches records that have at least one email entry ending with the match value.
emptyMatches records whose field value is empty (no email entries). Omit values.
not_emptyMatches records whose field value is not empty (at least one email entry). Omit values.

Multi Phone

This is an example on how to filter records by a multi_phone field:

➡️ Multi Phone Filter
{
"filters": [
{
"field_id": "1",
"field_type": "multi_phone",
"match_type": "starts_with",
"values": [{ "value": "+49" }],
"type": "phone"
}
]
}

A phone field can hold several numbers. Most match types quantify over those entries — a record matches when at least one phone entry satisfies the criterion (not_contains matches when no entry contains the value; empty when there are no entries). Comparison is case insensitive and leading/trailing whitespace in the match value is ignored.

The following match_type values are supported for multi_phone fields:

Match typeDescription
fully_includesMatches records that have at least one phone entry equal to the match value in full.
containsMatches records that have at least one phone entry containing the match value.
not_containsMatches records where none of the phone entries contain the match value.
starts_withMatches records that have at least one phone entry starting with the match value.
ends_withMatches records that have at least one phone entry ending with the match value.
emptyMatches records whose field value is empty (no phone entries). Omit values.
not_emptyMatches records whose field value is not empty (at least one phone entry). Omit values.

This is an example on how to filter records by a multi_link field:

➡️ Multi Link Filter
{
"filters": [
{
"field_id": "1",
"field_type": "multi_link",
"match_type": "contains",
"values": [{ "value": "github.com" }],
"type": "embed"
}
]
}

Note that the data type for a link field is embed, not link. A link field can hold several links; matching is performed over each entry's URL (case insensitive, surrounding whitespace ignored), and a record matches when at least one URL satisfies the criterion.

Link fields have no exact-match armequal and fully_includes are not supported and return a 400. Use contains (or starts_with / ends_with) instead.

The following match_type values are supported for multi_link fields:

Match typeDescription
containsMatches records that have at least one link whose URL contains the match value.
not_containsMatches records where none of the link URLs contain the match value.
starts_withMatches records that have at least one link whose URL starts with the match value.
ends_withMatches records that have at least one link whose URL ends with the match value.
emptyMatches records whose field value is empty (no links). Omit values.
not_emptyMatches records whose field value is not empty (at least one link). Omit values.

Single Location

This is an example on how to filter records by a single_location field:

➡️ Single Location Filter
{
"filters": [
{
"field_id": "1",
"field_type": "single_location",
"match_type": "contains",
"values": [{ "value": "Berlin" }],
"type": "location"
}
]
}

A location filter matches free text over the formatted address — the street address, postal code, city, state, country and original formatted address concatenated together. There is no component-level filtering (you cannot filter on city or country in isolation). Comparison is case insensitive and leading/trailing whitespace in the match value is ignored.

The following match_type values are supported for single_location fields:

Match typeDescription
containsMatches records whose formatted address contains the match value.
not_containsMatches records whose formatted address does not contain the match value (records with no address set also match).
emptyMatches records whose field value is empty (no address set). A coordinate-only value counts as not empty. Omit values.
not_emptyMatches records whose field value is not empty (an address or coordinates are set). Omit values.

Single Attachment

This is an example on how to filter records by a single_attachment field:

➡️ Single Attachment Filter
{
"filters": [
{
"field_id": "1",
"field_type": "single_attachment",
"match_type": "contains",
"values": [{ "value": "invoice" }],
"type": "file"
}
]
}

Note that the data type for an attachment field is file. Attachment filters match on the file name, never on file ids — the match value must be a string file name. Comparison is case insensitive and leading/trailing whitespace in the match value is ignored.

The following match_type values are supported for single_attachment fields:

Match typeDescription
equalMatches records whose attached file name equals the match value.
not_equalMatches records whose attached file name does not equal the match value.
containsMatches records whose attached file name contains the match value.
not_containsMatches records whose attached file name does not contain the match value.
starts_withMatches records whose attached file name starts with the match value.
ends_withMatches records whose attached file name ends with the match value.
emptyMatches records with no file attached. Omit values.
not_emptyMatches records with a file attached. Omit values.

Multi Attachment

This is an example on how to filter records by a multi_attachment field:

➡️ Multi Attachment Filter
{
"filters": [
{
"field_id": "1",
"field_type": "multi_attachment",
"match_type": "contains",
"values": [{ "value": "invoice" }],
"type": "file"
}
]
}

Like Single Attachment, the data type is file and matching is on file names (provide a string). A multi-attachment field can hold several files, so every match type quantifies over them. equal / not_equal reach the exact-match arm over the file-name set.

The following match_type values are supported for multi_attachment fields:

Match typeDescription
equalMatches records where at least one attached file name equals the match value.
not_equalMatches records where no attached file name equals the match value (records with no attachments also match).
containsMatches records where an attached file name contains the match value.
not_containsMatches records where none of the attached file names contain the match value.
starts_withMatches records where at least one attached file name starts with the match value.
ends_withMatches records where at least one attached file name ends with the match value.
emptyMatches records with no files attached. Omit values.
not_emptyMatches records with at least one file attached. Omit values.

Multi Image

This is an example on how to filter records by a multi_image field:

➡️ Multi Image Filter
{
"filters": [
{
"field_id": "1",
"field_type": "multi_image",
"match_type": "ends_with",
"values": [{ "value": ".png" }],
"type": "file"
}
]
}

Image fields share the file data type with attachment fields — the discriminant is field_type. Matching is on the image file name (provide a string). An image field can hold several images, so every match type quantifies over them; equal / not_equal reach the exact-match arm over the file-name set. Comparison is case insensitive and leading/trailing whitespace in the match value is ignored.

The following match_type values are supported for multi_image fields:

Match typeDescription
equalMatches records where at least one image file name equals the match value.
not_equalMatches records where no image file name equals the match value (records with no images also match).
containsMatches records where an image file name contains the match value.
not_containsMatches records where none of the image file names contain the match value.
starts_withMatches records where at least one image file name starts with the match value.
ends_withMatches records where at least one image file name ends with the match value.
emptyMatches records with no images. Omit values.
not_emptyMatches records with at least one image. Omit values.

Checklist

A checklist field holds a list of entries, each with a title, an optional assignee, a completion status, and an optional due date. A checklist filter targets one of these entry properties through the entry_property operand (title, assignee, status, or due_date). Every checklist match type quantifies over the entries — e.g. entry_property: "title" with contains matches a record when any entry's title contains the value.

When entry_property is omitted, the filter applies to the field as a whole and supports only empty / not_empty (i.e. "the checklist has no entries at all" / "has at least one entry").

➡️ Checklist Filter
{
"filters": [
{
"field_id": "1",
"field_type": "checklist",
"entry_property": "title",
"match_type": "contains",
"values": [{ "value": "Design review" }],
"type": "checklist"
}
]
}

The data type is always checklist. The following table lists which match types each entry_property accepts and the operand shape it expects (any other combination returns a 400):

entry_propertyAllowed match_typeOperand
(omitted)empty, not_emptynone — omit values
titlecontains, not_contains, empty, not_emptyvalues: [{ "value": "<text>" }] (a string); omit values for empty / not_empty
assigneeequal, not_equal, empty, not_emptyvalues: [{ "value": <user_id> }, …] (one or more user ids) and/or include_active_user: true; omit values for empty / not_empty
statusequalvalues: [{ "value": <boolean> }]true = completed, false = incomplete
due_dateequal, not_equal, empty, not_empty, before, after, on_or_before, on_or_after, withina date operand — see Operand keys; omit values for empty / not_empty

A few rules that are easy to miss:

  • status uses a boolean, not a match type. Unlike the top-level Status field (which uses the completed / incomplete match types), a checklist status filter is match_type: "equal" with a boolean value: false for incomplete entries, true for completed entries.
  • include_active_user is assignee-only. The include_active_user: true "@me" flag is valid only with entry_property: "assignee", and only alongside equal / not_equal (not empty / not_empty). See Operand keys.
  • Checklist due_date has no exact_range. The within match type requires a relative_date_range_type, and — unlike date fields — the checklist variant does not support exact_range (there is no exact end date to store). Use a bounded range such as next_num_days or current_week.

Example — incomplete entries (status, boolean value):

➡️ Checklist Filter — incomplete entries
{
"filters": [
{
"field_id": "1",
"field_type": "checklist",
"entry_property": "status",
"match_type": "equal",
"values": [{ "value": false }],
"type": "checklist"
}
]
}

Example — due within the next 7 days (due_date + within, using a relative range):

➡️ Checklist Filter — due within the next 7 days
{
"filters": [
{
"field_id": "1",
"field_type": "checklist",
"entry_property": "due_date",
"match_type": "within",
"relative_date_range_type": "next_num_days",
"values": [{ "value": { "offset_amount": 7 } }],
"type": "checklist"
}
]
}

Example — assigned to me (assignee + include_active_user):

➡️ Checklist Filter — assigned to me
{
"filters": [
{
"field_id": "1",
"field_type": "checklist",
"entry_property": "assignee",
"match_type": "equal",
"include_active_user": true,
"type": "checklist"
}
]
}

The following match_type values are supported for checklist fields. Which ones are valid depends on entry_property (see the matrix above):

Match typeValid entry_propertyDescription
equalassignee, status, due_dateAn entry matches the operand: assigned to the given user / completion equals the boolean / due date equals the date.
not_equalassignee, due_dateNegation of equal.
containstitleAn entry title contains the match value.
not_containstitleNo entry title contains the match value.
empty(omitted), title, assignee, due_dateField-level: the checklist has no entries. Entry-level: an entry's title / assignee / due date is empty. Omit values.
not_empty(omitted), title, assignee, due_dateComplement of empty. Omit values.
beforedue_dateAn entry's due date is before the resolved date.
afterdue_dateAn entry's due date is after the resolved date.
on_or_beforedue_dateAn entry's due date is on or before the resolved date.
on_or_afterdue_dateAn entry's due date is on or after the resolved date.
withindue_dateAn entry's due date falls within the given range. Requires relative_date_range_type.

Operand keys

Beyond values, some filters carry optional operand keys that refine the criterion. They apply mainly to the temporal filters — every filter with type: "date" (Single Date, Range Date, Created At, Last Modified At, and date-typed Calculation) — and to Checklist filters with entry_property: "due_date". Each key is validated per field type: supplying one where it is not accepted returns a 400.

offset_amount is nested; the other keys are top-level

Every operand key below is a top-level property of the filter object — except offset_amount, which lives inside the value at values[0].value.offset_amount. Placing it at the top level has no effect.

Operand keyWhere it goesApplies toUsed with
relative_date_typetop-leveldate filters, checklist due_dateresolves the target date for a comparison
relative_date_range_typetop-leveldate filters, checklist due_datematch_type: within
end_datetop-leveldate filterswithin with relative_date_range_type: exact_range
weekdaytop-leveldate filtersmatch_type: on_weekday
quarter_of_yeartop-leveldate filtersmatch_type: in_quarter_of_year
month_of_yeartop-leveldate filtersmatch_type: in_month_of_year
include_active_usertop-leveluser filters, checklist assigneeboolean "@me" flag
entry_propertytop-levelchecklistselects the entry sub-property
offset_amountnested in values[0].valuedate filters, checklist due_datethe num_* / next_num_days / past_num_days types

relative_date_type

Resolves a comparison (equal, before, after, on_or_before, on_or_after, …) to a single date. Supported values:

relative_date_typeValue to provideMeaning
today, tomorrow, yesterdaynonethe corresponding day
exact_datevalues[0].value.date (ISO-8601 string)an absolute calendar date
num_days_before, num_days_aftervalues[0].value.offset_amount (integer)N days before / after
num_weeks_before, num_weeks_aftervalues[0].value.offset_amount (integer)N weeks before / after
num_months_before, num_months_aftervalues[0].value.offset_amount (integer)N months before / after

For single_date and range_date fields the num_* offset is applied to the anchor date you pass in values[0].value.date. For created_on, last_modified_on and checklist due_date filters the offset is resolved relative to the current date (any anchor date is ignored). The exact_date value accepts only an ISO-8601 string — a numeric epoch is not honored (end_date, however, does accept an epoch number).

relative_date_range_type

Used with match_type: within to select a date range. Supported values:

relative_date_range_typeValue to provide
current_week, current_month, current_year, past_week, past_month, past_year, next_week, next_month, next_yearnone
next_num_days, past_num_daysvalues[0].value.offset_amount (integer)
exact_rangevalues[0].value.date (start) and end_date (end)

exact_range is available on date fields only. Checklist due_date filters support every value except exact_range.

end_date

An ISO date string (or epoch number) giving the end of the range for a within + exact_range filter on a date field. The range start is taken from values[0].value.date.

weekday

One of monday, tuesday, wednesday, thursday, friday, saturday, sunday. Used with match_type: on_weekday on date fields to match records whose date falls on the given weekday.

quarter_of_year

One of q1, q2, q3, q4. Used with match_type: in_quarter_of_year on date fields.

month_of_year

One of january, february, march, april, may, june, july, august, september, october, november, december. Used with match_type: in_month_of_year on date fields.

include_active_user

A boolean "@me" flag that resolves to the current API key's owner. Set include_active_user: true to match against the calling user without hard-coding a user id. It is used by user-based filters (single_user, multi_user, created_by, last_modified_by) and by checklist assignee filters. For a checklist it is valid only with entry_property: "assignee" and only with equal / not_equal (not empty / not_empty); it may be combined with explicit user ids in values.

entry_property

Checklist-only sub-discriminator: title, assignee, status, or due_date. Selects which checklist entry property the filter applies to; when omitted, the filter applies to the field as a whole (empty / not_empty only). See Checklist.

offset_amount

An integer supplied inside the value object at values[0].value.offset_amount (not as a top-level key). It provides the count for the num_days_* / num_weeks_* / num_months_* relative date types and for the next_num_days / past_num_days range types.

Record metadata filters

All of the filters above target a field — each one carries a field_id and a field_type. Tape additionally supports a small set of metadata filters that match on a record's intrinsic properties. Because every record has these properties, a metadata filter needs no field on the App.

A metadata filter is identified by its type alone and omits field_id and field_type:

typeFilters onMatch value
created_atWhen the record was creatednested — { "date": "…" }
last_modified_atWhen the record was last modifiednested — { "date": "…" }
app_record_idThe record's App-specific ID (the app_record_id property)bare scalar — e.g. 123

Metadata filters go in the same filters array as field filters and are combined with the same boolean AND.

The timestamp match value is nested

created_at and last_modified_at read the match value from values[0].value.date — a nested object. Field filters and app_record_id use a bare scalar at values[0].value. This asymmetry is an easy integration mistake to make.

Created At (metadata)

Filter records by their creation time, without the App having a Created-At field:

➡️ Created At Meta Filter — bounded window
{
"filters": [
{
"type": "created_at",
"match_type": "on_or_after",
"values": [{ "value": { "date": "2026-07-01T00:00:00.000Z" } }]
},
{
"type": "created_at",
"match_type": "on_or_before",
"values": [{ "value": { "date": "2026-07-02T00:00:00.000Z" } }]
}
]
}
  • Absolute UTC dates only. Provide a full ISO-8601 timestamp as value.date. relative_date_type may be omitted or set to exact_date; any genuinely relative value (num_days_before, num_weeks_after, …) returns a 400. The offset_amount sub-field is accepted by the type but ignored — do not rely on it.
  • All bounds are inclusive. Every supported match type compares with >= or <=: after behaves exactly like on_or_after, and before like on_or_before.
  • Express a window with two filters — one lower bound and one upper bound, as shown above. Repeating a bound in the same direction narrows the window (the latest lower bound and the earliest upper bound win); it never widens it.
  • Invalid input fails loudly with a 400 rather than being silently dropped — an unsupported match_type, a missing or unparseable date, or a calendar year outside 19999.

The following match_type values are supported for created_at:

Match typeDescription
after, on_or_after, larger, larger_or_equalMatches records created on or after the value
before, on_or_before, smaller, smaller_or_equalMatches records created on or before the value

Any other match type (equal, empty, not_empty, …) returns a 400.

For filtering an App that has a dedicated Created-At field, see Created At above.

Last Modified At (metadata)

Identical to Created At (metadata) in every respect — same match types, inclusive bounds, absolute-date rule and 400 behavior — using type: "last_modified_at":

➡️ Last Modified At Meta Filter
{
"filters": [
{
"type": "last_modified_at",
"match_type": "on_or_after",
"values": [{ "value": { "date": "2026-07-01T00:00:00.000Z" } }]
}
]
}
Never-modified records are excluded

A record that has not been edited since it was created has no last-modified timestamp, and matches no last_modified_at filter — not even a far-past on_or_after. To retrieve everything created or modified since a point in time, query created_at and last_modified_at separately and merge the results (see Pattern: incremental sync).

App Record ID (metadata)

Filter records by their App-specific ID — the sequential app_record_id returned on every record (the first record created in an App is 1, the second 2, and so on):

➡️ App Record ID Meta Filter
{
"filters": [
{
"type": "app_record_id",
"match_type": "larger_or_equal",
"values": [{ "value": 1000 }]
}
]
}

The match value is a bare scalar (values[0].value), not a nested object, and must be numeric — a missing or non-numeric value returns a 400 for every match type, including empty / not_empty.

The following match_type values are supported for app_record_id:

Match typeDescription
equalMatches the record whose App ID equals the value
not_equalMatches all records whose App ID does not equal the value
largerMatches all records whose App ID is larger than the value
larger_or_equalMatches all records whose App ID is larger than or equal to the value
smallerMatches all records whose App ID is smaller than the value
smaller_or_equalMatches all records whose App ID is smaller than or equal to the value
emptyMatches records that have no App ID
not_emptyMatches records that have an App ID

Any other match type returns a 400. Note that every record always has an app_record_id, so in practice empty matches nothing and not_empty matches every record.

Pattern: incremental sync

A common use of the timestamp metadata filters is an incremental sync — pulling only the records that changed since your last run, without having to add Created-At or Last-Modified fields to every App.

Because filters combine with AND (there is no OR), "created or modified since T" cannot be expressed in a single request. Issue two requests and union the results:

➡️ Request 1 — records created since T
{
"filters": [
{
"type": "created_at",
"match_type": "on_or_after",
"values": [{ "value": { "date": "2026-07-22T00:00:00.000Z" } }]
}
]
}

De-duplicate the combined result by record id. Request 2 only returns records edited since creation (see the caveat above), which is why Request 1 is still needed to catch brand-new records.

These filters previously had no effect

Before this change, the API accepted created_at and last_modified_at metadata filters but silently ignored them, returning the full unfiltered record set. They are now applied. An integration that was unknowingly relying on the old no-op behavior will see its result sets shrink.