Інструкція для розробників · REST і MCP
Синхронізуйте базу знань
Пишіть і далі у своїй звичній системі, а зміни надсилайте в Sonny. У цьому прикладі ми створимо категорію Billing, синхронізуємо статтю як чернетку, а потім опублікуємо її для аудиторії верифікованих клієнтів.
1. Виберіть канал і створіть ключ
- Відкрийте Канали → ваш канал. Скопіюйте ID, що йде після /app/sources/ в URL його панелі керування. В API цей ID каналу називається sourceId; він відрізняється від siteId віджета та публічного slug довідкового центру.
- У розділі Налаштування → Для розробників → API-ключі → Створити ключ надайте права kb:read і kb:write. Обмежте доступ до каналів лише тим каналом, який збираєтеся синхронізувати. Ключ показується лише один раз — збережіть його в менеджері секретів свого сервера.
- Задайте наведені нижче змінні в середовищі свого бекенду. У прикладах використано curl; замініть ID, написані великими літерами, на значення, які повертає Sonny. Перш ніж синхронізувати робочий довідковий центр, запустіть їх на тестовому каналі.
# Load SONNY_API_KEY from your server's secret manager first.
# SOURCE_ID is the ID in the channel dashboard URL: /app/sources/SOURCE_ID
export SOURCE_ID="YOUR_SOURCE_ID"
export BASE="https://www.usesonny.com/api/v1/sources/$SOURCE_ID"Необов’язковий пошук каналів: GET /api/v1/sources і MCP-інструмент list_sources повертають доступні канали та потребують права conversations:read. Якщо ID каналу у вас уже є, це право не потрібне. Підключення домену, як і раніше, виконується в панелі керування.
Повне налаштування API-ключа2. Створіть або оновіть категорію
Використовуйте в URL стабільний ID зі своєї системи. Повторне надсилання того самого зовнішнього ID оновлює наявну категорію, а не створює дублікат. Перше створення автоматично ініціалізує довідковий центр цього каналу.
curl --fail-with-body -X PUT "$BASE/categories/by-external-id/billing" \
-H "Authorization: Bearer $SONNY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Billing","position":0}'Очікуйте 201 у разі створення або 200 у разі оновлення, а саму категорію — в data. Збережіть data.id, якщо вам потрібен внутрішній ID категорії в Sonny. Кодуйте зовнішні ID для URL (URL-encode) і не змінюйте їх, навіть коли змінюються назви.
3. Синхронізуйте статтю як чернетку
curl --fail-with-body -X PUT "$BASE/articles/by-external-id/billing-guide" \
-H "Authorization: Bearer $SONNY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"title":"Manage billing","body":"## Find your invoices\n\nOpen **Settings → Billing** in your account.","bodyFormat":"markdown","categoryExternalId":"billing","status":"draft"}'Відповідь містить data.id і очищений HTML у data.body. Відкрийте статтю в розділі Канали → ваш канал → Довідковий центр, щоб перевірити форматування. Markdown перетворюється на HTML; також приймається сирий HTML із bodyFormat: "html" (за замовчуванням). Назва статті не залежить від заголовків у її тексті.
Щоб указати категорію з кроку 2, використовуйте categoryExternalId або categoryId (її ID у Sonny). Передавайте лише одне з двох. Щоб прибрати статтю з категорії, задайте будь-якому з них значення null. Кожен upsert потребує title і body; для часткових змін доступний PATCH. Якщо status не вказано, нові статті створюються як чернетки.
4. Налаштуйте доступ і опублікуйте
Для цього прикладу з приватним центром спершу підключіть вхід для верифікованих клієнтів. Створіть аудиторію та збережіть повернений data.id:
curl --fail-with-body -X POST "$BASE/audiences" \
-H "Authorization: Bearer $SONNY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Pro customers","rules":{"match":"all","conditions":[{"trait":"plan","op":"in","value":["pro","business"]}]}}'Замініть AUDIENCE_ID, ARTICLE_ID і URL входу нижче. Перший запит вмикає довідковий центр і відкриває його лише для клієнтів Pro. Другий публікує статтю. Процес входу у вашому застосунку має передавати довідковому центру підписаний JWT клієнта; одне лише налаштування signInUrl нікого не авторизує.
curl --fail-with-body -X PATCH "$BASE/help-center" \
-H "Authorization: Bearer $SONNY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"enabled":true,"title":"Acme Help Center","audience":"verified","audienceId":"AUDIENCE_ID","signInUrl":"https://app.example.com/login"}'
# Replace ARTICLE_ID and AUDIENCE_ID with the returned data.id values.
curl --fail-with-body -X PATCH "$BASE/articles/ARTICLE_ID" \
-H "Authorization: Bearer $SONNY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"audienceId":"AUDIENCE_ID","status":"published"}'Перевірте вигляд для читача, який увійшов, і для браузера без входу за URL, який повертає GET /help-center. API-ключі та MCP діють від імені співробітників і можуть читати вміст у межах своїх прав; їхня успішна відповідь не доводить, що клієнт бачить статтю.
Для публічного центру задайте audience: "everyone" і audienceId: null для центру та статті, а також перевірте доступ до категорії. Щоб прибрати лише іменовану групу, надішліть audienceId: null; доступ лише для верифікованих клієнтів залишиться, доки ви явно не зміните audience. Якщо audienceId не передано, попереднє призначення зберігається. Читач має відповідати всім обмеженням довідкового центру, категорії та статті.
Іменовані правила використовують match: "all" або "any", до 10 умов і строго типізовані значення. Оператори: eq, neq, in, not_in, exists, not_exists, gt, gte, lt, lte. Числові порівняння приймають числа; in/not_in приймають масиви з 1–100 скалярних значень; для exists/not_exists value не передається. Якщо атрибута немає, порівняння не виконується. Докладніше про поведінку правил, успадкування та проблеми з доступом.
5. Підтримуйте синхронізацію в актуальному стані
Повторні записи без дублювання вмісту
Повторюйте PUT із тим самим зовнішнім ID щоразу, коли змінюється джерело. Зовнішні ID унікальні в межах довідкового центру. Поля, не передані під час оновлення, зберігають поточні значення. Не передавайте status у наступних upsert-запитах, щоб зберегти стан публікації; явне надсилання draft знімає опубліковану статтю з публікації. publishedAt встановлюється під час першої публікації й більше не змінюється. Це поле лише для читання, тож імпортувати історичні дати публікації не можна. Незмінений вміст і зміни лише метаданих не запускають зайвої повторної індексації.
Читання змін і аналітики
curl --fail-with-body --get "$BASE/articles" \
-H "Authorization: Bearer $SONNY_API_KEY" \
--data-urlencode "page=1" --data-urlencode "limit=100" \
--data-urlencode "status=published" \
--data-urlencode "updatedSince=2026-09-01T00:00:00Z"
# Get the full sanitized HTML and read-only analytics for one article.
curl --fail-with-body "$BASE/articles/ARTICLE_ID" \
-H "Authorization: Bearer $SONNY_API_KEY"Списки статей і категорій повертають data, а також pagination: page, limit, total. Сторінки нумеруються з 1; limit за замовчуванням 50, максимум — 100. Зберігайте ті самі фільтри й запитуйте сторінки, доки page × limit не досягне total. Обидва списки приймають externalId і updatedSince; список статей також приймає categoryId і status (draft або published). Для updatedSince використовуйте мітку часу ISO з часовим поясом; до результату потрапляють і записи, оновлені саме в цей момент.
Щоб отримати повний body, viewCount, helpfulYes і helpfulNo, запитуйте деталі кожної статті окремо. Ця аналітика доступна лише для читання. updatedSince показує наявні записи, але не повідомляє про видалення. Відстежуйте видалення у своїй системі та явно видаляйте відповідний запис у Sonny, коли це потрібно.
Завантаження зображення
curl --fail-with-body -X POST "$BASE/media" \
-H "Authorization: Bearer $SONNY_API_KEY" \
-F "file=@billing.png;type=image/png"Використайте повернений data.url у синтаксисі зображення Markdown або в HTML-елементі img, а потім синхронізуйте текст статті. Можна завантажувати JPEG, PNG, GIF і WebP розміром до 25 МБ; довідковий центр має бути ініціалізований. Завантажені URL публічні: обмеження аудиторії статті не захищає URL зображення. У MCP замість multipart form data використовується upload_kb_media із sourceId, fileName, contentType і dataBase64 файлу.
Упорядкування статей і категорій
curl --fail-with-body -X PUT "$BASE/articles/reorder" \
-H "Authorization: Bearer $SONNY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"ids":["ARTICLE_ID_1","ARTICLE_ID_2"]}'Спершу отримайте всі сторінки без фільтрів за статусом, категорією чи датою, разом із чернетками. Замініть зразкові ID на ID усіх поточних статей — кожен рівно один раз, у потрібному порядку. Для повного списку категорій використовуйте /categories/reorder. Успішне впорядкування повертає 204 без тіла відповіді. Якщо список змінився, містить чужі чи повторювані ID або в ньому бракує якихось ID, оновіть його, перш ніж повторити спробу. Також можна задати невід’ємне значення position в окремих записах.
Той самий процес через MCP
- Підключіть свій MCP-клієнт і виберіть потрібний робочий простір. Переконайтеся, що він має права kb:read і kb:write та доступ до вашого каналу.
- Використовуйте ID каналу з панелі керування або викличте list_sources, якщо ваші облікові дані також мають право conversations:read. Ніколи не підставляйте замість нього siteId віджета.
- Виконайте перші п’ять прикладів нижче по черзі. Замініть SOURCE_ID на ID свого каналу, а ARTICLE_ID/AUDIENCE_ID — на data.id з результату відповідного попереднього кроку. Перед публікацією замініть URL входу та підключіть вхід для клієнтів.
- Щоб переглянути зміни, використовуйте list_kb_articles. Запускайте впорядкування лише після того, як зберете повний список без фільтрів, разом із чернетками. Після успішних записів оновлюйте свої списки.
Кожен приклад показує назву інструмента та його аргументи. Поля upsert передаються безпосередньо в arguments; інструменти оновлення передають змінені поля всередині updates. Це вхідні дані для виклику інструмента, а не HTTP-запит до MCP-ендпоінта.
1. upsert_kb_category
{
"name": "upsert_kb_category",
"arguments": {
"sourceId": "SOURCE_ID",
"externalId": "billing",
"name": "Billing",
"position": 0
}
}2. upsert_kb_article
{
"name": "upsert_kb_article",
"arguments": {
"sourceId": "SOURCE_ID",
"externalId": "billing-guide",
"title": "Manage billing",
"body": "## Find your invoices\n\nOpen **Settings → Billing** in your account.",
"bodyFormat": "markdown",
"categoryExternalId": "billing",
"status": "draft"
}
}3. create_kb_audience
{
"name": "create_kb_audience",
"arguments": {
"sourceId": "SOURCE_ID",
"name": "Pro customers",
"rules": {
"match": "all",
"conditions": [
{
"trait": "plan",
"op": "in",
"value": [
"pro",
"business"
]
}
]
}
}
}4. update_help_center
{
"name": "update_help_center",
"arguments": {
"sourceId": "SOURCE_ID",
"updates": {
"enabled": true,
"title": "Acme Help Center",
"audience": "verified",
"audienceId": "AUDIENCE_ID",
"signInUrl": "https://app.example.com/login"
}
}
}5. update_kb_article
{
"name": "update_kb_article",
"arguments": {
"sourceId": "SOURCE_ID",
"articleId": "ARTICLE_ID",
"updates": {
"audience": "verified",
"audienceId": "AUDIENCE_ID",
"status": "published"
}
}
}6. list_kb_articles
{
"name": "list_kb_articles",
"arguments": {
"sourceId": "SOURCE_ID",
"page": 1,
"limit": 100,
"updatedSince": "2026-09-01T00:00:00Z"
}
}7. reorder_kb_articles
{
"name": "reorder_kb_articles",
"arguments": {
"sourceId": "SOURCE_ID",
"ids": [
"ARTICLE_ID_1",
"ARTICLE_ID_2"
]
}
}8. update_kb_audience
{
"name": "update_kb_audience",
"arguments": {
"sourceId": "SOURCE_ID",
"audienceId": "AUDIENCE_ID",
"updates": {
"name": "Paid customers"
}
}
}Пов’язані операції
Шляхи REST нижче вказано відносно BASE. Усі поля та схеми відповідей описано в довіднику API.
| Завдання | REST | MCP |
|---|---|---|
| Список / отримання статей | GET /articles · GET /articles/{articleId} | list_kb_articles · get_kb_article |
| Список / отримання категорій | GET /categories · GET /categories/{categoryId} | list_kb_categories · get_kb_category |
| Створення без зовнішнього ID | POST /articles · POST /categories | create_kb_article · create_kb_category |
| Редагування наявного вмісту | PATCH /articles/{articleId} · PATCH /categories/{categoryId} | update_kb_article · update_kb_category |
| Порядок категорій | PUT /categories/reorder | reorder_kb_categories |
| Читання / зміна налаштувань довідкового центру | GET /help-center · PATCH /help-center | get_help_center · update_help_center |
| Список / зміна аудиторій | GET /audiences · PATCH /audiences/{audienceId} | list_kb_audiences · update_kb_audience |
| Видалення | DELETE /articles/{articleId} · /categories/{categoryId} · /audiences/{audienceId} | delete_kb_article · delete_kb_category · delete_kb_audience |
Видалення статті безповоротне. Видалення категорії залишає її статті без категорії та знімає успадковане від неї обмеження. Видалення аудиторії прибирає її правила атрибутів, але пов’язаний вміст залишається доступним лише верифікованим клієнтам. Перед видаленням перевірте, на чий доступ це вплине; щоб зняти статтю з публікації, але зберегти її, переведіть її в чернетки.
Усунення проблем із синхронізацією
- 400 · Некоректний запит
- Перевірте обов’язкові title/body або name, точні назви полів, допустимі типи правил і повний список ID для впорядкування. Надсилайте categoryId або categoryExternalId, але не обидва.
- 401 · Не авторизовано
- Передайте дійсний ключ Bearer. Перевірте, чи не минув термін його дії та чи його не відкликано.
- 403 · Доступ заборонено
- Перевірте права ключа, дозволи його власника та стан оплати робочого простору. Якщо інструменти MCP-клієнта доступні лише для читання, перепідключіть його з потрібним доступом.
- 404 · Не знайдено
- Переконайтеся, що канал належить до вибраного робочого простору й дозволений для цих облікових даних. Новий довідковий центр ініціалізується, коли ви вперше створюєте вміст; запити на читання його не створюють.
- 409 · Конфлікт
- Повторно отримайте поточний вміст і усуньте конфлікт ID або застарілий порядок, перш ніж повторити спробу.
- 413 · Завеликий розмір
- Зменште зображення до розміру менше 25 МБ.
- 429 · Перевищено ліміт запитів
- Перш ніж повторити спробу, зачекайте час, указаний у Retry-After. Щоб регулювати частоту запитів, використовуйте RateLimit-Limit, RateLimit-Remaining і RateLimit-Reset.
Пов’язані посібники
- Довідковий центр
Публікуйте відповіді, впорядковуйте категорії, налаштовуйте доступ для читачів і підтримуйте довідковий центр актуальним.
- Аудиторії довідкового центру
Створюйте групи клієнтів, робіть довідковий центр приватним і перевіряйте, хто може читати кожну відповідь.
- Публічний APIBeta
Сортуйте й синхронізуйте розмови, діліться контекстом клієнтів, читайте звіти й надсилайте файли за допомогою API-ключів з обмеженими правами.
- Sonny MCPBeta
Підключайте AI-асистентів до роботи з вхідними, пам’яті про клієнтів, звітів і файлів через OAuth або ключі з обмеженими правами.