Problemy w Codenica API

Pracę z problemami przez Codenica API zaczynasz od utworzenia klucza w ustawieniach Codenica. Jeśli klucz nie został jeszcze utworzony, otwórz w nowej karcie Codenica API - wprowadzenie. Znajdziesz tam wspólne zasady wydawania kluczy, przechowywania sekretu i uwierzytelniania.

Techniczna nazwa modułu to problems, a typ pojedynczego obiektu to problem. Problem służy do rejestrowania przyczyny lub źródła powtarzających się incydentów. Oprócz danych opisowych ma pola diagnostyczne isKnown, symptoms, rootCause i impactInfo.

W kolejnych krokach znajdziesz adresy, zakresy, schema, listy, filtrowanie, tworzenie, edycję, ETag, batch, relacje, użytkowników, pliki, akcje workflow, eskalację, akceptację i usuwanie problemów.

Przykłady wykorzystują prefix PUBLIC-API-PROBLEM-20260905131727. W swojej integracji zastąp go własnym identyfikatorem, a adresy e-mail, identyfikatory i wartości pól dopasuj do danych w swojej bazie.


Problemy - adres API i wybór instalacji

Wszystkie trasy dotyczące problemów zaczynają się od:

{BASE_URL}/api/v1/problems

W Codenica Cloud użyj publicznej domeny przypisanej do właściwej instalacji:

export BASE_URL="https://twoja-firma.codenica.com"

W domyślnej instalacji On-Premise adres lokalnie rejestrowany przez program Codenica Discovery to:

export BASE_URL="http://codenica.local:5150"

Jeżeli administrator udostępnił instalację pod firmową domeną, przez reverse proxy, z HTTPS albo na innym porcie, użyj dokładnego adresu przekazanego dla tej instalacji:

export BASE_URL="https://api.twoja-firma.example"

Nie używaj localhost, jeśli program integrujący działa na innym komputerze niż API. Nie przekazuj tenantId w body ani w query stringu. Właściwa baza danych jest wybierana na podstawie adresu hosta, z którym łączy się integracja.


Problemy - klucz API i limity licencyjne

Klucz API utwórz w Codenica w miejscu Ustawienia - API - API Keys. Sekret jest pokazywany tylko raz, bezpośrednio po utworzeniu albo obróceniu klucza. Zapisz wtedy Client ID i Client Secret w bezpiecznym magazynie używanym przez integrację.

Codenica API jest dostępne dla licencji Plus i Enterprise. Licencja Plus pozwala utworzyć do 50 aktywnych kluczy, a Enterprise do 100. Starter nie udostępnia Codenica API. Dla każdej aplikacji i środowiska utwórz osobny klucz, aby można było niezależnie ograniczyć jego zakresy, obrócić sekret albo usunąć dostęp.

Licencja
Codenica API
Aktywne klucze
Starter
niedostępne
0
Plus
dostępne
maksymalnie 50
Enterprise
dostępne
maksymalnie 100

Domyślny termin ważności klucza wynosi 90 dni, jeżeli w panelu nie ustawisz innej daty. Maksymalny termin ważności wynosi 5 lat. Klucze wygasłe lub nieaktywne nie zajmują aktywnego slotu, ale pozostają widoczne do czasu użycia opcji Usuń. Usunięcie rekordu jest trwałe.


Problemy - uwierzytelnianie i bezpieczne żądania

Każde żądanie Codenica API uwierzytelniaj dwoma nagłówkami klucza:

export CLIENT_ID="cna_twoj_client_id"
export CLIENT_SECRET="cns_twoj_client_secret"

curl --request GET --url "$BASE_URL/api/v1/problems?page=1&pageSize=25" \
  --header "Accept: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Zewnętrzna integracja nie potrzebuje JWT administratora ani ciasteczek z panelu Codenica. Klucza nie umieszczaj w repozytorium, kodzie dostarczanym do przeglądarki, adresie URL, historii poleceń ani logach. Poza lokalnymi testami korzystaj z HTTPS.

W odpowiedzi zachowuj meta.requestId. Jest potrzebny do diagnozowania konkretnego żądania, ale nie zastępuje identyfikatora problemu i nie powinien być używany jako sekret.


