Library and comments API: website and CRM integration

SENSEVER

The official Sensever channel: guides and API documentation for Chat, Requests, Flow, Studio, bots and messaging channels.

10 min de lecture

Library and comments API: website and CRM integration

This guide is for a website or CRM that shows Sensever content and embeds discussions. The library handles reading permitted content, delegation handles reading on behalf of a signed-in user, and a comments session handles access to a specific discussion. These mechanisms use different keys and don't substitute for one another.

A knowledge base on your website

Content is created and edited in Sensever Studio and published only to a channel: the library includes content published in that channel. Your server gets it through the API and shows it on your website. Categories handle navigation; access is determined by the publication's policy, not by its position in the tree.

Tree and content

GET /api/v1/library/tree?channel=17
GET /api/v1/library/units?channel=17&limit=50
GET /api/v1/library/units/{message_ulid}
GET /api/v1/library/units/{message_ulid}/outline
GET /api/v1/library/search?channel=17&q=widget
GET /api/v1/library/fragments?ids={fragment_id}

tree returns categories, units and next_cursor. units returns items and next_cursor. While next_cursor isn't null, pass it as cursor in the next request with the same channel and q. Merge categories by id. Each page's tree contains only the categories of its available content and their parents. Empty and hidden branches aren't revealed.

A single content item is returned in data: the publication id, type, title, source with ref and url, channel_id, revision, audience, anchors and body. body is the original structured document, not ready-made HTML. Render only supported nodes and safe links. For a regular article, this is Tiptap JSON; galleries, recipes and videos have their own structures. Resolve relative media links against https://sensever.com. File permissions are checked separately; the library doesn't make private attachments public.

Search and freshness

Search matches the text and headings of available content; matches contains the fragments found. outline doesn't include body. A fragment ID is tied to a revision: after a change, an old anchor may return 404. Fetch the current content again. When permissions change, access is checked again, including for fragments.

Public content is available without a key. With a key, only the channels selected when it was issued are visible. A library key alone doesn't open private content: that requires a verified reader. Don't put private library responses into a shared public cache.

Library API: tree, articles, search and paragraphs

The library API lets you show a channel's content on your own website and read it in parts for an assistant. Public reading is allowed without a key; unavailable content and branches aren't returned. A key needs library:read or library:search and a selected project source.

Read routes

GET /api/v1/library/tree?channel=ID&type=article returns categories, units, next_cursor and available_types. Types: message, article, reel, video, gallery, recipe. The category_id parameter selects a branch together with its descendants. GET /api/v1/library/units?channel=ID&type=article&limit=20 returns items and next_cursor; limit is 1 to 100. GET /api/v1/library/units/ULID returns data with body. GET /api/v1/library/search?channel=ID&type=article&q=widget searches available titles and text; q is up to 200 characters. Without type, the API reads all types for the integration.

Headings and selected paragraphs

GET /api/v1/library/units/ULID/outline returns metadata and anchors without body. GET /api/v1/library/fragments?ids=ANCHOR1,ANCHOR2 returns items; no more than 30 IDs. Take anchors from a fresh outline rather than constructing them: after the content changes, an anchor may become invalid. Permissions are checked again on every read.

IDs and pagination

A library unit ID is the ULID from the response, while the article's own ID is a UUID. The document UUID is used in /api/v1/content/article/UUID; the ULID of the source message is used in library/units and channel-content-messages. For a link to readers, use source.url — an address like https://sensever.ru/<channel>/<content>; don't build the address from the UUID: there's no numbered page /content/<type>/<id> (404). File addresses /content/<type>/<id>/media/<uuid> in body haven't changed. Pass next_cursor unchanged as cursor to the same route, channel, type, category and search; don't try to decode it. Merge categories by id across pages.

Format and rendering

An article's body is a structured document, not ready-made HTML. Render the permitted node types and escape user strings. Media links have their own access checks; knowing a content ID doesn't replace permission to access a file.

The message type in the library means a regular channel message: its text is stored right in the message and returned as document paragraphs. The source has ref m.<thread_id>.<seq>. Reels and editorial content keep their own type. In all cases, access is checked against the source message.

A channel has no separate knowledge base tab. Tabs appear automatically for available types: articles, reels, videos, galleries and others. Each tab has its own category tree up to four levels deep. Readers see only branches with available content; an administrator can manage empty categories. The website and the assistant read this same structure through the API, without copies.

Private knowledge base and reader access

The integration server acts as the executor, and the signed-in user acts as the reader. Content is available only when both the reader and the key owner have access. You can't pass an arbitrary user_id and get that user's rights.

Temporary delegation

A signed-in Sensever user calls POST /api/v1/delegations with their own user Bearer token. Body: key_id — the key's UUID, channel — the ID of the selected channel. The response data contains a temporary token. subject_id is forbidden: the server determines the user from the active session.

POST /api/v1/delegations
{"key_id":"KEY_UUID","channel":"17"}

