Overview
Most restApi:v3 entities publish a pair of metadata methods:
<entity>.field.list— every field the entity has, as a list of descriptors;<entity>.field.get— one field, byname.
This is a large part of the v3 surface: 91 of the 245 methods a measured cloud portal
publishes belong to this family — 37%. Every module has it: rest 22, main 18, note 10,
bizprocdesigner 9, humanresources 8, tasks 8, mail 6, vibecodeconnector 6,
call 2, timeman 2.
Calling it through the SDK
An ordinary v3 call — no special helper:
const response = await $b24.actions.v3.call.make<{
items: Array<{ name: string, type: string, sortable: boolean, filterable: boolean }>
}>({ method: 'tasks.task.field.list' })
const fields = response.getData()?.result?.items ?? []
const sortable = fields.filter(field => field.sortable).map(field => field.name)
The rows arrive under result.items. <entity>.field.get answers with a single
descriptor under result.item instead:
const response = await $b24.actions.v3.call.make<{
item: { name: string, type: string, sortable: boolean }
}>({ method: 'tasks.task.field.get', params: { name: 'title' } })
Both accept an optional select, which narrows the descriptor keys — pass
select: ['name', 'sortable'] and each row comes back with those two keys only.
What a descriptor holds
Three of these have no other source. filterable, editable and requiredGroups
appear nowhere in the OpenAPI document's request schema, so "can I filter on this?" and
"what must I pass to add?" are answerable here and nowhere else.
sortable and filterable are independent — do not infer one from the other. They
happen to name the same five fields on main.eventlog (id, timestampX, auditTypeId,
userId, guestId of thirteen), which makes the coincidence look like a rule. It is not:
on tasks.task, title is sortable: true and filterable: false, and exactly one field
of ninety-five — id — is filterable at all, against nineteen that are sortable. A rich
order alongside a bare filter is a normal state for a v3 entity, not a portal fault.
Under restApi:v2 the same entity filters on RESPONSIBLE_ID, STATUS and GROUP_ID
happily; that is a difference between the two APIs, not something to work around.filterable also gates aggregation, which the flag's name does not suggest.
A field that is selectable and comes back from list quite normally is still
refused by an aggregate select unless it is filterable — the portal checks the
same attribute for both. Measured: the refusal is a soft failure
(isSuccessfalse, not a throw — a 4xx in the
restApi:v3 envelope), carrying
BITRIX_REST_V3_EXCEPTION_VALIDATION_REQUESTVALIDATIONEXCEPTION and naming the
field in validation[].field. Match on the code and the field:
the message is localised. Given the ratio above, this is a real constraint on
what you can ask a v3 entity to count —
see Choosing the right method.requiredGroups is null rather than an empty array when a field is
required by nothing — guard before iterating it.
filterable or sortable is decided by the Bitrix24 module that owns the entity, and it
changes from one module version to the next. The reference documentation states the current
answer per method — tasks.task.list on restApi:v3, for instance,
documents id as the only supported filter
— but the portal in front of you is the one that answers your request. Read the flag rather
than assume, especially in code that has to keep working across portal upgrades.Why it is worth the call
A v3 field that is not marked Filterable or Sortable is refused — the portal does not
quietly ignore the clause. Both refusals were measured, on two entities. Both arrive
soft: a 4xx in the restApi:v3 envelope is not thrown, so check
isSuccess rather than writing a try/catch around these.
// `title` has `filterable: false` — this answers HTTP 400
await $b24.actions.v3.call.make({
method: 'tasks.task.list',
params: { filter: [['title', '=', 'x']], select: ['id'] }
})
{
"error": {
"code": "BITRIX_REST_V3_EXCEPTION_VALIDATION_REQUESTVALIDATIONEXCEPTION",
"validation": [{ "field": "title", "message": "…requires the `Filterable` attribute…" }]
}
}
Ordering by a field with sortable: false answers the same way, naming Sortable — measured
on main.eventlog.list ordered by description, one of the thirteen fields that method
returns:
{
"error": {
"code": "BITRIX_REST_V3_EXCEPTION_VALIDATION_REQUESTVALIDATIONEXCEPTION",
"validation": [{ "field": "description", "message": "…`EventLogDto`…`Sortable`…" }]
}
}
A field being returned says nothing about whether it may be filtered or sorted on.
message is localised — a portal answers in the portal's language. Match on
error.code and on validation[].field, never on the text.The useful habit is therefore: read the fields, then build the request.
const meta = await $b24.actions.v3.call.make<{
items: Array<{ name: string, filterable: boolean, sortable: boolean }>
}>({ method: 'tasks.task.field.list', params: { select: ['name', 'filterable', 'sortable'] } })
const fields = meta.getData()?.result?.items ?? []
const canFilterOn = new Set(fields.filter(field => field.filterable).map(field => field.name))
// On the portal measured, `tasks.task` exposes exactly one filterable field: `id`.
if (canFilterOn.has('deadline')) {
// …only then send a filter on `deadline`
}
Field names
restApi:v3 field names are camelCase. Measured across two entities and 108
descriptors — tasks.task (95) and main.eventlog (13) — not one of the 108 starts with an
uppercase letter: id, title, creatorId, responsibleId, startPlan, storyPoints,
timestampX, auditTypeId.
restApi:v2 is the opposite: ID, TITLE, RESPONSIBLE_ID.
That is the whole reason for the SDK's paging defaults, and it is a rule rather than a per-method quirk:
cursorIdKey exists for the methods that spell the id differently in the request and in
the response. Under restApi:v2, tasks.task.list is the known case: it returns a
lowercase id but filters on an uppercase ID, so a walk left on the defaults reads the
cursor from a field that is not there, never advances, and repeats the first page for ever.
// restApi:v2 `tasks.task.list` — without `cursorIdKey` the walk never ends
const response = await $b24.actions.v2.callList.make({
method: 'tasks.task.list',
params: { select: ['ID', 'TITLE'] },
idKey: 'id',
cursorIdKey: 'ID',
customKeyForResult: 'tasks'
})
Under restApi:v3 the same method needs no override — request and response agree on id.
<entity>.field.list what the response calls its id.Availability
Near-universal, not universal. On the cloud portal measured, seven entities publish a
.list with no matching .field.list — the four crm.*.timeline.activity.email families,
humanresources.access.permission, humanresources.node.communication and rest.scope.
Treat a missing metadata method as ordinary: check isSuccess and fall back to the OpenAPI
document or to documented field names.
The counts here are portal-specific, like the rest of the v3 surface — the portals measured published 147, 220 and 245 methods in total. Read them as an order of magnitude, not a contract.
Alternatives and Recommendations
- One entity's fields, with flags —
<entity>.field.list. Small, cheap, per entity, and the only source offilterable/editable/requiredGroups. - The whole method surface —
rest.documentation.openapi. One document, often 100 KB or more; fetch it once and cache it. - Neither — for
restApi:v2, the classiccrm.item.fields/*.fieldsmethods still apply; this family is v3.