[Intum Pomoc](https://intum.pl/pomoc.md) / [API](https://intum.pl/pomoc/baza-wiedzy/api.md)

# [Wpisy bazy wiedzy](https://intum.pl/pomoc/baza-wiedzy/api/wpisy.md)

Tworzenie, aktualizacja, usuwanie i pobieranie wpisów bazy wiedzy przez API.

**Autoryzacja:** `Authorization: Bearer TOKEN` — token musi mieć uprawnienie **kb**
**Content-Type:** `application/json`

## API Endpoints

| Metoda | Ścieżka | Opis |
|--------|---------|------|
| GET | `/kb/entries.json?knowledge_base_id=X` | Lista wpisów w bazie wiedzy |
| GET | `/kb/entries.json?knowledge_base_id=X&external_id=Y` | Wpis o danym identyfikatorze zewnętrznym (lista z 0 albo 1 elementem) |
| GET | `/kb/entries/:id.json` | Pojedynczy wpis |
| POST | `/kb/entries.json` | Utworzenie wpisu |
| PATCH | `/kb/entries/:id.json` | Aktualizacja wpisu |
| DELETE | `/kb/entries/:id.json` | Usunięcie wpisu |

## Pola entry

| Pole | Typ | Wymagane | Opis |
|------|-----|----------|------|
| `title` | string | tak | Tytuł wpisu |
| `content` | string | tak | Treść wpisu — domyślnie w **Markdown** (patrz sekcja "Format treści"). Opisuje temat z perspektywy użytkownika — do czego służy, jak używać, ważne informacje |
| `knowledge_base_id` | integer | tak | ID bazy wiedzy |
| `category_id` | integer | nie | ID kategorii |
| `status_id` | integer | nie | ID statusu wpisu |
| `private` | boolean | nie | Czy wpis jest prywatny (domyślnie `false`) |
| `tags` | array | nie | Tablica tagów `["tag1", "tag2"]` |
| `priority` | number | nie | Priorytet (domyślnie `0`) |
| `url` | string | nie | Slug URL — zostaw pusty, system wygeneruje automatycznie z prefiksem kategorii (np. `zadania/jak-dodac-zadanie`) |
| `html_title` | string | nie | Meta tytuł SEO |
| `html_description` | string | nie | Meta opis SEO |
| `publish_from` | string | nie | Data publikacji `"YYYY-MM-DD"` |
| `multilang_code` | string | nie | Kod grupy tłumaczeń |
| `external_id` | string | nie | Identyfikator wpisu w systemie zewnętrznym (import, synchronizacja). Unikalny w bazie wiedzy; pusty = brak. Kategorie (`/kb/categories.json`, pole `category[external_id]`) i bazy (`knowledge_base[external_id]`, unikalny na koncie) mają takie samo pole |
| `content_api` | string | nie | Dokumentacja techniczna API — endpointy, pola, przykłady requestów/odpowiedzi (Markdown). Oddzielona od `content` — `content` to opis dla użytkownika, `content_api` to dokumentacja dla programisty/agenta. Wartość `"true"` = opisem API jest sama treść wpisu (widok `.api` pokazuje `content`, bez kopiowania) |
| `connected_entry_ids` | array | nie | Tablica ID powiązanych wpisów `[123, 456]` — tworzy dwukierunkowe powiązanie między wpisami (sekcja "Powiązane" w widoku wpisu) |

## Format requestu

### POST — Utworzenie wpisu

```
POST /kb/entries.json
Authorization: Bearer TOKEN
Content-Type: application/json
```

```json
{
  "entry": {
    "title": "Tytuł wpisu",
    "content": "## Nagłówek\n\nTreść akapitu\n\n- Punkt 1\n- Punkt 2",
    "knowledge_base_id": 1,
    "category_id": 3
  }
}
```

### GET — Pobranie wpisu (przed edycją)

```
GET /kb/entries/:id.json
Authorization: Bearer TOKEN
```

Odpowiedź zawiera pełną treść wpisu (`title`, `content`, `category_id`, `tags` itd.) — użyj jej jako bazy do edycji.

### PATCH — Aktualizacja wpisu

```
PATCH /kb/entries/:id.json
```

Wysyłasz tylko pola, które chcesz zmienić — reszta pozostaje bez zmian.

```json
{
  "entry": {
    "title": "Zmieniony tytuł",
    "content": "## Nowa treść\n\nZaktualizowany artykuł."
  }
}
```

### Powiązanie wpisów (connected entries)

Wpisy można powiązać ze sobą — w widoku wpisu pojawi się sekcja "Powiązane". Powiązanie jest **dwukierunkowe** (wystarczy ustawić z jednej strony).

```json
{
  "entry": {
    "connected_entry_ids": [123, 456]
  }
}
```

**Uwaga:** `connected_entry_ids` zastępuje całą listę powiązań — podaj **wszystkie** ID powiązanych wpisów, nie tylko nowe. Pominięcie istniejącego ID usunie to powiązanie.

## Format odpowiedzi

### Sukces — POST (201 Created)

```json
{
  "id": 123,
  "title": "Tytuł wpisu",
  "content": "<p>Treść</p>",
  "url": "tytul-wpisu",
  "knowledge_base_id": 1,
  "category_id": 3,
  "private": false,
  "tags": [],
  "priority": "1.0",
  "created_at": "2026-03-05T09:18:22.485+01:00"
}
```

### Sukces — GET lista (200 OK)

```json
[
  {
    "id": 123,
    "title": "Tytuł wpisu",
    "content": "<p>Treść</p>",
    "url": "tytul-wpisu",
    "knowledge_base_id": 1,
    "category_id": 3
  }
]
```

### Błąd walidacji (422 Unprocessable Content)

```json
{
  "title": ["nie może być puste"]
}
```

Klucze to nazwy pól, wartości to tablice komunikatów błędów.

## Format treści (content)

Pole `content` obsługuje dwa formaty:

- **Markdown** (domyślnie) — system renderuje treść jako GitHub Markdown. Używaj `##` dla nagłówków, `**bold**`, `-` dla list, `` `code` `` dla kodu itd.
- **HTML** — jeśli wpis ma w `config` ustawione `"editor": "html"`, treść jest traktowana jako surowy HTML. Przez API nie da się ustawić `config`, więc domyślnie zawsze jest Markdown.

**Domyślnie pisz treść w Markdown** — jest czytelniejszy i nie wymaga dodatkowej konfiguracji.

### Przykład treści w Markdown

```json
{
  "entry": {
    "title": "Jak dodac zadanie",
    "knowledge_base_id": 1,
    "category_id": 3,
    "content": "## Tworzenie zadania\n\nAby dodac nowe zadanie:\n\n1. Przejdz do modulu **Zadania**\n2. Kliknij przycisk **+**\n3. Wypelnij formularz\n\n## Pola formularza\n\n- **Nazwa** - tytul zadania (wymagane)\n- **Opis** - szczegoly zadania\n- **Priorytet** - waznosc zadania"
  }
}
```

## Wskazówki

- **Pisz z polskimi znakami** — treść powinna zawierać prawidłowe polskie znaki diakrytyczne (ą, ć, ę, ł, ń, ó, ś, ź, ż). Używaj `--data-binary` zamiast `-d` w curl i dodaj `charset=utf-8` w Content-Type aby zapewnić poprawne kodowanie
- **Domyślnie pisz w Markdown** — system automatycznie renderuje Markdown jako HTML
- **Twórz wpisy sekwencyjnie** — jeden po drugim, czekając na odpowiedź 201 przed wysłaniem kolejnego
- **Każdy wpis** powinien mieć unikalny tytuł i sensowną treść
- **URL** jest generowany automatycznie z tytułu jeśli nie podany. **Zawsze używaj nazwy kategorii jako prefiksu URL**, np. `helpdesk/tagi-w-ticketach`, `organizacja/tagi`, `voip/call-center`, `crm/klienci`
- **Linki do innych wpisów** — w treści (`content`) używaj relatywnych URL-i: `../kategoria-url/post-url`, np. `[Tagi w ticketach](../helpdesk/tagi-w-ticketach)`
- **Linki do ekranów systemu** — pisz z markerem `app:` (jak w pomocy `/<modul>/help`): `[Organizacja → Ustawienia](app:/organize/settings)`. Przy renderowaniu wpisu marker zamienia się na adres z pola bazy wiedzy `app_link_host` (np. `https://app.intum.pl/organize/settings`), a gdy pole jest puste - na samą ścieżkę `/organize/settings`. Na domenie `app.` ścieżka przetrwa logowanie/rejestrację: niezalogowany czytelnik po zalogowaniu (albo założeniu konta) trafia na ten ekran na swoim koncie. Nie wpisuj gołego `/organize/settings` - w publicznej bazie na innej domenie taki link prowadzi donikąd. Linkuj do list, ustawień i formularzy dodawania, nigdy do konkretnego rekordu (`/crm/clients/123`)
- **Pomoc o systemie na bazie z ustawionym `app_link_host`** — zanim zaczniesz pisać wpisy pomocy, pobierz bazę (`GET /kb/knowledge_bases/:id.json`) i sprawdź pole `fields.app_link_host` (w JSON-ie leży w `fields`). Gdy jest ustawione, baza jest pomocą do systemu pod tym adresem: każde miejsce we wpisie, które każe coś kliknąć albo otworzyć w systemie („wejdź w Ustawienia", „na liście zadań kliknij..."), podlinkuj markerem `app:/ścieżka` do tego ekranu, np. `W [Organizacja → Ustawienia](app:/organize/settings) zaznacz...`. Pisz sam marker `app:/...`, nigdy pełnego adresu z `app_link_host` (host doklei się przy renderowaniu, a zmiana pola od razu poprawi wszystkie linki). Ścieżki bierz z faktycznych adresów ekranów (menu, pomoc `/<modul>/help`), nie zgaduj
- **Synchronizacja z zewnętrznym źródłem** — przy imporcie albo cyklicznej aktualizacji wpisów z innego systemu nadaj każdemu wpisowi `external_id` (np. `wiki/123`). Przy kolejnym przebiegu szukaj wpisu po `GET /kb/entries.json?knowledge_base_id=X&external_id=...` i aktualizuj go przez PATCH, zamiast szukać po tytule czy URL-u, które redaktor mógł zmienić. Prefiks `kb_inner:` jest zajęty przez publikację pomocy systemu, nie używaj go
- **Uzupełniaj `content_api`** — jeśli wiesz coś o API danego tematu (endpointy, parametry, formaty requestów/odpowiedzi), dodaj to w polu `content_api`. Dzięki temu wpis będzie miał zarówno dokumentację dla użytkownika (`content`), jak i dokumentację techniczną API (`content_api`) widoczną pod suffixem `.api`
- **Pobieranie treści w Markdown** — aby pobrać aktualną treść wpisu w formacie Markdown (np. przed edycją), dodaj `.md` do publicznego URL wpisu: `https://domena.pl/pomoc/helpdesk/ai-w-helpdesk.md`. Zwraca czysty Markdown bez HTML — przydatne gdy chcesz zobaczyć oryginalną treść lub użyć jej jako bazy do aktualizacji. `.md` na adresie kategorii zwraca treść jej wpisu głównego (wpis o adresie kategorii), listę pozostałych wpisów i podkategorie z ich wpisami - cały spis sekcji w jednym dokumencie

## Obrazki i załączniki we wpisie (np. screenshoty)

Obrazek wstawia się w trzech krokach: direct upload blobu, podpięcie do wpisu, odwołanie w treści.

### 1. Utwórz blob (direct upload)

```
POST /file/attachments/direct_uploads
Authorization: Bearer TOKEN
Content-Type: application/json
```

```json
{
  "blob": {
    "filename": "panel.png",
    "byte_size": 123456,
    "checksum": "BASE64_MD5_PLIKU",
    "content_type": "image/png"
  }
}
```

- `checksum` = MD5 pliku w base64 (`openssl dgst -md5 -binary plik.png | base64`),
  `byte_size` = rozmiar w bajtach (`stat -f%z plik.png`).
- Odpowiedź zawiera `signed_id` oraz `direct_upload.url` + `direct_upload.headers`.

### 2. Wgraj plik i podepnij do wpisu

```bash
curl -X PUT --data-binary @plik.png -H "NAGŁÓWKI_Z_direct_upload.headers" "URL_Z_direct_upload.url"
```

Potem `PATCH /kb/entries/:id.json` z `"entry": { "entry_attachments": ["SIGNED_ID"] }`.

### 3. Odwołaj się w treści — po FAKTYCZNEJ nazwie załącznika

System przy podpinaniu **prefiksuje nazwę pliku** (np. `panel.png` → `08dcaf2b6416-panel.png`).
Odwołanie `![...](panel.png)` w treści NIE zrenderuje się. Po PATCH z załącznikiem zrób
`GET /kb/entries/:id.json`, odczytaj faktyczną nazwę z `entry_attachments` i dopiero wtedy
wstaw do `content`:

```markdown
![Panel aplikacji](08dcaf2b6416-panel.png)
```

System sam podmieni ją na podpisany URL S3 przy renderowaniu. Kolejność bezpieczna:
najpierw PATCH z `entry_attachments`, potem GET po nazwę, na końcu PATCH treści z obrazkiem.

## Helplinki

Helplinki to kontekstowe podpowiedzi wyświetlane w interfejsie użytkownika jako małe ikonki "?" — po kliknięciu pokazują tooltip z treścią i linkiem do wpisu w bazie wiedzy.

### API Endpoints helplinków

| Metoda | Ścieżka | Opis |
|--------|---------|------|
| GET | `/kb/helplinks.json` | Lista helplinków |
| GET | `/kb/helplinks/:id.json` | Pojedynczy helplink |
| POST | `/kb/helplinks.json` | Utworzenie helplinku |
| PATCH | `/kb/helplinks/:id.json` | Aktualizacja helplinku |
| DELETE | `/kb/helplinks/:id.json` | Usunięcie helplinku |

### Pola helplinku

| Pole | Typ | Wymagane | Opis |
|------|-----|----------|------|
| `key` | string | tak | Unikalny klucz helplinku (np. `kb_entries`, `organize_task_form`) — identyfikuje miejsce w interfejsie |
| `knowledge_base_id` | integer | tak | ID bazy wiedzy, do której należy helplink |
| `entry_id` | integer | nie | ID wpisu KB, do którego prowadzi helplink (po kliknięciu otwiera ten wpis) |
| `content` | string | nie | Krótka treść tooltipa — **domyślnie w Markdown** (`##` nagłówki, `**bold**`, `*italic*`, `-` listy, `[text](url)` linki, `` `code` ``). HTML używaj **tylko na wyraźne życzenie użytkownika** (dozwolone tagi: `<p>`, `<br>`, `<strong>`, `<em>`, `<a>`, `<ul>`, `<ol>`, `<li>`, `<img>`). System wykrywa markdown automatycznie — żeby treść była zapisana jako markdown, musi mieć **min. 2 wskaźniki markdown** (np. `##` + `**bold**`); inaczej zostanie uznana za HTML |
| `section` | string | nie | Sekcja we wpisie — jeśli podana, link prowadzi do konkretnego nagłówka (np. `#tworzenie-zadania`) |
| `active` | boolean | nie | Czy helplink jest aktywny (domyślnie `false`) — nieaktywne helplinki nie wyświetlają się użytkownikom |

### Tworzenie helplinku

```
POST /kb/helplinks.json
Authorization: Bearer TOKEN
Content-Type: application/json
```

```json
{
  "helplink": {
    "key": "kb_entries",
    "knowledge_base_id": 1,
    "entry_id": 123,
    "content": "## Dodawanie wpisu\n\nKliknij **+** i wypełnij formularz — tytuł, kategorię i treść.",
    "active": true
  }
}
```

Przykład z HTML (tylko gdy user wyraźnie o to poprosi):

```json
{
  "helplink": {
    "key": "kb_entries",
    "content": "<p>Aby dodać nowy wpis, kliknij <strong>+</strong> i wypełnij formularz.</p>"
  }
}
```

### Jak to działa

1. W interfejsie użytkownika obok elementu pojawia się ikonka "?" (helplink)
2. Po kliknięciu wyświetla się popup z treścią `content` i linkiem do wpisu (`entry_id`)
3. Klucz `key` identyfikuje miejsce w interfejsie — każdy helplink ma unikalny klucz w ramach bazy wiedzy
4. Jeśli helplink z danym `key` nie istnieje, system automatycznie tworzy go jako nieaktywny — wystarczy go potem aktywować i uzupełnić

### Wskazówki

- **`content`** powinien być krótkim podsumowaniem (1-3 zdania) wyjaśniającym kontekst danego elementu interfejsu
- **Domyślnie pisz `content` w Markdown** — HTML stosuj tylko jeśli użytkownik wprost o to poprosi lub potrzebuje tagu, którego markdown nie ogarnia (np. `<br>`, `<img>`)
- **Pilnuj min. 2 wskaźników markdown** — system wykrywa format automatycznie z treści. Jeden `**bold**` to za mało; dodaj np. nagłówek `##`, listę `-` albo drugi bold. Inaczej treść zostanie zapisana jako HTML i markdownowa składnia (`**bold**`) pokaże się dosłownie
- **Jak zmienić już zapisany format** — API nie permituje pola `fields.markup`. Żeby przełączyć helplink z HTML na markdown, zrób PATCH z pustym `content`, a potem PATCH z nowym markdownowym contentem (reset + zapis wykryje format na nowo)
- **`entry_id`** powinien wskazywać na wpis z pełną dokumentacją tematu — użytkownik klika "Czytaj więcej" i trafia do artykułu
- **`key`** powinien być opisowy i używać podkreśleń (np. `organize_task_priority`, `mail_inbox_filters`)
- **`active: true`** — pamiętaj o ustawieniu, inaczej helplink nie będzie widoczny

## Sugestie po wykonaniu zadania

Po utworzeniu lub edycji wpisu, zaproponuj użytkownikowi kolejne akcje (jako listę do wyboru):

- **Popraw treść wpisu** i dodaj sekcję o...
- **Przetłumacz wpis na angielski** i dodaj jako nowy wpis w tej samej kategorii
- **Dodaj helplink** do tego wpisu (kontekstowa podpowiedź w interfejsie)
- **Dodaj nowe wpisy** w tej samej kategorii o powiązanej tematyce
- **Połącz z innym wpisem** — dodaj powiązanie do istniejącego wpisu (podaj ID lub nazwę)

Dzięki temu użytkownik może szybko zlecić kolejne powiązane zadania bez formułowania pełnego polecenia.

## Powiązane

- [kb_knowledge_base_api](https://intum.intum.pl/kb/intum-kb/baza-wiedzy/api/bazy-wiedzy) — zarządzanie bazami wiedzy, szablony, domeny, `content_api`
- [common_api](https://app.intum.pl/noe/prompt/common_api.md) — wspólne zasady API (format, autoryzacja, odpowiedzi)