Problemy - sprawdzenie kontekstu połączenia

Przed pierwszym zapisem pobierz kontekst. Dzięki temu sprawdzisz, czy adres prowadzi do właściwej bazy, a wybrany klucz ma potrzebne zakresy:

curl --request GET --url "$BASE_URL/api/v1/context" \
  --header "Accept: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

W odpowiedzi zweryfikuj:

  • data.apiVersion i data.contractVersion;
  • data.tenant.id, data.tenant.name i data.tenant.resolvedDomain;
  • data.caller.authentication równe api_key;
  • obecność problems w data.capabilities.resources;
  • zakresy przypisane do klucza;
  • limity stron, batch, plików i żądań.

Jeżeli kontekst wskazuje inną bazę albo nie zawiera wymaganego zakresu, zatrzymaj integrację i popraw adres lub klucz. Zakresów nie można nadać pojedynczym żądaniem.


Problemy - zakresy uprawnień

Pełna obsługa problemów wymaga zakresów odpowiadających wykorzystywanym operacjom:

problems:read
problems:write
problems:delete
problems:schema
problems:stats
problems:relationships:read
problems:relationships:write
problems:users:read
problems:users:write
problems:files:read
problems:files:write
problems:technical:read
problems:technical:write
problems:pin:write
problems:spam:write
problems:reopen:write
problems:rating:write
problems:escalation:write
problems:approval:write

Do zwykłego odczytu wystarczy problems:read. Schema i statystyki wymagają osobnych zakresów problems:schema oraz problems:stats. Odczyt relacji, użytkowników i plików wymaga odpowiednich zakresów odczytu. Operacje zapisu mają analogiczne zakresy :write.

Relacje z innymi modułami wymagają także odczytu wskazywanego modułu, na przykład assets:read, documents:read, tickets:read albo solutions:read. Do utworzenia i decyzji approval dodaj zakresy potrzebne dla samego modułu approvals. Przyznawaj zakresy zgodnie z zasadą najmniejszych uprawnień.


Problemy - schema i pola diagnostyczne

Schema pokazuje, które pola można odczytać i zapisać w konkretnej bazie. Pobierz je przed przygotowaniem formularza lub mapowania:

curl --request GET --url "$BASE_URL/api/v1/problems/schema" \
  --header "Accept: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Dla każdego pola sprawdź między innymi readable, writable, required, technical, unique oraz maxLength. Schema zwraca również słowniki oraz dostępne cele relacji.

Minimalny zapis problemu wymaga obecnie pól subject i requesterEmail. Problemy mają własną grupę diagnostyczną:

Grupa
Pola
Zastosowanie
Podstawowe
subject, requesterEmail, description, comments
opis problemu i osoba zgłaszająca
Klasyfikacja
type, status, priority, impact, urgency, severity
sposób obsługi i znaczenie problemu
Diagnostyka
isKnown, symptoms, rootCause, impactInfo
znany problem, objawy, przyczyna i wpływ
Integracja
source, services, tags, externalNumber, referenceNumber
powiązanie z innym systemem

Pola pin i isSpam są techniczne i zmienia się je przez dedykowane akcje. Pola systemowe oraz tylko do odczytu, w tym dane oceny i eskalacji, nie powinny być przesyłane w zwykłym PATCH-u. Problemy nie obsługują pól kosztowych currency, estimatedCost i totalValue znanych z innych modułów.


Problemy - podstawowe endpointy

Najczęściej używane trasy problemów są następujące:

  • GET /api/v1/problems - lista problemów;
  • GET /api/v1/problems/{id} - pojedynczy problem;
  • POST /api/v1/problems - utworzenie;
  • PATCH /api/v1/problems/{id} - częściowa edycja;
  • DELETE /api/v1/problems/{id} - usunięcie;
  • GET /api/v1/problems/schema - schema pól i relacji;
  • GET /api/v1/problems/stats - statystyki;
  • GET /api/v1/problems/values - wartości używane w filtrach;
  • POST /api/v1/problems:batch - operacje create, update i delete.

