#CRM Timeline
12 REST endpoints for logging actions in the timeline of CRM entities: creating log entries, notes on them, pinning, binding to multiple entities at once. Handy for AI agents, background integrations, and automation that need to leave a structured trail in a deal or contact card.
Scope: crm | Base URL: https://vibecode.bitrix24.tech/v1 | Authorization: X-Api-Key
Quick start | An AI agent logs its actions (full example) | Error codes | Endpoint reference
#Documentation sections
- Log entries — create, view, delete log entries
- Notes — a note-comment on a log entry
- Pins — pin or unpin an entry at the top of the timeline
- Bindings — link one entry to multiple CRM entities
#When to use
- Record an AI agent's action: analyzed the client, prepared a quote, sent a notification.
- Capture an event from an external system: payment succeeded, order assembled, document signed.
- Build an audit trail of an integration: what data it processed, what it based its decision on.
- Pin a key deal event at the top of the timeline so the manager sees the context right away.
For user text comments (not system events) use `/v1/timelines` — a separate API over crm.timeline.comment.*.
#Quick start
#1. Create an entry in a deal's timeline
curl -X POST https://vibecode.bitrix24.tech/v1/timeline-logs \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"entityTypeId": 2,
"entityId": 100,
"title": "AI agent processed the request",
"text": "Client data analyzed. Recommendation: offer the Enterprise plan."
}'
Response:
{
"success": true,
"data": {
"id": 5012,
"created": "2026-04-27T10:00:00+03:00",
"authorId": 1,
"title": "AI agent processed the request",
"text": "Client data analyzed. Recommendation: offer the Enterprise plan.",
"iconCode": ""
}
}
#2. Pin the entry at the top of the timeline
curl -X POST https://vibecode.bitrix24.tech/v1/timeline-logs/5012/pin \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "entityTypeId": 2, "entityId": 100 }'
#3. Attach an internal note
curl -X POST https://vibecode.bitrix24.tech/v1/timeline-logs/5012/note \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "entityTypeId": 2, "entityId": 100, "text": "The client usually responds within 2 days." }'
#Full example: an AI agent logs its actions
Scenario: an AI agent analyzes a deal, leaves a log entry with the result, binds it to a contact and a company, attaches a note for the manager, pins it in the timeline.
const VIBE_KEY = process.env.VIBE_KEY
const BASE = 'https://vibecode.bitrix24.tech/v1'
async function api(method, path, body = null) {
const opts = { method, headers: { 'X-Api-Key': VIBE_KEY } }
if (body) {
opts.headers['Content-Type'] = 'application/json'
opts.body = JSON.stringify(body)
}
const res = await fetch(`${BASE}${path}`, opts)
return res.json()
}
const dealId = 100
const contactId = 50
const companyId = 10
// 1. Record that work has started
const start = await api('POST', '/timeline-logs', {
entityTypeId: 2,
entityId: dealId,
title: 'AI agent started processing',
text: 'Client data analysis, credit-limit check, quote preparation.',
})
const startId = start.data.id
// 2. Bind the entry to the contact and the company — managers of both will see
// the same event in their timelines
await api('POST', `/timeline-logs/${startId}/bind`, { entityTypeId: 3, entityId: contactId })
await api('POST', `/timeline-logs/${startId}/bind`, { entityTypeId: 4, entityId: companyId })
// ... the AI agent does its work ...
// 3. Record the result as a separate log entry
const result = await api('POST', '/timeline-logs', {
entityTypeId: 2,
entityId: dealId,
title: 'AI agent finished processing',
text: [
'[b]Analysis results:[/b]',
'- Credit limit: OK (500,000 RUB)',
'- Recommended plan: Enterprise',
'- Discount: 10% (returning client)',
'- Quote generated and sent by email',
].join('\n'),
})
const resultId = result.data.id
// 4. Pin the final entry at the top of the timeline
await api('POST', `/timeline-logs/${resultId}/pin`, { entityTypeId: 2, entityId: dealId })
// 5. Leave an internal note for the manager
await api('POST', `/timeline-logs/${resultId}/note`, {
entityTypeId: 2,
entityId: dealId,
text: 'The client usually responds within 2 days. Remind the manager if there is no reply.',
})
console.log('AI agent finished, all actions logged')
#Which key to use
CRUD operations work with any key type — personal (vibe_api_*) or an OAuth app (vibe_app_*). However, DELETE /v1/timeline-logs/:id imposes a restriction: Bitrix24 allows a log entry to be deleted only by the same app that created it.
- OAuth app (
vibe_app_*+Authorization: Bearer ...) — stableclient_id, you can delete your own entries. If you plan to delete created entries via the API, use this key type. - Personal key (
vibe_api_*) — VibeCode rotates tokens between calls, so to Bitrix24 each call looks like a separate app.DELETEalways returns403 CROSS_APP_DELETE_FORBIDDEN, including for freshly created entries.
If the app that created the entry is unavailable, deleting it is impossible by design. Bitrix24 does not provide a UI delete button for a log entry in the entity card. Keep this in mind when designing audit scenarios.
More details — Delete an entry.
#Parent entity types
The entityTypeId parameter (the CRM entity's numeric code) specifies whose timeline the entry is created in:
entityTypeId |
Entity | Where to find the ID |
|---|---|---|
| 1 | Lead | `GET /v1/leads` |
| 2 | Deal | `GET /v1/deals` |
| 3 | Contact | `GET /v1/contacts` |
| 4 | Company | `GET /v1/companies` |
| 7 | Quote | `GET /v1/quotes` |
| 14 | Order | `GET /v1/orders` |
| 31 | Invoice | `GET /v1/invoices` |
| ≥ 128 | Smart process | `GET /v1/items/:entityTypeId`; list of processes — `GET /v1/smart-processes` |
In bindings (bind/unbind) you can use either the numeric entityTypeId or the string entityType directly ("deal", "contact", "dynamic_174", etc.) — see Bind an entry.
#Error codes
#Timeline errors
| HTTP | Code | Description |
|---|---|---|
| 400 | INVALID_PARAMS |
Required parameters are missing or invalid (entityTypeId, entityId, title, text, itemType, etc. — the specific field is in message) |
| 400 | INVALID_ENTITY_TYPE_ID |
In bindings.bind/unbind an entityTypeId was passed with no mapping to ENTITY_TYPE (< 128 and not in the table above) |
| 403 | CROSS_APP_DELETE_FORBIDDEN |
Attempt to delete a log entry via a key other than the one it was created with |
| 404 | ENTITY_NOT_FOUND |
A log entry with the given id does not exist — Bitrix24 returned a NOT_FOUND error |
| 404 | NOT_FOUND |
Only GET /v1/timeline-logs/:id: Bitrix24 returned a successful response but the entry object is empty |
| 404 | NOTE_NOT_FOUND |
The specified timeline item has no attached note |
#System errors
| HTTP | Code | Description |
|---|---|---|
| 401 | AUTH_REQUIRED |
Missing X-Api-Key |
| 401 | INVALID_API_KEY |
Invalid API key |
| 401 | TOKEN_MISSING |
The API key has no configured tokens (a vibe_app_* key requires Authorization: Bearer ...) |
| 403 | SCOPE_DENIED |
The API key lacks the crm scope |
| 422 | BITRIX_ERROR |
Bitrix24 returned an error (text in message) |
| 429 | RATE_LIMITED |
Request rate limit exceeded. Wait 1–2 seconds and retry. Several calls can be combined into `POST /v1/batch` |
| 502 | ERROR_LOOP_DETECTED |
The circuit breaker triggered: many identical errors from B24 in a row. Wait ~60 seconds |
| 502 | BITRIX_UNAVAILABLE |
The Bitrix24 portal is unavailable |
| 504 | QUEUE_TIMEOUT |
The request to B24 did not complete within the portal's queue. Narrow the filter or retry later |
| 500 | INTERNAL_ERROR |
Internal server error |
Full list of common API codes — Errors.
#Endpoint reference
All 12 endpoints:
| Method | Path | Bitrix24 method | Description |
|---|---|---|---|
| POST | /v1/timeline-logs | crm.timeline.logmessage.add |
Create a log entry |
| GET | /v1/timeline-logs | crm.timeline.logmessage.list |
List log entries |
| GET | /v1/timeline-logs/:id | crm.timeline.logmessage.get |
Get a single entry |
| DELETE | /v1/timeline-logs/:id | crm.timeline.logmessage.delete |
Delete an entry |
| POST | /v1/timeline-logs/:id/note | crm.timeline.note.save |
Save or update a note |
| GET | /v1/timeline-logs/:id/note | crm.timeline.note.get |
Get a note |
| DELETE | /v1/timeline-logs/:id/note | crm.timeline.note.delete |
Delete a note |
| POST | /v1/timeline-logs/:id/pin | crm.timeline.item.pin |
Pin an entry |
| POST | /v1/timeline-logs/:id/unpin | crm.timeline.item.unpin |
Unpin an entry |
| POST | /v1/timeline-logs/:id/bind | crm.timeline.bindings.bind |
Bind to another entity |
| POST | /v1/timeline-logs/:id/unbind | crm.timeline.bindings.unbind |
Unbind from an entity |
| GET | /v1/timeline-logs/:id/bindings | crm.timeline.bindings.list |
List all bindings of an entry |
#See also
- Timeline comments — user text comments (a separate API over
crm.timeline.comment.*) - Deals, Leads, Contacts, Companies — typical parent entities
- Smart processes — for timeline entries on custom CRM types
- Batch — bulk operations
- Limits and optimization — rate limits