---
title: "Zgłoszenia (tickets) — API v1 i MCP | Dokumentacja Nodea"
description: "Pełny reference zgłoszeń wsparcia: endpointy REST API v1 (lista z filtrem statusu, szczegóły z konwersacją bez notatek wewnętrznych, tworzenie, odpowiedź, zamknięcie), zakresy account:read/write + hosting-suite, narzędzia MCP i przykłady curl oraz JSON-RPC."
url: "https://nodea.pl/pl/dokumentacja-api/tickets"
lang: "pl"
updated: "2026-07-16"
---

# Zgłoszenia (tickets) — API v1 i MCP | Dokumentacja Nodea

> Reference zgłoszeń wsparcia — endpointy API v1 (lista z filtrem statusu, szczegóły + konwersacja bez notatek wewnętrznych, tworzenie/odpowiedź/zamknięcie), zakresy account:read/write, flaga hosting-suite, narzędzia MCP i przykłady.

Moduł **Zgłoszenia (tickets)** obejmuje portal wsparcia klienta: listowanie zgłoszeń konta klienta, podgląd konwersacji, otwieranie nowego zgłoszenia, dodawanie odpowiedzi i zamykanie. Dokument opisuje warstwę REST API v1 (/api/v1/tickets) oraz narzędzia MCP z tego modułu.

## Uwierzytelnianie i zakresy (scopes)

API v1 uwierzytelnia się osobistym tokenem Passport przez nagłówek Authorization: Bearer \<token\>.

- account:read — listowanie i podgląd (index, show).
- account:write — tworzenie, odpowiedź i zamknięcie (store, reply, close).

Cały moduł jest dodatkowo bramkowany flagą Pennant features:hosting-suite — odpowiada web'owym grupom /app/account/\*. Limit zapytań: throttle:api-v1 = 240/min na użytkownika tokenu.

## Konto klienta, własność i widoczność