Relacje, użytkownicy, pliki, akcje workflow i akceptacje mają osobne trasy. Dzięki temu integracja może otrzymać tylko te uprawnienia, które są rzeczywiście potrzebne.


Problemy - listowanie i paginacja

Listę pobieraj stronicami. Nawet przy małej liczbie rekordów podaj jawnie numer strony i jej rozmiar:

curl --request GET --url "$BASE_URL/api/v1/problems?page=1&pageSize=25" \
  --header "Accept: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Odpowiedź zawiera data.items oraz informacje page, pageSize, totalItems, totalPages i hasNextPage. Pobieraj następne strony, dopóki hasNextPage ma wartość true:

curl --request GET --url "$BASE_URL/api/v1/problems?page=2&pageSize=25&sort=dateUpdated&direction=desc" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Do synchronizacji najwygodniej sortować po dateUpdated i zapamiętywać ostatnio przetworzone rekordy. Nie ustawiaj pageSize wyższego niż limit zwrócony w kontekście.


Problemy - wyszukiwanie, filtry i sortowanie

Parametry listy możesz łączyć. Poniższy przykład wyszukuje rekord po identyfikatorze, ogranicza wynik do typu problem i znanych problemów, a następnie sortuje go według daty aktualizacji:

curl --get --url "$BASE_URL/api/v1/problems" \
  --data-urlencode "itemType=problem" \
  --data-urlencode "customId=PUBLIC-API-PROBLEM-20260905131727-SOURCE" \
  --data-urlencode "isKnown=true" \
  --data-urlencode "sort=dateUpdated" \
  --data-urlencode "direction=desc" \
  --data-urlencode "page=1" \
  --data-urlencode "pageSize=25" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

W codziennej synchronizacji przydatne są również parametry search, status, priority, subject, requesterEmail, source, externalNumber, referenceNumber, symptoms, rootCause, impactInfo, createdAfter, createdBefore, updatedAfter i updatedBefore, o ile są dostępne w aktualnym schema.

Filtr strukturalny ma format field:operator:value. Dostępne operatory to eq, ne, in, contains, startsWith, endsWith, empty, notEmpty, gt, gte, lt i lte:

curl --get --url "$BASE_URL/api/v1/problems" \
  --data-urlencode "filter=status:eq:Closed" \
  --data-urlencode "filter=rootCause:contains:connection" \
  --data-urlencode "page=1" \
  --data-urlencode "pageSize=25" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Wartości tekstowe i daty koduj zgodnie z zasadami URL. Nie zakładaj, że słownik w dwóch bazach będzie identyczny.


Problemy - wybór pól i dołączanie danych

Parametr fields pozwala ograniczyć odpowiedź do pól potrzebnych integracji. Parametr include dołącza dane powiązane:

curl --get --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}" \
  --data-urlencode "fields=subject,requesterEmail,status,priority,isKnown,symptoms,rootCause,impactInfo" \
  --data-urlencode "include=files,relationships,users" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Przy odczycie całego modelu możesz użyć fields=*. Dołączanie plików, relacji i użytkowników wymaga odpowiednich zakresów odczytu. fields nie omija kontroli dostępu ani nie ujawnia pól technicznych, do których klucz nie ma uprawnień.

W odpowiedzi zwracaj uwagę na data.id, data.itemType, data.attributes i data.meta. Pola techniczne, takie jak pin albo isSpam, odczytuj, ale zmieniaj przez dedykowane akcje opisane dalej.


Problemy - statystyki i wartości słownikowe

Statystyki pozwalają na przykład policzyć problemy według pola isKnown. Są operacją odczytową i nie modyfikują rekordów:

curl --get --url "$BASE_URL/api/v1/problems/stats" \
  --data-urlencode "field=isKnown" \
  --data-urlencode "limit=20" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Wartości pola rootCause przydatne do budowy podpowiedzi lub filtrów pobierzesz osobno:

curl --get --url "$BASE_URL/api/v1/problems/values" \
  --data-urlencode "field=rootCause" \
  --data-urlencode "search=connection" \
  --data-urlencode "limit=20" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Najpierw pobierz słownik, a dopiero potem wyślij wartość w body. Jest to szczególnie ważne dla status, priority, type i pól diagnostycznych konfigurowanych w danej bazie.


