Overview
rest.documentation.openapi is a v3 REST method that returns the portal's ownOpenAPI 3.0.0 document — a single
machine-readable description of every REST API v3 method that exists on that
specific portal, with the request body fields (and example values) and the
response envelope for each one.
This is the source of truth for v3 method availability. The SDK deliberately
keeps no hardcoded list of v3 methods (an earlier allowlist both lagged the
server and blocked valid methods); instead, $b24.actions.v3.* sends any method
to the server and lets it decide. When you need to know what's actually there
— which methods, which fields — you ask the portal itself with this call.
BITRIX_REST_V3_EXCEPTION_INSUFFICIENTSCOPEEXCEPTION (403) when the token lacks
the scope — so the document cannot be used as a permission check. It is not
filtered by your rights either: widening a webhook from 10 scopes to 15 did not
change it at all. Scopes are published separately, by rest.scope.list.result wrapper and no time block. The SDK wraps it
back into result so the snippets below work, but a raw HTTP client will see the
document itself as the response body.Calling it through the SDK
It's an ordinary v3 call — no special helper:
const response = await $b24.actions.v3.call.make<{ openapi: string }>({
method: 'rest.documentation.openapi'
})
if (!response.isSuccess) {
console.error(new Error(`Error: ${response.getErrorMessages().join('; ')}`))
} else {
const doc = response.getData()?.result
console.log(`OpenAPI ${doc?.openapi}`) // e.g. "3.0.0"
}
Is a given action published? The *.aggregate case
Because paths is one entry per method, a suffix filter answers "does this
portal publish this kind of action at all" in a single call. Aggregation is the
case that keeps coming up, since actions.v3.aggregate.make is @experimental
precisely because nothing shipped exercises it:
const response = await $b24.actions.v3.call.make<{ paths?: Record<string, unknown> }>({
method: 'rest.documentation.openapi'
})
const aggregates = Object.keys(response.getData()?.result?.paths ?? {})
.filter(path => path.endsWith('.aggregate'))
.map(path => path.replace(/^\//, ''))
console.log(aggregates.length === 0 ? '(none)' : aggregates.join(', '))
On the four portals measured this prints (none): no shipped module opts into
the server-side aggregation trait, so
Aggregate.make()
has nothing to run against and a client-side reduce over CallList is the
answer. Ask your own portal rather than taking that as permanent — the machinery
ships and works, and a module can opt in at any version.
What the document looks like
A standard OpenAPI 3.0.0 object. The parts you care about in practice:
Each paths['/method.name'] carries post (and get) operations with a
tags array (the owning module), a requestBody JSON Schema describing the
accepted parameters — often with an example field listing the real field
names — and a responses schema for the { result } envelope.
// Shape (abridged) — the fields you read in practice
type OpenApiDoc = {
openapi: string // e.g. "3.0.0"
info: { title: string, version: string } // title: "Bitrix24 REST V3 API"
tags: Array<{ name: string, description: string }> // one entry per module
paths: Record<string, {
// keyed by "/method.name", e.g. "/tasks.task.list"
post?: {
tags?: string[] // the owning module
requestBody?: { content: { 'application/json': { schema: unknown } } }
}
get?: { tags?: string[] }
}>
}
Why this matters for AI agents
The document is the cleanest way for an LLM or a code generator to work against a portal without guessing:
- Discovery — enumerate exactly which v3 methods exist before generating a
call, instead of hallucinating a method name that returns
METHODNOTFOUNDEXCEPTION. - Correct fields — read the real
select/ parameter names from each method'srequestBodyschema (and itsexample) instead of inventing them. - Typing / codegen — feed the schema into a generator to produce typed
wrappers, or narrow
$b24.actions.v3.call.make<T>()with the rightT. - Portal-aware — because the answer is per-portal, an agent can adapt to the
modules actually installed rather than to a generic assumption. Scopes are a
separate question the document does not answer; pair it with
rest.scope.list, which is where the portal publishes them.
Error Handling
rest.documentation.openapi is a normal v3 call, so it follows the standard
AjaxResult contract — always check isSuccess before reading
the document:
const response = await $b24.actions.v3.call.make<{ openapi: string }>({
method: 'rest.documentation.openapi'
})
if (!response.isSuccess) {
// e.g. the token lacks the scope, or the portal is unreachable
console.error(new Error(`Error: ${response.getErrorMessages().join('; ')}`))
} else {
const doc = response.getData()?.result
console.log(`OpenAPI ${doc?.openapi}`)
}
Examples
List every available method
const response = await $b24.actions.v3.call.make<{
paths: Record<string, unknown>
}>({ method: 'rest.documentation.openapi' })
const methods = Object.keys(response.getData()?.result?.paths ?? {})
.map(path => path.replace(/^\//, '')) // "/tasks.task.list" → "tasks.task.list"
console.log(`${methods.length} v3 methods available`)
Methods grouped by module
type OpenApiDoc = {
paths: Record<string, { post?: { tags?: string[] } }>
}
const doc = (await $b24.actions.v3.call.make<OpenApiDoc>({
method: 'rest.documentation.openapi'
})).getData()?.result
const byModule = new Map<string, string[]>()
for (const [path, ops] of Object.entries(doc?.paths ?? {})) {
const moduleName = ops.post?.tags?.[0] ?? 'unknown'
const list = byModule.get(moduleName) ?? []
list.push(path.replace(/^\//, ''))
byModule.set(moduleName, list)
}
console.log([...byModule.keys()]) // ['humanresources', 'mail', 'main', 'note', 'rest', 'tasks', 'timeman', …]
Check whether a specific method exists
const doc = (await $b24.actions.v3.call.make<{ paths: Record<string, unknown> }>({
method: 'rest.documentation.openapi'
})).getData()?.result
const exists = Boolean(doc?.paths?.['/note.collection.list'])
console.log(`note.collection.list on v3: ${exists}`)
Alternatives and Recommendations
- For one entity's fields:
<entity>.field.listis the cheaper half of the same question. This document tells you which methods exist; that one tells you which fields this entity has — and carriesfilterable,editableandrequiredGroups, which are not in the request schema here at all. - Apidocs reference: the public REST API v3 reference
documents methods in human-readable form;
rest.documentation.openapiis the programmatic, portal-specific counterpart. - For calling a discovered method: use
Call,CallList/FetchList, or the nativeCallTail/FetchTailwhen the method publishes atailaction. - Picking v2 vs v3: see Choosing the right method.
Errors
Reference for SdkError and AjaxError codes raised by the SDK, plus the Bitrix24 REST error codes that surface through them.
Security
Two hardening patterns for any server that receives Bitrix24 outbound events or OAuth install/uninstall callbacks: reply 200 before you verify, and compare application_token in constant time.