Zgłoszenia należą do **konta klienta** (patrz [Konta klientów](https://nodea.pl/pl/dokumentacja-api/accounts)), a nie do pojedynczego użytkownika. Żądanie działa w bieżącym koncie (przypięcie tokenu → nagłówek X-Account-Id → konto domyślne) i — obok scope'a tokenu — wymaga uprawnienia konta tickets (właściciel ma je zawsze):

EndpointUprawnienie kontaGET /tickets, GET /tickets/{ticket}, POST /tickets, POST /tickets/{ticket}/reply, POST /tickets/{ticket}/closetickets

- **Lista** (GET /tickets) zwraca zgłoszenia **bieżącego konta** — założone przez dowolnego członka, nie tylko przez Ciebie.
- **Podgląd, odpowiedź i zamknięcie** działają dla każdego zgłoszenia bieżącego konta. Zgłoszenie spoza bieżącego konta — innego klienta, innego Twojego konta albo zgłoszenie gościa bez konta — zwraca 404 (nie 403), więc API nie potwierdza istnienia zasobu.
- **Tworzenie** (POST /tickets) zakłada zgłoszenie w bieżącym koncie: account\_id = bieżące konto, zgłaszający (user\_id) = użytkownik tokenu.
- TicketResource niesie pole account\_id (int|null — null dla starszych zgłoszeń bez konta).
- is\_by\_owner w odpowiedziach oznacza **„odpowiedź strony klienta”**: true, gdy autor nie jest pracownikiem obsługi (rola ADMIN) — dotyczy to także odpowiedzi innych członków konta; odpowiedź zgłaszającego jest zawsze po stronie klienta, a odpowiedź bez autora traktowana jest jako odpowiedź obsługi, chyba że pochodzi od nadawcy-gościa (klienta bez konta logowania — np. kontaktu z ticketu zaimportowanego z poprzedniego panelu klienta); wtedy jest po stronie klienta. Odpowiedzi obsługi zaimportowane z poprzedniego panelu, których autor nie ma konta pracownika, mają autora „Zespół Nodea (archiwum)” i są odpowiedziami obsługi.

Brak uprawnienia tickets zwraca 403 account\_permission\_denied z "permission": "tickets"; brak ustalonego konta — 403 no\_account\_context.

## Notatki wewnętrzne — niewidoczne

Konwersacja jest zawsze ładowana przez scope public() na TicketReply, więc **wewnętrzne notatki administratorów nigdy nie trafiają do odpowiedzi** — to wymóg bezpieczeństwa, nie optymalizacja. Klient **nigdy nie może utworzyć notatki wewnętrznej**: pole is\_internal\_note jest twardo ustawiane na false przy każdej odpowiedzi tworzonej przez API. Załączniki nie są obsługiwane przez API (brak uploadu i URL-i pobierania) — eksponowane są wyłącznie metadane załączników odpowiedzi (id, original\_name, size, mime).

## API v1 — endpointy

MetodaŚcieżkaScopeOpisGET/api/v1/ticketsaccount:readLista zgłoszeń bieżącego konta (wszystkich członków), najnowsza aktywność pierwsza (last\_reply\_at DESC, id DESC). Filtr status. Paginacja simple. GET/api/v1/tickets/{ticket}account:readSzczegóły zgłoszenia z pełną konwersacją (publiczne odpowiedzi w porządku chronologicznym, bez notatek wewnętrznych). POST/api/v1/ticketsaccount:writeOtwarcie nowego zgłoszenia (status open); treść staje się pierwszą odpowiedzią. Zwraca 201. POST/api/v1/tickets/{ticket}/replyaccount:writeDodanie odpowiedzi klienta. Zwraca 201 (TicketReplyResource). POST/api/v1/tickets/{ticket}/closeaccount:writeZamknięcie zgłoszenia przez klienta. Zwraca zaktualizowane zgłoszenie.

### GET /tickets — parametry zapytania

- status (enum, opcjonalny) — dokładne dopasowanie: open, pending, answered, customer\_reply, in\_progress, on\_hold, escalated, client\_action\_required, closed, spam. Inna wartość → 422.

### Statusy zgłoszeń

Statusy odpowiadają statusom WHMCS (zgłoszenia zaimportowane z WHMCS zachowują status 1:1). Pole awaiting\_reply\_from mówi, kto ma teraz ruch: staff, client albo null (zamknięte/spam).

StatusZnaczenieawaiting\_reply\_fromopenNowe zgłoszenie, bez odpowiedzi zespołu.staff pendingOczekuje na zespół (status nodea).staff customer\_replyKlient odpowiedział po odpowiedzi zespołu (WHMCS Customer-Reply).staff in\_progressZespół pracuje nad zgłoszeniem (ustawia administrator).staff on\_holdWstrzymane przez zespół (ustawia administrator).staff escalatedEskalowane — brak odpowiedzi zespołu w wyznaczonym czasie albo decyzja administratora.staff answeredZespół odpowiedział.client client\_action\_requiredZespół czeka na działanie klienta.client closedZamknięte (is\_closed = true).null spamOznaczone jako spam — nieodwracalne.null

- per\_page (int 1–100, domyślnie 20), page (int ≥1).

Odpowiedź: kolekcja TicketResource — pola: id, number (T-YYYY-NNNNNN), subject, status, awaiting\_reply\_from (staff|client|null), priority, department (id/name/slug), last\_reply\_at, last\_reply\_by\_admin, is\_closed, closed\_at, created\_at, updated\_at. Dodatkowo account\_id (int|null). Klucz replies\[\] pojawia się tylko w szczegółach (gdy kontroler doładował relację). Każda odpowiedź: id, body, source, is\_by\_owner (odpowiedź strony klienta), author (id/name), attachments\[\] (metadane), created\_at.

### POST /tickets — parametry ciała

- subject (string, wymagany, min 5, max 255).
- body (string, wymagany, min 10) — persystowany jako pierwsza publiczna odpowiedź.
- ticket\_department\_id (wymagany, musi istnieć w ticket\_departments z is\_active = true).
- priority (enum, opcjonalny: low|normal|high|urgent; domyślnie normal).

Tworzenie jest atomowe (transakcja): tymczasowy numer spełnia unikalny indeks, następnie generateNumber() wylicza realny T-YYYY-NNNNNN, a treść zapisywana jest jako pierwsza odpowiedź (source = api). Skrzynka działu jest powiadamiana jako anonimowy notifiable. Załączniki nie są przyjmowane przez API.

### POST /reply oraz /close — reguły biznesowe

- reply: ciało body (string, wymagany, min 1). Odpowiedź klienta przełącza status answered, client\_action\_required i on\_hold → customer\_reply; pozostałe stany (m.in. open, in\_progress, escalated) są zachowane.
- Zgłoszenie closed odrzuca odpowiedź: 422, kod ticket\_closed.
- Zgłoszenie spam odrzuca odpowiedź: 422, kod ticket\_spam.
- close: zamknięcie już zamkniętego to 422, kod already\_closed; zgłoszenia spam klient nie może zamknąć: 422, kod ticket\_spam. Sukces stempluje closed\_at i closed\_by\_id.

### Kody błędów

- 401 — brak/niepoprawny token.
- 403 — brak wymaganego scope lub nieaktywna flaga hosting-suite.
- 403 — błąd kontekstu konta: account\_permission\_denied (pole permission podaje brakującą flagę) — tu zawsze tickets, no\_account\_context, account\_forbidden / account\_mismatch (nagłówek X-Account-Id lub przypięcie tokenu) — patrz [Konta klientów](https://nodea.pl/pl/dokumentacja-api/accounts).
- 404 — nieznane zgłoszenie albo zgłoszenie spoza bieżącego konta.
- 422 — walidacja lub reguła biznesowa (kody: ticket\_closed, ticket\_spam, already\_closed).

## Przykłady — API

### Lista zgłoszeń z filtrem statusu

curl -s "https://app.nodea.io/api/v1/tickets?status=open&per\_page=20" \\ -H "Authorization: Bearer $NODEA\_TOKEN" \\ -H "Accept: application/json"

### Otwarcie nowego zgłoszenia

curl -s -X POST https://app.nodea.io/api/v1/tickets \\ -H "Authorization: Bearer $NODEA\_TOKEN" \\ -H "Content-Type: application/json" \\ -d '{ "ticket\_department\_id": 1, "subject": "Problem z DNS", "body": "Rekord A nie propaguje się od godziny.", "priority": "high" }'

### Odpowiedź na zgłoszenie

curl -s -X POST https://app.nodea.io/api/v1/tickets/42/reply \\ -H "Authorization: Bearer $NODEA\_TOKEN" \\ -H "Content-Type: application/json" \\ -d '{ "body": "Dziękuję, już działa." }'

### Zamknięcie zgłoszenia

curl -s -X POST https://app.nodea.io/api/v1/tickets/42/close \\ -H "Authorization: Bearer $NODEA\_TOKEN" \\ -H "Accept: application/json"

## MCP — narzędzia

Narzędzia MCP dzielą model uwierzytelniania i zakresów z API v1 (Bearer + scope sprawdzany w ensureScope) oraz flagę features:hosting-suite — narzędzie na nieaktywnej fladze znika z tools/list i każde wywołanie kończy się błędem „Tool \[...\] not found.”. Identyfikatory zgłoszeń to liczby całkowite (id). **Brakujący i cudzy identyfikator zwracają ten sam błąd** (AuthorizationException: „Ticket not found or not accessible with your permissions.”) — brak enumeracji między najemcami.

NarzędzieScopeTrybOpistickets-listaccount:readread-onlyLista zgłoszeń bieżącego konta (wszystkich członków); filtr status, page, per\_page (max 50, domyślnie 15). reply\_count liczy tylko publiczne odpowiedzi. ticket-getaccount:readread-onlyJedno zgłoszenie z pełną konwersacją (publiczne odpowiedzi chronologicznie, bez notatek wewnętrznych). Param: id. ticket-createaccount:writezapisOtwarcie zgłoszenia; ticket\_department\_id, subject (max 255), body, opcjonalny priority. Status open, source = mcp. ticket-replyaccount:writezapisOdpowiedź klienta; id, body. answered/client\_action\_required/on\_hold → customer\_reply. Zamknięte/spam odrzucają. ticket-closeaccount:writezapisZamknięcie zgłoszenia; id. Już zamknięte lub spam zwracają błąd narzędzia.

Uwagi: tickets-list, ticket-get mają adnotacje IsReadOnly/IsIdempotent. ticket-create, ticket-reply, ticket-close są zapisujące (bez adnotacji read-only). Reguły biznesowe (zamknięte/spam, przejście do customer\_reply po odpowiedzi klienta, twarde is\_internal\_note = false, powiadomienie skrzynki działu) są identyczne jak w API; przy błędzie zwracany jest Response::error zamiast HTTP 422. ticket-create i ticket-close ładują reply\_count tylko z publicznych odpowiedzi.

**Konta klientów w MCP.** Narzędzia działają w bieżącym koncie połączenia MCP (patrz [Konta klientów](https://nodea.pl/pl/dokumentacja-api/accounts)) i wymagają uprawnienia konta tickets obok scope'a. tickets-list zwraca zgłoszenia wszystkich członków konta; ticket-get, ticket-reply i ticket-close działają na zgłoszeniach bieżącego konta; ticket-create zakłada zgłoszenie w bieżącym koncie z wywołującym jako zgłaszającym. is\_by\_owner ma to samo znaczenie co w API (strona klienta). Odmowy kończą się sufiksem (code: account\_permission\_denied, permission: tickets) lub (code: no\_account\_context); zgłoszenie spoza konta zwraca „Ticket not found or not accessible with your permissions.”.

### Przykład — MCP (JSON-RPC)

{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "ticket-create", "arguments": { "ticket\_department\_id": 1, "subject": "Problem z DNS", "body": "Rekord A nie propaguje się od godziny.", "priority": "high" } } } { "jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": { "name": "ticket-reply", "arguments": { "id": 42, "body": "Dziękuję, już działa." } } }

## Powiązane

- [Profil konta — API v1 i MCP | Dokumentacja Nodea](https://nodea.pl/pl/dokumentacja-api/profile)
- [Rozliczenia (billing) — API v1 i MCP | Dokumentacja Nodea](https://nodea.pl/pl/dokumentacja-api/billing)
- [Konta klientów — API v1 i MCP | Dokumentacja Nodea](https://nodea.pl/pl/dokumentacja-api/accounts)

---

Wersje językowe: [en](https://nodea.io/en/api-docs/tickets.md)  
Spis treści witryny: [llms.txt](https://nodea.pl/pl/llms.txt)