Problemy - tworzenie rekordu

Nowy problem utworzysz przez POST /api/v1/problems. W body umieść techniczny typ problem i zapisywalne pola w attributes. Przykład zawiera dane opisowe, klasyfikację, informacje integracyjne oraz pełną grupę diagnostyczną:

export IDEMPOTENCY_KEY="public-api-problem-create-20260905131727"

curl --request POST --url "$BASE_URL/api/v1/problems" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "Idempotency-Key: $IDEMPOTENCY_KEY" \
  --data-raw '{
    "itemType": "problem",
    "attributes": {
      "customId": "PUBLIC-API-PROBLEM-20260905131727-SOURCE",
      "subject": "Problem integracyjny Codenica API",
      "requesterEmail": "[email protected]",
      "description": "Problem utworzony przez integrację Codenica API.",
      "comments": "Przykład diagnostyczny dla modułu Problems.",
      "source": "Codenica API",
      "type": "Standard",
      "status": "Closed",
      "priority": "High",
      "impact": "Medium",
      "urgency": "High",
      "severity": "High",
      "services": "Codenica API",
      "tags": "codenica-api,problem",
      "externalNumber": "EXT-CODENICA-API-PROBLEM-20260905131727",
      "referenceNumber": "REF-CODENICA-API-PROBLEM-20260905131727",
      "isKnown": true,
      "symptoms": "Użytkownicy nie mogą zakończyć synchronizacji.",
      "rootCause": "Błąd połączenia z usługą zewnętrzną.",
      "impactInfo": "Synchronizacja problematycznej grupy danych jest opóźniona."
    },
    "customValues": [
      {
        "name": "description",
        "valuePattern": "[problem-test] PUBLIC-API-PROBLEM-20260905131727"
      }
    ]
  }'

Wymagane minimum to subject i requesterEmail, o ile schema nie nakłada dodatkowych wymagań. Udane utworzenie zwraca HTTP 201, identyfikator data.id oraz ETag w nagłówku i w data.meta.etag. Secret klucza nie jest częścią odpowiedzi obiektu.


Problemy - idempotencja tworzenia

Powtórzenie tego samego żądania z tym samym Idempotency-Key powinno zwrócić ten sam wynik logiczny, a nie utworzyć drugi problem:

curl --request POST --url "$BASE_URL/api/v1/problems" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "Idempotency-Key: public-api-problem-create-20260905131727" \
  --data-binary @problem.json

Ten sam klucz można bezpiecznie powtórzyć po niepewnym wyniku sieciowym tylko dla tego samego żądania. Nie używaj jednego klucza dla dwóch różnych operacji. Dla nowego body wygeneruj nowy klucz.

Idempotency-Key obowiązuje przy każdym żądaniu zmieniającym dane, także przy edycji, relacji, pliku, akcji workflow i usuwaniu. Ponowienie tego samego klucza z inną trasą lub innym body kończy się błędem konfliktu idempotencji.


Problemy - odczyt i ETag

Odczyt pojedynczego problemu z dołączonymi danymi wykonaj tak:

curl --get --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}" \
  --data-urlencode "fields=*" \
  --data-urlencode "include=files,relationships,users" \
  --header "Accept: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Zachowaj ETag z nagłówka odpowiedzi. Wartość powinna odpowiadać data.meta.etag i meta.etag w kopercie odpowiedzi. Po każdym udanym zapisie, akcji, zmianie relacji lub operacji plikowej pobierz albo odczytaj nowy ETag.

ETag reprezentuje wersję konkretnego problemu. Nie używaj ETag-u pobranego dla jednego problemu do modyfikacji innego.


Problemy - edycja z If-Match

Edycja jest częściowa. Prześlij tylko pola, które mają zostać zmienione:

curl --request PATCH --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-update-20260905131727" \
  --data-raw '{
    "attributes": {
      "description": "Opis zaktualizowany przez integrację.",
      "status": "Closed",
      "priority": "High",
      "isKnown": false,
      "symptoms": "Objawy po ponownej obserwacji.",
      "rootCause": "Zaktualizowana analiza przyczyny.",
      "impactInfo": "Wpływ po zastosowaniu obejścia."
    }
  }'

