Eight places in the repository hand a v3 reader a method name that no v3 portal
publishes. Seven are crm.item.* / crm.contact.list, which exist only on v2;
one is tasks.task.comment.list, which exists nowhere. Every one sits inside
something explicitly labelled v3 — a restApiVersion: 'rest-api-ver3' page, a
[v3] code fence, or the JSDoc of a …V3 export. Copy any of them and the call
fails: the portal answers an unpublished method with a soft
METHODNOTFOUNDEXCEPTION. Mechanical and cheap: eight string swaps, no behaviour
change, no new dependency. Good first PR.
What we claim
All eight locations are in the swap table below; line numbers are from commit
6e8c85f, where every occurrence was opened.
The parameter table of both v3 list pages carries the same row, verbatim:
| **`method`** | `string`{lang="ts-type"} | Yes | REST API method name that returns a data list (e.g., `crm.contact.list`, `tasks.task.list`). |
The first example offered on a v3 page is a method that is not on v3. The second
one is fine.
call.ts:27 is the worst of the eight, because it is what an IDE shows on hover
at the moment someone is typing a method name:
* - `method: string` - REST API method name (eg: `crm.item.get`)
Every one of these three files already contradicts its own parameter line lower
down: the @example blocks at call.ts:36, call-list.ts:67 and
fetch-list.ts:70 use tasks.task.get and main.eventlog.list, which are real,
as does the matching docs page (1.call-rest-api-ver3.md:57).
5.filtering.md has two problems, not one: its [v3] fence calls crm.item.list
and passes entityTypeId — a field exactly one v3 path declares in its request
schema across the three snapshots (main.like.reactions, cloud only, not a list
method).
The repository already contradicts itself here:
skills/b24jssdk-rest/SKILL.md:407 lists the exact call in call.ts:27 as an
anti-pattern —
❌ Calling $b24.actions.v3.call.make({ method: 'crm.item.get', ... }) — crm.* is v2-only, so the v3 server returns a METHODNOTFOUNDEXCEPTION soft error
What the portal does
Measured from rest.documentation.openapi snapshots taken 2026-09-02..04 on three
portals: an on-premise build (SM_VERSION 26.700.0), a cloud portal, and a
disposable cloud sandbox.
|
on-premise |
cloud |
sandbox |
| v3 paths published |
147 |
245 |
220 |
paths matching crm.item. |
0 |
0 |
0 |
paths named crm.contact.list |
0 |
0 |
0 |
paths matching tasks.task.comment. |
0 |
0 |
0 |
methods in the tasks module |
19 |
22 |
22 |
crm is not absent from v3 outright — on the two cloud portals it appears as
timeline email (crm.activity.mail.*,
crm.{company,contact,deal,lead}.timeline.activity.email.*); the on-premise build
has no crm path at all. But crm.item.* and crm.contact.list are nowhere.
An unpublished method comes back as a soft error, not a throw. Measured live
on the on-premise build with two unpublished names, both matching the expected
METHODNOTFOUNDEXCEPTION; this portal answered:
Метод `main.eventlog.aggregate` не найден
Метод `no.such.method.at.all` не найден
Both read "Method <name> not found". The message is portal-localised and the
error code is not, so match on the code, never on the text.
All four replacements proposed below are published on all three portals. Request
fields, from the same snapshots: tasks.task.list, main.eventlog.list and
tasks.task.result.list each take select, filter, order, pagination;
tasks.task.get takes id, select. (note.collection.list — not a
replacement, see below — takes pagination and nothing else.)
Why it matters
The failure is soft: response.isSuccess === false, no exception, so a caller who
copies an example and does not check isSuccess gets an empty result rather than
a stack trace — and, via call.ts:27, is steered to the one call the SDK's own
skill file lists as a mistake.
pnpm run lint:v3-refs is green and always will be here.
scripts/check-v3-method-refs.mjs matches actions\.v3\.([a-zA-Z]\w*) against its
V3_ACTIONS set of eight action names (line 28; the prose header at lines 7-8
lists only seven and is stale — it omits aggregate), over Markdown under
docs/content/docs, skills/, and packages/jssdk/README-AI.md. It never reads
packages/jssdk/src/** and never looks at a portal method name at all — the gap
named when #206 was closed.
What to do
Eight swaps. Pages are under docs/content/docs/2.working-with-the-rest-api/,
*.ts under packages/jssdk/src/ (core/actions/v3/, except
tools/batch-ref-v3.ts):
| Location |
Now |
Proposed |
2.call-list-rest-api-ver3.md:74 |
crm.contact.list, tasks.task.list |
tasks.task.list, main.eventlog.list |
2.fetch-list-rest-api-ver3.md:72 |
same row |
same |
call.ts:27 |
crm.item.get |
tasks.task.get — matches its @example |
call-list.ts:41 |
crm.item.list, tasks.task.list |
tasks.task.list, main.eventlog.list — matches its @example |
fetch-list.ts:43 |
same line |
same |
5.filtering.md:172-193 |
crm.item.list + entityTypeId |
tasks.task.list, entityTypeId dropped |
batch.ts:59-60 |
crm.item.get ×2 |
tasks.task.get with { id, select } |
batch-ref-v3.ts:49 |
tasks.task.comment.list |
tasks.task.result.list |
Two need a word of justification.
5.filtering.md. The page's point is v2 prefix-keyed filters versus v3
array-of-triples, so the v3 half only has to be a real v3 list method with a date
field and an enum-ish field. tasks.task.list has both — its order schema
exposes status, priority, created, deadline, responsibleId. Dropping
entityTypeId is not optional: tasks.task.list accepts select, filter,
order, pagination and nothing else. idKey: 'id' and
customKeyForResult: 'items' stay correct for it on v3, per
skills/b24jssdk-recipes/SKILL.md:164.
batch-ref-v3.ts:49. The example collects task ids and filters a second
command by them, so the replacement must accept a filter on a task id.
tasks.task.result.list does: it accepts filter, and the portal's schema lists
taskId among its select example fields. (The phantom name itself most likely
came from the hand-written v3 reference this file cites as "reference §8", which
uses it — an inference from the citation, not a measurement.) Shape:
const response = await b24.actions.v3.batch.make({
calls: [
{ method: 'tasks.task.list', as: 'tasks', params: { select: ['id'] } },
{
method: 'tasks.task.result.list',
params: { filter: [['taskId', 'in', R.refArray('tasks.id')]] }
}
]
})
There is no v3 analogue of "task comments" to substitute one-for-one: the tasks
module publishes tasks.task.chat.message.send and two field.* descriptors, but
nothing that lists messages. Do not invent one.
Bump audited: on five pages in that same directory — the three edited directly
(2.call-list-rest-api-ver3.md, 2.fetch-list-rest-api-ver3.md,
5.filtering.md, all stamped 2026-08-29) plus the two whose frontmatter
links: point at a JSDoc file being edited (1.call-rest-api-ver3.md →
v3/call.ts and 3.batch-rest-api-ver3.md → v3/batch.ts, both 2026-08-31),
since docs:lint-pages compares the stamp against git log of each linked
source. 3.api-reference/1.index.md names batch-ref-v3.ts in its body table
(line 45) but not in its links:, which holds only index.ts — and
docs:lint-pages reads links: only, so that page is never aged and needs no
bump.
While in the same two tables: the customKeyForResult row
(2.call-list-rest-api-ver3.md:78, 2.fetch-list-rest-api-ver3.md:76) and the
same JSDoc lines justify items by "a list of CRM elements" / "CRM items". The
value is right on v3; only the CRM justification is not.
What not to do:
How to verify
Local, no portal:
pnpm run docs:lint # lint-pages + lint-links + api-index
pnpm run docs:typecheck-blocks
pnpm run jsdoc:typecheck-blocks # the edited @example blocks must still compile
pnpm run lint:v3-refs # green before and after — that is the point
pnpm run lint && pnpm run typecheck
docs:lint-pages only warns about a stale audited:; docs:lint-pages:strict
turns that warning into a failure.
With a portal (local only — these never run in CI):
// absence, directly:
const r = await b24.actions.v3.call.make({ method: 'crm.item.get', params: { id: 1 } })
console.log(r.isSuccess, r.getErrorMessages()) // false, METHODNOTFOUNDEXCEPTION
// presence of every replacement:
for (const method of ['tasks.task.list', 'main.eventlog.list', 'tasks.task.result.list']) {
console.log(method, (await b24.actions.v3.call.make({ method, params: { pagination: { limit: 1 } } })).isSuccess)
}
Regression test: none in this PR, deliberately — nothing here is SDK
behaviour. If you want a lock anyway, the smallest honest one is a
*.unit.spec.ts under test/integration/ (project jsSdk:unit, one of the three
portal-free projects CI runs) grepping core/actions/v3/** and
tools/batch-ref-v3.ts for the three names measured absent — crm.item.,
crm.contact.list, tasks.task.comment. — and nothing else. Not a blanket ban on
crm.: crm.activity.mail.* is genuinely on v3 in the cloud.
Not verified
crm.item.get was never called on a v3 endpoint. The absence claim is from
the three OpenAPI documents; the soft-error behaviour was measured with two
other unpublished names.
- Whether
taskId is filterable on tasks.task.result.list. It appears in
that method's select example in the portal's schema; the proposed $refArray
batch was not executed.
customKeyForResult: 'items' for tasks.task.list on v3 is taken from the
repo's own skill file (b24jssdk-recipes/SKILL.md:164), not re-measured.
- Whether
between works on tasks.task.list. The rewritten filtering
example needs its operator mix checked against a portal before merge.
- Cloud/sandbox request schemas were compared for method presence only; the
request fields above are from the on-premise snapshot. And the counts cover only
the four names searched — no exhaustive sweep for other v2 method names sitting
in v3-labelled prose.
Eight places in the repository hand a v3 reader a method name that no v3 portal
publishes. Seven are
crm.item.*/crm.contact.list, which exist only on v2;one is
tasks.task.comment.list, which exists nowhere. Every one sits insidesomething explicitly labelled v3 — a
restApiVersion: 'rest-api-ver3'page, a[v3]code fence, or the JSDoc of a…V3export. Copy any of them and the callfails: the portal answers an unpublished method with a soft
METHODNOTFOUNDEXCEPTION. Mechanical and cheap: eight string swaps, no behaviourchange, no new dependency. Good first PR.
What we claim
All eight locations are in the swap table below; line numbers are from commit
6e8c85f, where every occurrence was opened.The parameter table of both v3 list pages carries the same row, verbatim:
The first example offered on a v3 page is a method that is not on v3. The second
one is fine.
call.ts:27is the worst of the eight, because it is what an IDE shows on hoverat the moment someone is typing a method name:
Every one of these three files already contradicts its own parameter line lower
down: the
@exampleblocks atcall.ts:36,call-list.ts:67andfetch-list.ts:70usetasks.task.getandmain.eventlog.list, which are real,as does the matching docs page (
1.call-rest-api-ver3.md:57).5.filtering.mdhas two problems, not one: its[v3]fence callscrm.item.listand passes
entityTypeId— a field exactly one v3 path declares in its requestschema across the three snapshots (
main.like.reactions, cloud only, not a listmethod).
The repository already contradicts itself here:
skills/b24jssdk-rest/SKILL.md:407lists the exact call incall.ts:27as ananti-pattern —
What the portal does
Measured from
rest.documentation.openapisnapshots taken 2026-09-02..04 on threeportals: an on-premise build (
SM_VERSION 26.700.0), a cloud portal, and adisposable cloud sandbox.
crm.item.crm.contact.listtasks.task.comment.tasksmodulecrmis not absent from v3 outright — on the two cloud portals it appears astimeline email (
crm.activity.mail.*,crm.{company,contact,deal,lead}.timeline.activity.email.*); the on-premise buildhas no
crmpath at all. Butcrm.item.*andcrm.contact.listare nowhere.An unpublished method comes back as a soft error, not a throw. Measured live
on the on-premise build with two unpublished names, both matching the expected
METHODNOTFOUNDEXCEPTION; this portal answered:Both read "Method
<name>not found". The message is portal-localised and theerror code is not, so match on the code, never on the text.
All four replacements proposed below are published on all three portals. Request
fields, from the same snapshots:
tasks.task.list,main.eventlog.listandtasks.task.result.listeach takeselect,filter,order,pagination;tasks.task.gettakesid,select. (note.collection.list— not areplacement, see below — takes
paginationand nothing else.)Why it matters
The failure is soft:
response.isSuccess === false, no exception, so a caller whocopies an example and does not check
isSuccessgets an empty result rather thana stack trace — and, via
call.ts:27, is steered to the one call the SDK's ownskill file lists as a mistake.
pnpm run lint:v3-refsis green and always will be here.scripts/check-v3-method-refs.mjsmatchesactions\.v3\.([a-zA-Z]\w*)against itsV3_ACTIONSset of eight action names (line 28; the prose header at lines 7-8lists only seven and is stale — it omits
aggregate), over Markdown underdocs/content/docs,skills/, andpackages/jssdk/README-AI.md. It never readspackages/jssdk/src/**and never looks at a portal method name at all — the gapnamed when #206 was closed.
What to do
Eight swaps. Pages are under
docs/content/docs/2.working-with-the-rest-api/,*.tsunderpackages/jssdk/src/(core/actions/v3/, excepttools/batch-ref-v3.ts):2.call-list-rest-api-ver3.md:74crm.contact.list,tasks.task.listtasks.task.list,main.eventlog.list2.fetch-list-rest-api-ver3.md:72call.ts:27crm.item.gettasks.task.get— matches its@examplecall-list.ts:41crm.item.list,tasks.task.listtasks.task.list,main.eventlog.list— matches its@examplefetch-list.ts:435.filtering.md:172-193crm.item.list+entityTypeIdtasks.task.list,entityTypeIddroppedbatch.ts:59-60crm.item.get×2tasks.task.getwith{ id, select }batch-ref-v3.ts:49tasks.task.comment.listtasks.task.result.listTwo need a word of justification.
5.filtering.md. The page's point is v2 prefix-keyed filters versus v3array-of-triples, so the v3 half only has to be a real v3 list method with a date
field and an enum-ish field.
tasks.task.listhas both — itsorderschemaexposes
status,priority,created,deadline,responsibleId. DroppingentityTypeIdis not optional:tasks.task.listacceptsselect,filter,order,paginationand nothing else.idKey: 'id'andcustomKeyForResult: 'items'stay correct for it on v3, perskills/b24jssdk-recipes/SKILL.md:164.batch-ref-v3.ts:49. The example collects task ids and filters a secondcommand by them, so the replacement must accept a filter on a task id.
tasks.task.result.listdoes: it acceptsfilter, and the portal's schema liststaskIdamong itsselectexample fields. (The phantom name itself most likelycame from the hand-written v3 reference this file cites as "reference §8", which
uses it — an inference from the citation, not a measurement.) Shape:
There is no v3 analogue of "task comments" to substitute one-for-one: the
tasksmodule publishes
tasks.task.chat.message.sendand twofield.*descriptors, butnothing that lists messages. Do not invent one.
Bump
audited:on five pages in that same directory — the three edited directly(
2.call-list-rest-api-ver3.md,2.fetch-list-rest-api-ver3.md,5.filtering.md, all stamped2026-08-29) plus the two whose frontmatterlinks:point at a JSDoc file being edited (1.call-rest-api-ver3.md→v3/call.tsand3.batch-rest-api-ver3.md→v3/batch.ts, both2026-08-31),since
docs:lint-pagescompares the stamp againstgit logof each linkedsource.
3.api-reference/1.index.mdnamesbatch-ref-v3.tsin its body table(line 45) but not in its
links:, which holds onlyindex.ts— anddocs:lint-pagesreadslinks:only, so that page is never aged and needs nobump.
While in the same two tables: the
customKeyForResultrow(
2.call-list-rest-api-ver3.md:78,2.fetch-list-rest-api-ver3.md:76) and thesame JSDoc lines justify
itemsby "a list of CRM elements" / "CRM items". Thevalue is right on v3; only the CRM justification is not.
What not to do:
check-v3-method-refs.mjs. Its header records that the allowlist was removed onpurpose, because the server validates method support; the guard's job is
narrower (ci(docs/skills): guard against v3 method/action drift — phantom actions + non-whitelisted methods #216 — phantom
actions.v3.*names, after theactions.v3.aggregatewalk-back in docs+skills: remove references to the non-existent actions.v3.aggregate action #164). A snapshot-driven coverage tool is the right answer and
belongs in feat(scripts): check documented v3 method names against a committed OpenAPI snapshot #463.
crm.item.*in the*-rest-api-ver2.mdpages,
v2/call.ts,v2/batch.ts,99.examples/and the v2 specs is correct.skills/b24jssdk-filtering/SKILL.md:164andskills/b24jssdk-recipes/SKILL.md:129, which callcrm.item.lista "v3-stylemethod". They are about camelCase field naming, not the v3 endpoint; that wording
needs a careful separate rewrite a mechanical sweep would mangle.
note.collection.listwhere the example showsfilterorselect— a real v3 method, but its request schema takespaginationonly.How to verify
Local, no portal:
docs:lint-pagesonly warns about a staleaudited:;docs:lint-pages:strictturns that warning into a failure.
With a portal (local only — these never run in CI):
Regression test: none in this PR, deliberately — nothing here is SDK
behaviour. If you want a lock anyway, the smallest honest one is a
*.unit.spec.tsundertest/integration/(projectjsSdk:unit, one of the threeportal-free projects CI runs) grepping
core/actions/v3/**andtools/batch-ref-v3.tsfor the three names measured absent —crm.item.,crm.contact.list,tasks.task.comment.— and nothing else. Not a blanket ban oncrm.:crm.activity.mail.*is genuinely on v3 in the cloud.Not verified
crm.item.getwas never called on a v3 endpoint. The absence claim is fromthe three OpenAPI documents; the soft-error behaviour was measured with two
other unpublished names.
taskIdis filterable ontasks.task.result.list. It appears inthat method's
selectexample in the portal's schema; the proposed$refArraybatch was not executed.
customKeyForResult: 'items'fortasks.task.liston v3 is taken from therepo's own skill file (
b24jssdk-recipes/SKILL.md:164), not re-measured.betweenworks ontasks.task.list. The rewritten filteringexample needs its operator mix checked against a portal before merge.
request fields above are from the on-premise snapshot. And the counts cover only
the four names searched — no exhaustive sweep for other v2 method names sitting
in v3-labelled prose.