GET /api/v1/library/tree?channel=17
Authorization: Bearer ak1.PROJECT_SECRET
X-Sensever-Delegation: dg1.TEMPORARY_TOKEN

A delegation lasts 120 seconds and is bound to the key, the channel, the user and their session. The user signing out or the key being revoked ends access. It allows reading the library, but not creating articles, sending messages or changing tasks on the reader's behalf.

This is the contract for signed-in Sensever users. CRM guest identity and automatic linking with a future AI bot aren't connected here yet. The existing comments widget authorization remains a separate mechanism. A regular public website doesn't need delegation.

API: delegating access to a private knowledge base

An API key alone isn't enough to read a private library. A short-lived delegation token binds the key, the signed-in reader, their session and a specific channel. The result is limited by the rights of both the key and the reader. A public website with a public knowledge base doesn't need delegation.

Granting permission

POST /api/v1/delegations is called by the signed-in user's personal session with key_id and channel. An arbitrary subject_id isn't accepted. The issued dg1 lasts 120 seconds; pass it in X-Sensever-Delegation together with Authorization: Bearer PROJECT_API_KEY when reading /api/v1/library/*.

What ends access

A different key, a different channel, an expired token, the user signing out or the original session being revoked won't work. A delegation allows only reading the library and doesn't turn the key into a way to change data on the reader's behalf.

External CRM guests

This delegation is designed for a signed-in Sensever session. External CRM users in private comments use a different contract: /api/comments/private/session with the site's server key. Don't mix up dg1, ak1 and cm1.

Comments API: installation and public discussions

Comments are added with a separate script, /comments/loader.js, at the place on the page where you want the block. data-site is the site's public key, data-entity-type and data-entity-id identify a persistent entity. One project can be used on many pages by passing different IDs; each one gets its own thread.

Installation code

In the project settings, turn on "Comments on your site" and copy the current code. Example: <script src="https://chat.sensever.ru/comments/loader.js" data-site="YOUR_PUBLIC_WIDGET_KEY" data-entity-type="article" data-entity-id="123" data-lang="en" async></script>. Place it below the content, not just in the shared header.

HTTP contract

GET /api/comments/messages accepts key, origin, context_type, context_external_id and an optional before. POST /api/comments/guest issues a guest token for a specific discussion. POST /api/comments/messages uses Bearer cm1, the same entity fields, text, client_message_id and an optional reply_to_seq. The site's server key isn't meant for sending user comments from the browser.

Identity and language

The entity ID and type are case-sensitive and don't change along with the article title. data-lang selects the widget's interface language but doesn't translate visitors' messages. The origin must be allowed in the site settings. Adding the script doesn't turn on AI by itself.

Reading and joining a discussion

Viewing a page and getting a widget session don't create a discussion or make the reader follow it. Until the first message is sent, thread_id in the response may be null. Existing comments can be read with a valid session without the discussion appearing in personal chats. Participation starts after a comment is sent. When a file is sent, a technical thread is reserved for the upload, but the reader becomes a member only after sending a message.

Private comments API: CRM server and session token

Private comments get access through POST /api/comments/private/session. Your site's server makes this request with Bearer s1 after checking its own user session and the right to the content. Only a limited cm1 is returned to the browser. The ak1 key doesn't replace this contract.

Server request

JSON: {"origin":"https://crm.example","context_type":"task","context_external_id":"42","user_id":"local-user-7","name":"Anna","can_write":true,"expires_in":300}. user_id is the persistent ID of a user in your CRM, not an arbitrary name entered by the visitor. expires_in is 60 to 900 seconds. The response contains token, expires_in, thread_id, visibility, can_write.

Connecting the widget

Set data-session-url to your own HTTPS endpoint. It checks the signed-in user and their access to this entity, calls the Sensever server API and returns the permission JSON with Cache-Control: no-store. Don't simply forward arbitrary user_id, can_write and material ID values from the browser without your own check.

Revocation and the secret

To revoke access, use the same server contract with revoke:true and the same identifiers. The s1 key is generated in the site settings, shown once and stored only on the server. Rotating it disables the old key and previously issued tokens. Don't pass it in a script, query string or client code; a request with a browser Origin header is rejected.

API: discussion URL and title without spoofing

A discussion is identified by the site, context_type and context_external_id. The URL and title are mutable metadata, not the thread key. Only a trusted server should change the shared link and title: otherwise a copy of the widget could rename someone else's discussion.

Updating the source

For a public discussion, use /api/comments/context with the site's server key; for a private one, pass page_url and page_title to /api/comments/private/session. page_url must match an allowed HTTPS origin of the site. page_title is a string of up to 255 characters without control characters.

What goes into the HTML

data-page-url and data-page-title can describe the page, but they don't give a visitor the right to rewrite shared server metadata. Copying a public data-site to another domain must not grant private access or the right to rename.

Going back

A member sees the source of the discussion and can go to the content from the chat. Sensever addresses use in-app navigation; external websites open separately from the embedded conversation block.

Commentaires

Auteurs