Nie zmieniaj zwykłym PATCH-em pól tylko do odczytu, takich jak rating, dateRating, dateFeedback, dateReopened i dateEscalated. Pin, spam, reopen, rating, eskalacja i approval mają dedykowane endpointy.

Po udanej edycji otrzymasz HTTP 200 i nowy ETag. Zapisz go przed następną operacją.


Problemy - kontrola nieaktualnego If-Match

Każda mutacja poza utworzeniem wymaga aktualnego ETag-u. Brak nagłówka i nieaktualna wartość są odrzucane:

curl --request PATCH --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "Idempotency-Key: public-api-problem-missing-if-match-20260905131727" \
  --data-raw '{"attributes":{"isKnown":false}}'

Brak If-Match zwraca HTTP 428 z kodem if_match_required. Jeżeli wyślesz starszy ETag, otrzymasz HTTP 412 z kodem if_match_failed. Odrzucone żądanie nie powinno zmienić problemu.

Po HTTP 412 pobierz rekord ponownie, odczytaj nowy ETag i dopiero wtedy zdecyduj, czy można ponowić edycję. Nie nadpisuj w ciemno zmian wykonanych przez innego użytkownika lub proces.


Problemy - operacje batch

Batch służy do obsługi wielu niezależnych pozycji. Jedno żądanie może zawierać operacje create, update i delete:

curl --request POST --url "$BASE_URL/api/v1/problems:batch" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "Idempotency-Key: public-api-problem-batch-20260905131727" \
  --data-raw '{
    "items": [
      {
        "operation": "create",
        "create": {
          "itemType": "problem",
          "attributes": {
            "customId": "PUBLIC-API-PROBLEM-20260905131727-BATCH-A",
            "subject": "Problem batch A",
            "requesterEmail": "[email protected]",
            "source": "Codenica API",
            "type": "Standard",
            "status": "Open",
            "priority": "Medium",
            "isKnown": true,
            "symptoms": "Objawy problemu A",
            "rootCause": "Przyczyna problemu A",
            "impactInfo": "Wpływ problemu A"
          }
        }
      },
      {
        "operation": "update",
        "id": "PROBLEM_UUID",
        "ifMatch": "\"CURRENT_ETAG\"",
        "update": {
          "attributes": {
            "isKnown": false,
            "rootCause": "Nowa analiza przyczyny"
          }
        }
      },
      {
        "operation": "delete",
        "id": "OTHER_PROBLEM_UUID",
        "ifMatch": "\"OTHER_CURRENT_ETAG\""
      }
    ]
  }'

W batch update i delete użyj ETag-u konkretnego rekordu. Klucz idempotencji identyfikuje całe żądanie batch, a nie pojedynczy element. Odpowiedź sprawdź element po elemencie, według indeksu, statusu, identyfikatora i błędu. Pełne powodzenie zwykle zwraca HTTP 200, a wynik częściowy HTTP 207 Multi-Status. Batch nie jest transakcją all-or-nothing.


Problemy - relacje z obiektami

Dostępne cele relacji są zwracane przez /api/v1/problems/schema. W aktualnym kontrakcie mogą obejmować:

assets
documents
changes
tickets
problems
solutions
releases
notes
approvals
worktasks
requesteditems

Obecność celu w schema nie oznacza, że w konkretnej bazie istnieje rekord dostępny dla użytkownika. Przed dodaniem relacji sprawdź identyfikator, targetDataSet, targetItemType i uprawnienia do odczytu celu.

Dla assets, documents, problems, changes, tickets, solutions i releases użyj relationshipType zgodnego ze schema, na przykład related. Dla notes, approvals, worktasks i requesteditems pozostaw relationshipType równe null. Nie wpisuj related na siłę.

Dodanie kilku relacji:

curl --request POST --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/relationships:batch" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-relationships-20260905131727" \
  --data-raw '{
    "add": [
      {
        "targetId": "ASSET_UUID",
        "targetDataSet": "assets",
        "targetItemType": "computer",
        "relationshipType": "related"
      },
      {
        "targetId": "DOCUMENT_UUID",
        "targetDataSet": "documents",
        "targetItemType": "invoice",
        "relationshipType": "related"
      },
      {
        "targetId": "NOTE_UUID",
        "targetDataSet": "notes",
        "targetItemType": "note",
        "relationshipType": null
      }
    ],
    "remove": []
  }'

