For AI agents: markdown of this page — /docs-content-en/performan/endpoints.md documentation index — /llms.txt
Performance review operations
Five read methods return campaigns, stage cards and manager-stage questions, and one write method saves a manager's draft answer or finalises the review. Switch methods in the tabs — each has its own parameters, response fields and error codes.
Scope: performan | Base URL: https://vibecode.bitrix24.com/v1 | Authorization: X-Api-Key
Review campaigns
GET /v1/performan/review/campaigns
Returns the performance review campaigns the key owner takes part in. The listing is cursor based, and an optional parameter narrows it down to a single campaign.
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
campaignId (query) |
number | no | — | Narrow the listing to one campaign. A campaign id, a positive integer |
limit (query) |
number | no | 50 | Records per page, 200 at most |
afterCursorId (query) |
number | no | — | The next-page cursor. The value comes from meta.nextCursor.id of the previous response. The first request omits it |
Examples
curl — personal key
curl "https://vibecode.bitrix24.com/v1/performan/review/campaigns?limit=20" \
-H "X-Api-Key: YOUR_API_KEY"
curl — OAuth application
curl "https://vibecode.bitrix24.com/v1/performan/review/campaigns?limit=20" \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN"
JavaScript — personal key
const res = await fetch('https://vibecode.bitrix24.com/v1/performan/review/campaigns?limit=20', {
headers: { 'X-Api-Key': 'YOUR_API_KEY' },
})
const body = await res.json()
if (!body.success) {
throw new Error(`${body.error.code}: ${body.error.message}`)
}
for (const campaign of body.data) {
console.log(campaign.id, campaign.title, campaign.status)
}
// Next page: put the cursor id into afterCursorId of the new request
console.log(body.meta.nextCursor)
JavaScript — OAuth application
const res = await fetch('https://vibecode.bitrix24.com/v1/performan/review/campaigns?limit=20', {
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
},
})
const body = await res.json()
if (!body.success) {
throw new Error(`${body.error.code}: ${body.error.message}`)
}
console.log(body.data, body.meta.nextCursor)
Response fields
| Field | Type | Description |
|---|---|---|
success |
boolean | Always true on success |
data |
array | The campaign array |
data[].id |
number | Campaign id. Goes into the campaignId parameter of the other methods of the section |
data[].title |
string | Campaign name |
data[].status |
string | Campaign state: created — created, inProgress — running, finished — finished |
data[].startDate |
string | Start date, ISO 8601 |
data[].endDate |
string | End date, ISO 8601 |
data[].createdAt |
string | When the campaign was created, ISO 8601 |
meta.nextCursor |
object | null | The next-page cursor. null — no more records |
meta.nextCursor.id |
number | The value for the afterCursorId parameter of the next request |
Response example
{
"success": true,
"data": [
{
"id": 2,
"title": "Q4 performance review",
"status": "created",
"startDate": "2026-10-01T09:00:00+00:00",
"endDate": "2026-12-15T09:00:00+00:00",
"createdAt": "2026-09-20T11:14:02+00:00"
},
{
"id": 1,
"title": "Q3 performance review",
"status": "finished",
"startDate": "2026-06-01T09:00:00+00:00",
"endDate": "2026-08-31T09:00:00+00:00",
"createdAt": "2026-05-25T08:40:11+00:00"
}
],
"meta": { "nextCursor": { "id": 1 } }
}
Error response example
400 — a parameter failed the check:
{
"success": false,
"error": {
"code": "INVALID_PARAMS",
"message": "limit must be a positive integer"
}
}
Errors
| HTTP | Code | Description |
|---|---|---|
| 400 | INVALID_PARAMS |
The value of campaignId or afterCursorId is not a positive integer, or limit is outside the 1–200 range |
| 401 | MISSING_API_KEY |
The X-Api-Key header was not sent |
| 401 | TOKEN_MISSING |
The key has no portal tokens. An OAuth application key requires the Authorization: Bearer header |
| 403 | SCOPE_DENIED |
The key has no performan scope |
| 404 | ROUTE_NOT_FOUND |
The Performance Review section is not enabled for the account. The answer is indistinguishable from the answer to any address that does not exist |
| 404 | ENTITY_NOT_FOUND |
The section is enabled, but the account has no Performance Review module: Bitrix24 answers that the performan.review.* method was not found |
| 409 | PERFORMAN_SCOPE_JUST_GRANTED |
A Cowork key was granted the performan scope by this very request. Repeat it and it goes through |
| 403 | BITRIX_ACCESS_DENIED |
Bitrix24 denied access. The permissions the key uses to reach the portal do not include performan |
| 422 | BITRIX_ERROR |
Bitrix24 rejected the request. The cause is in error.message, the machine code from Bitrix24 in error.b24Code |
| 429 | RATE_LIMITED |
The request rate on the Bitrix24 side was exceeded |
| 429 | QUEUE_OVERFLOW, QUEUE_TIMEOUT |
The portal request queue is full or the request did not get through the queue in time. The Retry-After header suggests the delay |
| 503 | BITRIX_TIMEOUT |
Bitrix24 accepted the request but did not answer in time. A read is safe to retry |
| 502 | BITRIX_UNAVAILABLE |
Bitrix24 is unavailable |
The full list of common API errors — Errors.
Known specifics
The listing is limited to the key owner's participation. The method returns the campaigns the employee is a member of, not every campaign on the account. An empty data array means this employee has no campaigns. An account administrator gets the same slice.
A limit outside the 1–200 range is refused. The answer is 400 INVALID_PARAMS and the request never reaches Bitrix24; ask for a page of 200 records with an explicit limit=200.
The method returns no total campaign count. To learn the number of records, walk every page by cursor.