Odpowiedź HTTP 200 zawiera liczniki added, removed i skipped. skipped nie jest błędem transportowym, dlatego po operacji pobierz kolekcję relacji i sprawdź jej zawartość.


Problemy - odczyt i usuwanie relacji

Listę relacji pobierzesz tak:

curl --request GET --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/relationships?page=1&pageSize=100" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Pojedynczą relację usuń z aktualnym ETag-em źródłowego problemu. Dla celu przechowującego relationshipType podaj go w query stringu:

curl --request DELETE --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/relationships/tickets/{TICKET_ID}?relationshipType=related" \
  --header "Accept: application/json, application/problem+json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-relationship-delete-20260905131727"

Przy celu takim jak notes, dla którego schema wskazuje brak typu relacji, pomiń parametr relationshipType. Relację można również usunąć przez częściową edycję:

curl --request PATCH --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-relationship-patch-20260905131727" \
  --data-raw '{
    "relationshipsToRemove": [
      {
        "targetId": "TICKET_UUID",
        "targetDataSet": "tickets",
        "targetItemType": "ticket",
        "relationshipType": "related"
      }
    ]
  }'

Usunięcie relacji nie usuwa rekordu, który był jej celem. Po każdej zmianie pobierz kolekcję ponownie i zapisz nowy ETag problemu.


Problemy - relacje z użytkownikami

Problem może mieć następujące relacje użytkownika:

  • agent - osoba odpowiedzialna za obsługę;
  • watcher - obserwator;
  • appUserRequester - użytkownik aplikacyjny zgłaszający problem.

Dla Problems nie zakładaj relacji clientRequester. Cele są aktywnymi użytkownikami i podlegają kontroli lokalizacji oraz działu.

Przypisanie agenta:

curl --request POST --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/user-relationships" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-agent-20260905131727" \
  --data-raw '{
    "targetId": "USER_UUID",
    "targetDataSet": "users",
    "relationshipType": "agent"
  }'

Dodanie obserwatora przez batch:

curl --request POST --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/user-relationships:batch" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-watcher-20260905131727" \
  --data-raw '{
    "add": [
      {
        "targetId": "WATCHER_USER_UUID",
        "targetDataSet": "users",
        "relationshipType": "watcher"
      }
    ],
    "remove": []
  }'

Odczyt i usunięcie relacji:

curl --request GET --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/user-relationships?page=1&pageSize=100" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

curl --request DELETE --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/user-relationships/users/{USER_ID}?relationshipType=agent" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-agent-delete-20260905131727"

Obserwatora można także usunąć przez batch z pustym add i wpisem w remove. Po każdej zmianie odczytaj nowy ETag.


Problemy - pliki

Przed operacją na pliku odczytaj aktualny problem i jego ETag. Wysłanie pliku wymaga żądania multipart/form-data:

curl --request POST --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/files?relationshipType=documentation" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-file-one-20260905131727" \
  --form "[email protected];type=text/plain"

Lista plików:

curl --request GET --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/files?page=1&pageSize=100" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Element listy zawiera między innymi id, name, fileName, contentType, size, relationshipType, isMain oraz downloadUrl. downloadUrl należy traktować jako ścieżkę API, a nie jako publiczny, anonimowy link. W Problems isMain jest zawsze równe false.

Pobranie treści zapisuje odpowiedź jako dane binarne:

curl --request GET --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/files/{FILE_ID}/content" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --output problem-evidence.txt

Istniejący plik możesz dołączyć do innego problemu. ETag dotyczy wtedy problemu docelowego:

curl --request POST --url "$BASE_URL/api/v1/problems/{OTHER_PROBLEM_ID}/files/{FILE_ID}?relationshipType=manual" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $OTHER_PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-file-attach-20260905131727"

Usunięcie pliku:

curl --request DELETE --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/files/{FILE_ID}" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-file-delete-20260905131727"

Limit rozmiaru pliku odczytaj z context przed uploadem. Nie przyjmuj dużego pliku do pamięci bez wcześniejszego sprawdzenia limitu.


Problemy - przypięcie, spam i ponowne otwarcie

Przypięcie, oznaczenie spamu i ponowne otwarcie są osobnymi akcjami. Każda akcja wymaga bieżącego ETag-u oraz nowego klucza idempotencji.

Przypięcie problemu:

curl --request POST --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/pin" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-pin-20260905131727" \
  --data-raw '{"pin":2}'

Wartość pin może być liczbą od 0 do 3 albo null, zgodnie ze schema. Oznaczenie jako spam i cofnięcie oznaczenia:

curl --request POST --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/spam" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-spam-on-20260905131727" \
  --data-raw '{"isSpam":true}'

curl --request POST --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/spam" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-spam-off-20260905131727" \
  --data-raw '{"isSpam":false}'

Ponowne otwarcie zamkniętego problemu:

curl --request POST --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/reopen" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-reopen-20260905131727"

Potrzebne zakresy to odpowiednio problems:pin:write, problems:spam:write i problems:reopen:write. Po każdej akcji pobierz problem ponownie i zapisz nowy ETag.


Problemy - ocena i eskalacja

Ocenę zapisuje się przez osobny endpoint. Możesz dołączyć do niej prośbę o eskalację:

curl --request POST --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/rating" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-rating-20260905131727" \
  --data-raw '{
    "rating": 4,
    "feedback": "Ocena z integracji Codenica API.",
    "isEscalationRequested": true,
    "escalationRequestReason": "Problem wymaga analizy zespołu drugiej linii."
  }'

Ocena ma wartość od 0 do 5 i wymaga zakresu problems:rating:write. Dołączenie żądania eskalacji wymaga dodatkowo problems:escalation:write oraz odpowiedniego uprawnienia użytkownika. Jeżeli zapisujesz tylko ocenę, pomiń pola eskalacji. Po zapisaniu odczytaj między innymi rating, feedback, daty oceny i escalationRequestReason.


Problemy - akceptacja i decyzja

Akceptację możesz utworzyć jako osobny obiekt approval i połączyć ją z problemem relacją. Osoba wskazana w approverId musi mieć prawo do podjęcia decyzji:

curl --request POST --url "$BASE_URL/api/v1/approvals" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "Idempotency-Key: public-api-problem-approval-create-20260905131727" \
  --data-raw '{
    "itemType": "approval",
    "approverId": "APPROVER_USER_UUID",
    "attributes": {
      "customId": "PUBLIC-API-PROBLEM-20260905131727-APPROVAL",
      "category": "Codenica API",
      "description": "Akceptacja analizy problemu."
    },
    "relationships": [
      {
        "targetId": "PROBLEM_UUID",
        "targetDataSet": "problems",
        "targetItemType": "problem"
      }
    ]
  }'

Po utworzeniu odczytaj approval, a decyzję zapisz trasą problemu. APPROVAL_ID jest identyfikatorem akceptacji, nie użytkownika:

curl --request POST --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}/approvals/{APPROVAL_ID}" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-approval-decision-20260905131727" \
  --data-raw '{
    "approve": true,
    "remark": "Zaakceptowano przez integrację Codenica API."
  }'

Odrzucenie wykonuje się z approve równym false i własnym komentarzem. Po decyzji odczytaj approval ponownie i sprawdź jego status albo datę decyzji. Następnie odśwież problem, ponieważ decyzja może zmienić jego ETag i stan procesu.


Problemy - usuwanie rekordu

Przed usunięciem pobierz problem ponownie i użyj aktualnego ETag-u:

curl --request DELETE --url "$BASE_URL/api/v1/problems/{PROBLEM_ID}" \
  --header "Accept: application/json, application/problem+json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $PROBLEM_ETAG" \
  --header "Idempotency-Key: public-api-problem-delete-20260905131727"

Po HTTP 200 wykonaj kontrolny GET tego samego UUID-u. Oczekuj HTTP 404 z kodem problem_not_found albo odpowiednim kodem wskazanym w kontrakcie. Jeżeli problem ma relacje, pliki lub approval, przed operacją sprawdź konsekwencje w schema i wymaganiach swojej bazy.

Usunięcie problemu nie powinno zastępować archiwizacji historii. Jeżeli rekord ma pozostać w dokumentacji, zmień jego status albo przenieś dane do systemu przeznaczonego do przechowywania historii.


Problemy - błędy, limity i bezpieczeństwo

Błędy zwracane są w formacie application/problem+json. Przykładowa odpowiedź:

{
  "type": "https://docs.codenica.com/errors/problem_not_found",
  "title": "Problem not found.",
  "status": 404,
  "detail": "The problem does not exist or is outside the caller's access scope.",
  "instance": "/api/v1/problems/PROBLEM_UUID",
  "code": "problem_not_found",
  "requestId": "request-id-from-response"
}

W logice integracji używaj przede wszystkim status i code. Pole detail jest informacją dla człowieka i może zmienić treść.

HTTP
Znaczenie
Reakcja
400
niepoprawne dane lub pole poza schema
odczytaj błędy pól i popraw mapowanie
401
brak lub nieprawidłowe uwierzytelnienie
sprawdź host i klucz
403
brak zakresu albo dostępu do bazy
zmień zakres klucza lub uprawnienia użytkownika
404
problem, plik albo cel relacji nie istnieje lub jest niewidoczny
zweryfikuj UUID i adres instalacji
409
konflikt danych, wersji lub idempotencji
nie twórz drugiego rekordu bez analizy
412
nieaktualny ETag
pobierz problem i nowy ETag
413
body lub plik jest zbyt duży
sprawdź limit w context
422
body albo wartości pól są niepoprawne
popraw payload zgodnie ze schema
428
brakuje If-Match albo Idempotency-Key
dodaj właściwy nagłówek
429
przekroczono limit żądań
zastosuj backoff i Retry-After

Odczytuj nagłówki X-RateLimit-Limit i X-RateLimit-Remaining. Po 429 zastosuj opóźnienie narastające i respektuj ewentualny Retry-After. W logach zapisuj metodę, endpoint, status i requestId, ale nigdy Client Secret ani pełnych nagłówków uwierzytelniających.

Dane problemów mogą zawierać informacje operacyjne, osobowe i diagnostyczne. Minimalizuj zakres pól, stosuj HTTPS i ogranicz dostęp integracji do konkretnej bazy danych.


Problemy - kolejność pracy integracji

  1. Ustaw BASE_URL dla właściwej instalacji Cloud albo On-Premise.
  2. Utwórz osobny klucz w Ustawienia - API - API Keys i wybierz minimalne zakresy.
  3. Umieść Client ID i Client Secret w bezpiecznym magazynie.
  4. Wyślij GET /api/v1/context i sprawdź bazę, caller oraz limity.
  5. Pobierz GET /api/v1/problems/schema i zbuduj mapowanie pól diagnostycznych.
  6. Pobierz listę problemów albo utwórz nowy przez POST z unikalnym Idempotency-Key.
  7. Zapisz UUID problemu i jego ETag.
  8. Przed każdą mutacją odśwież ETag i użyj nowego klucza idempotencji.
  9. Dodawaj relacje, użytkowników i pliki dopiero po sprawdzeniu celów w schema.
  10. Wykonuj pin, spam, rating, eskalację, reopen i decyzje approval jako osobne operacje.
  11. Przy 412 pobierz rekord, rozstrzygnij konflikt i świadomie ponów operację.
  12. Przy batch sprawdź wynik każdej pozycji, ponieważ częściowy błąd nie musi cofnąć sukcesów.
  13. Obsłuż 429, zapisuj requestId bez sekretów i usuń klucz, gdy integracja przestaje być używana.
  14. Przed usunięciem potwierdź aktualny ETag, a po operacji sprawdź HTTP 404.

Tak przygotowany przepływ pozwala synchronizować problemy i ich analizę z innym systemem bez opierania integracji na wewnętrznej strukturze bazy. Jeśli zmieni się konfiguracja pól, adres instalacji lub zakresy klucza, ponownie odczytaj kontekst i schema.