Zasoby w Codenica API

Poniżej znajdziesz praktyczne przykłady pracy z zasobami przechowywanymi w systemie Codenica. W Public API techniczna nazwa tego obiektu to assets. Pojedynczy zasób może przedstawiać między innymi komputer, urządzenie, program, licencję albo inny element ewidencji dostępny w Twojej bazie.

Zanim wykonasz pierwsze żądanie, przygotuj klucz API opisany w artykule Codenica API - wprowadzenie. Dalej znajdziesz pełną obsługę zasobów: od sprawdzenia schematu i listowania, przez tworzenie i edycję, aż po relacje, pliki, operacje batch i usuwanie.

  • odczyt pojedynczych zasobów i list z paginacją;
  • wyszukiwanie oraz filtrowanie po polach ewidencji;
  • tworzenie i częściowa edycja rekordów;
  • ochrona zmian przez ETag oraz bezpieczne ponawianie przez Idempotency-Key;
  • relacje z innymi zasobami i obiektami Codenica;
  • upload, pobieranie, podpinanie i usuwanie plików;
  • statystyki, wartości pól oraz przetwarzanie wielu operacji w jednym żądaniu.

Przykłady używają itemType=computer. Nie każda baza ma taki sam zestaw pól. Przed zapisem pobierz schemat dla typu, z którym pracujesz.


Zasoby - adres API i wybór instalacji

Żądania kieruj do publicznego adresu, pod którym dostępna jest Twoja instalacja Codenica. Nie używaj adresu samej bazy danych, kontenera ani portu dostępnego wyłącznie wewnątrz serwera. Ścieżki dla zasobów zaczynają się od:

{BASE_URL}/api/v1/assets

W Codenica Cloud użyj publicznej domeny przypisanej do Twojej 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śli administrator wystawił instalację On-Premise przez firmową domenę, reverse proxy, HTTPS albo inny port zewnętrzny, użyj dokładnego adresu przekazanego dla tej instalacji:

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

Nie próbuj wybierać bazy przez dodatkowe pole w query stringu ani w body. Właściwa baza jest wybierana na podstawie adresu hosta. Nie używaj localhost, jeśli program integrujący działa na innym komputerze niż API. W produkcji korzystaj z HTTPS, gdy instalacja jest opublikowana z certyfikatem.


Zasoby - zakresy klucza API

Klucz API utwórz w systemie Codenica w Ustawienia - API - API Keys. Dla integracji pracującej z zasobami wybierz tylko potrzebne zakresy. Dostęp do API nie rozszerza uprawnień użytkownika, dla którego utworzono klucz, ani dostępu do danych ustawionego w Twojej bazie.

Podstawowe zakresy dla zasobów:

  • assets:read - listowanie i odczyt zasobów;
  • assets:write - tworzenie oraz edycja zasobów;
  • assets:delete - usuwanie zasobów;
  • assets:schema - odczyt pól, ich właściwości i celów relacji;
  • assets:stats - statystyki oraz wartości pól używane przy filtrowaniu;
  • assets:relationships:read - odczyt relacji;
  • assets:relationships:write - dodawanie i usuwanie relacji;
  • assets:files:read - listowanie i pobieranie plików;
  • assets:files:write - przesyłanie, podpinanie, ustawianie głównego pliku i usuwanie plików;
  • assets:technical:read - odczyt pól oznaczonych jako techniczne;
  • assets:technical:write - zapis zapisywalnych pól technicznych;
  • assets:secrets:write - zapis pól sekretów, jeśli dany schemat je udostępnia.

Pola techniczne i sekretowe nie są potrzebne do zwykłego odczytu lub aktualizacji danych ewidencyjnych. Sekrety są zapisywane tylko przy odpowiednim zakresie i nie są zwracane w odpowiedziach.

Po utworzeniu skopiuj Client ID i Client Secret do bezpiecznego magazynu aplikacji integrującej. Sekret jest pokazywany tylko podczas utworzenia lub rotacji klucza. Zewnętrzna aplikacja używa tych dwóch wartości, a nie sesji panelu ani Bearer JWT.


Zasoby - uwierzytelnianie i kontekst

Każde żądanie wykonuj z dwoma nagłówkami klucza API:

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

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"

Przed rozpoczęciem właściwej integracji odczytaj /api/v1/context. Sprawdź, czy odpowiedź dotyczy właściwej bazy, czy caller ma authentication równe api_key, a lista scope'ów zawiera wymagane operacje.

W obiekcie capabilities potwierdź obecność assets oraz odczytaj limity, między innymi maxPageSize, maxUploadBytes i limit żądań. Zachowaj meta.requestId. Ten identyfikator ułatwia znalezienie konkretnego żądania w logach lub podczas kontaktu z administratorem.

Jeżeli kontekst wskazuje inną bazę lub nie zawiera potrzebnego zakresu, zatrzymaj integrację i popraw konfigurację klucza albo adresu API. Nie próbuj zmieniać bazy przez dane wysyłane w body.


Zasoby - schemat pól i relacji

Schemat pokazuje, co można odczytać i zapisać w używanej bazie. Pobierz go dla używanego typu zasobu:

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

W odpowiedzi sprawdź dla każdego pola między innymi:

  • nazwę i typ danych;
  • readable oraz writable;
  • required;
  • technical i ewentualne secretWriteOnly;
  • wartości options;
  • maksymalną długość i unikalność;
  • autogenerowanie oraz dodatkowe wymagania bazy.

Schemat może różnić się zależnie od itemType i konfiguracji ewidencji. Dla przykładu pole category może przyjmować inne wartości w dwóch różnych bazach. Nie buduj integracji na założeniu, że lista pól lub opcji jest stała.

Schemat zawiera także katalog celów relacji. Przed wysłaniem relacji sprawdź, czy wybrany typ obiektu, jego targetItemType i rodzaj relacji są zgodne z odpowiedzią.


Zasoby - dostępne endpointy

Poniższa mapa pokazuje główne ścieżki używane przez integrację. Zastąp {id}, {targetDataSet}, {targetId} i {fileId} właściwymi identyfikatorami.

  • GET /api/v1/assets - lista zasobów;
  • GET /api/v1/assets/schema - schemat;
  • GET /api/v1/assets/stats - statystyki;
  • GET /api/v1/assets/values - wartości pól;
  • GET /api/v1/assets/{id} - pojedynczy zasób;
  • POST /api/v1/assets - utworzenie;
  • PATCH /api/v1/assets/{id} - częściowa edycja;
  • DELETE /api/v1/assets/{id} - usunięcie;
  • POST /api/v1/assets:batch - operacje create, update i delete;
  • GET /api/v1/assets/{id}/relationships - lista relacji;
  • POST /api/v1/assets/{id}/relationships - dodanie relacji;
  • POST /api/v1/assets/{id}/relationships:batch - grupowa zmiana relacji;
  • DELETE /api/v1/assets/{id}/relationships/{targetDataSet}/{targetId} - usunięcie relacji;
  • GET /api/v1/assets/{id}/files - lista plików;
  • POST /api/v1/assets/{id}/files - upload pliku;
  • POST /api/v1/assets/{id}/files/{fileId} - podpięcie istniejącego pliku;
  • PUT /api/v1/assets/{id}/files/{fileId}/main - ustawienie głównego pliku;
  • DELETE /api/v1/assets/{id}/files/{fileId} - usunięcie pliku;
  • GET /api/v1/assets/{id}/files/{fileId}/content - pobranie treści pliku.

Zakres potrzebny do każdej ścieżki wynika z nazwy operacji. Jeżeli otrzymasz 403, najpierw sprawdź scope klucza i uprawnienia użytkownika przypisanego do klucza.


Zasoby - listowanie i paginacja

Listę pobieraj stronicami. Przykładowe żądanie zwraca pierwsze dwadzieścia widocznych zasobów typu computer:

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

Odpowiedź kolekcji ma strukturę podobną do:

{
  "data": {
    "items": [
      {
        "id": "11111111-1111-1111-1111-111111111111",
        "itemType": "computer",
        "attributes": {
          "customId": "CND-OFFICE-PC-01",
          "name": "Komputer biurowy 01",
          "category": "Hardware"
        },
        "meta": {
          "dateUpdated": "2026-09-07T10:00:00Z",
          "etag": "\"etag-v1\""
        }
      }
    ],
    "page": 1,
    "pageSize": 20,
    "totalItems": 1,
    "totalPages": 1,
    "hasNextPage": false
  },
  "meta": {
    "requestId": "request-id-from-response"
  }
}

Nie zakładaj, że pierwsza strona zawiera wszystkie dane. Kontynuuj pobieranie, dopóki hasNextPage jest równe true, albo korzystaj z totalPages. Nie ustawiaj pageSize wyższego niż limit zwrócony w kontekście.


Zasoby - wyszukiwanie i filtry

Do prostego wyszukiwania użyj search, a do dokładniejszego wyboru pól użyj parametrów skróconych lub parametru filter:

curl --request GET --url "$BASE_URL/api/v1/assets?itemType=computer&search=office&page=1&pageSize=50" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

curl --request GET --url "$BASE_URL/api/v1/assets?customId=CND-OFFICE-PC-01" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

curl --request GET --url "$BASE_URL/api/v1/assets?filter=category:contains:Hardware" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Możesz używać między innymi parametrów itemType, ids, search, name, category, status, location, department, manufacturer, model, serialNumber, inventoryNumber, customId, tag, createdAfter, createdBefore, updatedAfter i updatedBefore.

Parametr filter obsługuje między innymi operatory:

  • eq - równe;
  • ne - różne;
  • in - jedna z podanych wartości;
  • contains - zawiera fragment;
  • startsWith i endsWith - zaczyna lub kończy się podanym tekstem;
  • empty i notEmpty - pole puste lub niepuste;
  • gt, gte, lt, lte - porównania.
filter=status:eq:In service
filter=serialNumber:contains:ABC
filter=category:in:Hardware,Software
filter=description:notEmpty:

Jeżeli wartość zawiera spacje lub znaki specjalne, zakoduj ją zgodnie z zasadami URL. Przy filtrowaniu po identyfikatorach pamiętaj, że ids ogranicza wynik do wskazanych UUID.


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

Parametr fields ogranicza pola zwracane w odpowiedzi. Jest przydatny, gdy integracja potrzebuje tylko kilku wartości:

curl --request GET --url "$BASE_URL/api/v1/assets?fields=id,itemType,name,category,status" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Do odczytu danych powiązanych użyj include. Dla zasobów dostępne są files i relationships:

curl --request GET --url "$BASE_URL/api/v1/assets/$ASSET_ID?include=files,relationships" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Zakres odczytu dołączonych danych musi być dopuszczony przez odpowiednie scope'y. Jeśli klucz nie ma assets:files:read albo assets:relationships:read, pobierz sam rekord bez danego include lub rozszerz klucz zgodnie z zasadą najmniejszych uprawnień.

fields=* nie ujawnia pól sekretów. Nie traktuj wyboru pól jako sposobu na obejście uprawnień. Pola techniczne i sekretowe pojawią się tylko wtedy, gdy pozwalają na to scope'y oraz schemat.


Zasoby - utworzenie rekordu

Do utworzenia użyj POST /api/v1/assets. W body podaj techniczny typ itemType oraz zapisywalne pola w obiekcie attributes. W poniższym przykładzie tworzony jest komputer biurowy:

export IDEMPOTENCY_KEY="asset-create-20260907-0001"

curl --request POST --url "$BASE_URL/api/v1/assets" \
  --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": "computer",
    "attributes": {
      "customId": "CND-OFFICE-PC-01",
      "name": "Komputer biurowy 01",
      "category": "Hardware",
      "manufacturer": "Lenovo",
      "model": "ThinkCentre",
      "location": "Warszawa",
      "status": "In service"
    }
  }'

W podstawowym modelu wymagane są co najmniej name i category, ale Twoja baza może mieć dodatkowe wymagania, wartości wyboru lub reguły unikalności. Zawsze porównaj body ze schematem.

Poprawna odpowiedź ma status 201 Created. Zapisz data.id, data.meta.etag oraz nagłówek HTTP ETag. Przykładowy fragment odpowiedzi:

{
  "data": {
    "id": "11111111-1111-1111-1111-111111111111",
    "itemType": "computer",
    "attributes": {
      "customId": "CND-OFFICE-PC-01",
      "name": "Komputer biurowy 01",
      "category": "Hardware"
    },
    "meta": {
      "customId": "CND-OFFICE-PC-01",
      "dateCreated": "2026-09-07T10:00:00Z",
      "dateUpdated": "2026-09-07T10:00:00Z",
      "etag": "\"etag-v1\""
    }
  },
  "meta": {
    "requestId": "request-id-from-response",
    "etag": "\"etag-v1\""
  }
}

Nie wysyłaj własnego id, chyba że schemat i integracja wymagają kontrolowanego UUID. Jeśli używasz własnego identyfikatora, musi być nieużywany i zgodny z wymaganiami API.


Zasoby - bezpieczne ponowienie tworzenia

Po timeoutcie możesz nie wiedzieć, czy serwer zdążył utworzyć rekord. Nie twórz wtedy nowego klucza idempotencji na ślepo. Wyślij dokładnie to samo żądanie z tym samym Idempotency-Key i identycznym body:

curl --request POST --url "$BASE_URL/api/v1/assets" \
  --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": "computer",
    "attributes": {
      "customId": "CND-OFFICE-PC-01",
      "name": "Komputer biurowy 01",
      "category": "Hardware",
      "manufacturer": "Lenovo",
      "model": "ThinkCentre",
      "location": "Warszawa",
      "status": "In service"
    }
  }'

Powtórzenie identycznej operacji odtworzy pierwszą odpowiedź i nie utworzy drugiego rekordu. Ten sam klucz nie może później opisywać innego body, innego endpointu ani innej intencji. Próba użycia go w taki sposób zwróci 422 idempotency_key_reused.

Idempotencja dotyczy także pozostałych żądań modyfikujących: edycji, zmian relacji, operacji na plikach i usuwania. Dla każdej nowej intencji użyj nowej wartości klucza.


Zasoby - odczyt pojedynczego rekordu

Po utworzeniu lub znalezieniu zasobu pobierz go po UUID:

export ASSET_ID="11111111-1111-1111-1111-111111111111"

curl --request GET --url "$BASE_URL/api/v1/assets/$ASSET_ID?include=files,relationships" \
  --header "Accept: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Odpowiedź zawiera id, techniczny itemType, pola w attributes oraz metadane w meta. Wartość ETag znajdziesz w nagłówku HTTP i zwykle także w data.meta.etag oraz kopercie meta.etag.

Przed każdą zmianą zasobu pobierz go ponownie. Dotyczy to edycji pól, relacji, uploadu, zmiany głównego pliku, usunięcia pliku i usunięcia całego rekordu. Dzięki temu operacja odnosi się do aktualnej wersji, a nie do wartości zapisanej wcześniej w pamięci integracji.


Zasoby - edycja częściowa z ETagiem

PATCH zmienia tylko pola przesłane w body. Nie musisz wysyłać całego rekordu. Do żądania dodaj świeży ETag z ostatniego odczytu oraz nowy klucz idempotencji:

export ASSET_ETAG='"etag-v1"'
export IDEMPOTENCY_KEY="asset-update-20260907-0001"

curl --request PATCH --url "$BASE_URL/api/v1/assets/$ASSET_ID" \
  --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" \
  --header "If-Match: $ASSET_ETAG" \
  --data-raw '{
    "attributes": {
      "name": "Komputer biurowy 01 - aktualizacja",
      "description": "zasób zaktualizowany przez integrację."
    }
  }'

Po sukcesie odpowiedź ma status 200 OK i zawiera nowy ETag. Zastąp nim poprzednią wartość przed kolejną operacją. Wysłanie null czyści pole, o ile pole nie jest wymagane i schemat dopuszcza pustą wartość.

Body musi zawierać rzeczywistą zmianę zapisywalnego pola, wartości niestandardowej albo relacji. Pole tylko do odczytu, techniczne lub sekretowe może wymagać osobnego zakresu albo endpointu.


Zasoby - ochrona przed nieaktualną wersją

ETag chroni rekord przed nadpisaniem zmian wykonanych w międzyczasie przez inną osobę lub integrację. Dwa scenariusze wymagają osobnej obsługi:

  • 428 if_match_required - brakuje wymaganego If-Match albo, w mutacji, Idempotency-Key;
  • 412 if_match_failed - przesłany ETag nie jest już aktualny.

Przykład odpowiedzi dla starego ETag-u:

{
  "type": "https://docs.codenica.com/errors/if_match_failed",
  "title": "Precondition failed.",
  "status": 412,
  "detail": "The supplied ETag is not the current asset version.",
  "instance": "/api/v1/assets/11111111-1111-1111-1111-111111111111",
  "code": "if_match_failed",
  "requestId": "request-id-from-response"
}

Po 412 pobierz zasób ponownie, porównaj aktualne wartości ze zmianą, którą chcesz wykonać, i dopiero wtedy wyślij nowy PATCH z nowym ETagiem. Nie ponawiaj bez końca tego samego żądania ze starym ETagiem. Konkretne If-Match jest zalecanym sposobem pracy integracji. Gwiazdka * jest scenariuszem kontrolowanym i nie powinna zastępować kontroli wersji w zwykłej synchronizacji.


Zasoby - dodawanie relacji

Relacja łączy zasób z innym widocznym obiektem. Dostępne cele obejmują:

assets, clients, documents, tickets, changes, problems, releases,
notes, worktasks, confirmations, requesteditems

Przykład łączy dwa komputery. Jeśli wysyłasz targetItemType, musi on odpowiadać rzeczywistemu typowi celu:

export TARGET_ASSET_ID="22222222-2222-2222-2222-222222222222"
export IDEMPOTENCY_KEY="asset-relation-add-20260907-0001"

curl --request POST --url "$BASE_URL/api/v1/assets/$ASSET_ID/relationships" \
  --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" \
  --header "If-Match: $ASSET_ETAG" \
  --data-raw '{
    "targetId": "22222222-2222-2222-2222-222222222222",
    "targetDataSet": "assets",
    "targetItemType": "computer",
    "relationshipType": "related"
  }'

Target musi istnieć i być widoczny dla użytkownika przypisanego do klucza. zasób nie może wskazywać samego siebie. W zależności od celu API może przechowywać relationshipType. Dla notes, worktasks i requesteditems tego pola nie wysyłaj, ponieważ aktualny model tych relacji go nie przechowuje.

Dodanie relacji zmienia wersję zasobu źródłowego. Po odpowiedzi 201 Created pobierz źródło ponownie i użyj nowego ETag-u przy następnej zmianie.


Zasoby - odczyt i usuwanie relacji

Relacje odczytuj przez kolekcję, opcjonalnie ograniczając wynik do wybranego zbioru celów:

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

Element relacji może zawierać między innymi targetId, targetDataSet, targetItemType, relationshipType, customId i name. Przy odczycie relacji nie otrzymujesz pełnego obiektu docelowego, jeśli nie korzystasz z osobnego odczytu lub include=relationships.

Do usunięcia relacji potrzebujesz świeżego ETag-u źródła:

export IDEMPOTENCY_KEY="asset-relation-delete-20260907-0001"

curl --request DELETE --url "$BASE_URL/api/v1/assets/$ASSET_ID/relationships/assets/$TARGET_ASSET_ID?relationshipType=related" \
  --header "Accept: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "Idempotency-Key: $IDEMPOTENCY_KEY" \
  --header "If-Match: $ASSET_ETAG"

Poprawne usunięcie zwraca 200 OK z data: true. Jeśli usuwasz relację bezpośrednim endpointem, wartość relationshipType w query musi odpowiadać relacji, którą chcesz usunąć. Po operacji ponownie odczytaj kolekcję i zasób źródłowy.


Zasoby - grupowa zmiana relacji

Jeżeli chcesz dodać lub usunąć kilka relacji, użyj relationships:batch. W jednym żądaniu możesz przekazać tablice add i remove:

export IDEMPOTENCY_KEY="asset-relations-batch-20260907-0001"

curl --request POST --url "$BASE_URL/api/v1/assets/$ASSET_ID/relationships:batch" \
  --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" \
  --header "If-Match: $ASSET_ETAG" \
  --data-raw '{
    "add": [
      {
        "targetId": "22222222-2222-2222-2222-222222222222",
        "targetDataSet": "assets",
        "targetItemType": "computer",
        "relationshipType": "related"
      }
    ],
    "remove": [
      {
        "targetId": "33333333-3333-3333-3333-333333333333",
        "targetDataSet": "clients",
        "relationshipType": "owner"
      }
    ]
  }'

Odpowiedź 200 OK zawiera liczniki added, removed i skipped. Ponowienie relacji już istniejącej może zostać policzone jako skipped. Batch relacji również zmienia ETag źródła, dlatego po operacji pobierz zasób ponownie.

W elementach dotyczących notes, worktasks i requesteditems pomiń relationshipType. Każdy cel musi być widoczny i zgodny z katalogiem relacji z odpowiedzi schematu.


Zasoby - lista i upload plików

Pliki są przechowywane obok zasobu i mają własny identyfikator. Najpierw możesz sprawdzić bieżącą listę:

curl --request GET --url "$BASE_URL/api/v1/assets/$ASSET_ID/files?page=1&pageSize=50" \
  --header "Accept: application/json" \
  --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 i downloadUrl.

Upload używa multipart/form-data. Do zmiany zasobu potrzebujesz świeżego ETag-u oraz nowego klucza idempotencji:

curl --request POST --url "$BASE_URL/api/v1/assets/$ASSET_ID/files?makeMain=true&relationshipType=documentation" \
  --header "Accept: application/json, application/problem+json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "Idempotency-Key: asset-file-upload-20260907-0001" \
  --header "If-Match: $ASSET_ETAG" \
  --form "file=@./asset-manual.txt;type=text/plain"

makeMain=true ustawia przesłany plik jako główny. Parametr relationshipType opisuje przeznaczenie pliku, na przykład documentation albo manual. Domyślny limit uploadu wynosi 20 MiB, ale sprawdź aktualną wartość maxUploadBytes w kontekście.

Nazwa pliku nie może zawierać ścieżki ani segmentu ... Nie zapisuj sekretów w nazwie pliku, jego metadanych ani treści, jeśli nie jest to konieczne.

Upload ma status 201 Created i zwraca obiekt pliku. Po zakończeniu pobierz zasób ponownie, ponieważ jego ETag zmienił się.


Zasoby - pobieranie i wybór głównego pliku

Treść pliku pobieraj przez endpoint /content. Odpowiedź jest treścią binarną, a nie kopertą JSON:

export FILE_ID="44444444-4444-4444-4444-444444444444"

curl --request GET --url "$BASE_URL/api/v1/assets/$ASSET_ID/files/$FILE_ID/content" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --output ./asset-file-download.txt

W obiekcie pliku downloadUrl jest względnym adresem. Dołącz do niego host wdrożenia i użyj tych samych nagłówków uwierzytelniających.

Jeśli zasób ma kilka plików, możesz wybrać plik główny. Operacja modyfikuje zasób i wymaga aktualnego ETag-u:

curl --request PUT --url "$BASE_URL/api/v1/assets/$ASSET_ID/files/$FILE_ID/main" \
  --header "Accept: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "Idempotency-Key: asset-set-main-20260907-0001" \
  --header "If-Match: $ASSET_ETAG"

Poprawna odpowiedź ma status 200 OK i zwykle zwraca data: true. Po zmianie pobierz listę plików i sprawdź, że wybrany element ma isMain=true, a poprzedni plik główny ma isMain=false. Następnie odczytaj nowy ETag zasobu.

Mały plik może być zaokrąglony w interfejsie do 0 MB. Rzeczywisty rozmiar sprawdzaj w polu size albo po liczbie pobranych bajtów.


Zasoby - podpinanie istniejącego pliku

Jeśli plik jest już zapisany w systemie, możesz podłączyć go do kolejnego zasobu bez ponownego przesyłania treści:

export TARGET_ASSET_ID="55555555-5555-5555-5555-555555555555"
export TARGET_ASSET_ETAG='"target-etag-v1"'

curl --request POST --url "$BASE_URL/api/v1/assets/$TARGET_ASSET_ID/files/$FILE_ID?makeMain=true&relationshipType=manual" \
  --header "Accept: application/json, application/problem+json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "Idempotency-Key: asset-attach-file-20260907-0001" \
  --header "If-Match: $TARGET_ASSET_ETAG"

Odpowiedź 201 Created zawiera identyfikator podłączonego pliku i jego metadane. Jeśli użyto makeMain=true, sprawdź w kolejnym odczycie, że isMain jest ustawione na true.

Podpięcie również zmienia wersję docelowego zasobu. Przed kolejną zmianą pliku pobierz aktualny ETag celu. Usunięcie pliku z jednego zasobu wykonuj dopiero wtedy, gdy masz pewność, że nie jest już potrzebny w tym miejscu ani w pozostałych relacjach.


Zasoby - usunięcie pliku

Usunięcie pliku jest operacją modyfikującą zasób. Pobierz aktualny ETag i użyj osobnego klucza idempotencji:

curl --request DELETE --url "$BASE_URL/api/v1/assets/$ASSET_ID/files/$FILE_ID" \
  --header "Accept: application/json, application/problem+json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "Idempotency-Key: asset-file-delete-20260907-0001" \
  --header "If-Match: $ASSET_ETAG"

Poprawna odpowiedź ma status 200 OK i data: true. Po każdym usunięciu pobierz ponownie listę plików oraz ETag zasobu. Jeżeli usuwasz kilka plików, ETag do następnej operacji musi pochodzić z poprzedniej, już zakończonej zmiany.

Usunięcie pliku nie usuwa całego zasobu. Próba pobrania usuniętej treści zwraca błąd 404 file_not_found. W przypadku pliku podpiętego do kilku zasobów przed usunięciem sprawdź, czy operacja dotyczy właściwego powiązania i czy plik nie jest nadal potrzebny.


Zasoby - statystyki i wartości pól

Endpoint stats pomaga zbudować podsumowanie widocznych danych. Możesz ograniczyć wynik do typu zasobu i wskazać pole, dla którego chcesz otrzymać wartości:

curl --request GET --url "$BASE_URL/api/v1/assets/stats?itemType=computer&field=category&limit=20" \
  --header "Accept: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Odpowiedź może zawierać łączną liczbę widocznych zasobów, podział według itemType, nazwę pola oraz wartości:

{
  "data": {
    "total": 11,
    "byItemType": {
      "computer": 11
    },
    "field": "category",
    "values": [
      "Laptop",
      "Desktop",
      "Hardware"
    ]
  },
  "meta": {
    "requestId": "request-id-from-response"
  }
}

Endpoint values zwraca wartości przydatne do budowania list filtrów:

curl --request GET --url "$BASE_URL/api/v1/assets/values?field=category&itemType=computer&search=hard&limit=20" \
  --header "Accept: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Dla wyszukiwania hard wynik może zawierać Hardware. Oba endpointy są odczytowe, wymagają assets:stats i nie wymagają ETag-u. Wyniki obejmują tylko dane widoczne dla użytkownika.


Zasoby - operacje batch

Batch pozwala połączyć tworzenie, aktualizację i usuwanie w jednym żądaniu. Każdy element ma własną operację, a update i delete przekazują własny ETag w polu ifMatch:

curl --request POST --url "$BASE_URL/api/v1/assets:batch" \
  --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: assets-batch-20260907-0001" \
  --data-raw '{
    "items": [
      {
        "operation": "create",
        "create": {
          "itemType": "computer",
          "attributes": {
            "customId": "CND-BATCH-PC-01",
            "name": "Komputer utworzony zbiorczo",
            "category": "Hardware"
          }
        }
      },
      {
        "operation": "update",
        "id": "11111111-1111-1111-1111-111111111111",
        "ifMatch": "\"current-etag\"",
        "update": {
          "attributes": {
            "description": "Opis zaktualizowany w batch."
          }
        }
      },
      {
        "operation": "delete",
        "id": "22222222-2222-2222-2222-222222222222",
        "ifMatch": "\"current-etag\""
      }
    ]
  }'

Jeżeli wszystkie elementy zakończą się sukcesem, odpowiedź ma status 200 OK. Wynik zawiera liczniki succeeded, failed oraz rezultat każdego elementu z jego index, operation i status.

Batch nie jest transakcją all-or-nothing. Przy częściowym sukcesie API zwraca 207 Multi-Status, a poprawnie wykonane elementy nie są cofane. Sprawdź wynik każdej pozycji. Jeśli batch zawiera nowe rekordy, zapisz ich ID i ETag zwrócone w poszczególnych wynikach.

Każda pozycja wymaga scope'u odpowiadającego jej operacji. Jedno żądanie batch nie rozszerza uprawnień klucza.


Zasoby - usunięcie rekordu

Przed usunięciem pobierz zasób ponownie i użyj jego aktualnego ETag-u:

export IDEMPOTENCY_KEY="asset-delete-20260907-0001"

curl --request DELETE --url "$BASE_URL/api/v1/assets/$ASSET_ID" \
  --header "Accept: application/json, application/problem+json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "Idempotency-Key: $IDEMPOTENCY_KEY" \
  --header "If-Match: $ASSET_ETAG"

Poprawne usunięcie zwraca 200 OK z data: true. Kolejny odczyt UUID zwróci 404 asset_not_found. Usunięcie uruchamia istniejące czyszczenie domenowe, ale Public API nie usuwa automatycznie powiązanych obiektów biznesowych, takich jak dokumenty, zgłoszenia lub klienci.

Po usunięciu usuń identyfikator z lokalnego indeksu integracji albo oznacz rekord jako nieaktywny. Nie próbuj ponownie aktualizować usuniętego UUID-u.


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

Błędy API używają formatu Problem Details z dodatkowymi polami Codenica:

{
  "type": "https://docs.codenica.com/errors/asset_not_found",
  "title": "Asset not found.",
  "status": 404,
  "detail": "The asset does not exist or is outside the caller's access scope.",
  "instance": "/api/v1/assets/11111111-1111-1111-1111-111111111111",
  "code": "asset_not_found",
  "requestId": "request-id-from-response"
}

W logice aplikacji używaj przede wszystkim status i code. Tekst detail jest wskazówką dla człowieka i może się zmienić.

  • 400 - nieprawidłowe body, parametr lub wartość pola;
  • 401 - brak lub nieprawidłowe uwierzytelnienie;
  • 403 - brak scope'u albo uprawnień użytkownika;
  • 404 - zasób, plik lub cel relacji nie istnieje albo jest niewidoczny;
  • 409 - konflikt danych lub stanu domenowego;
  • 412 - nieaktualny ETag;
  • 413 - zbyt duży upload lub body;
  • 428 - wymagany ETag albo Idempotency-Key;
  • 429 - przekroczony limit żądań;
  • 500 lub 503 - błąd serwera albo chwilowa niedostępność.

Odczytuj nagłówki X-RateLimit-Limit, X-RateLimit-Remaining i, przy 429, Retry-After. Stosuj kontrolowane ponowienia z rosnącym opóźnieniem. Nigdy nie zapisuj Client Secret w repozytorium, URL-u, kodzie dostarczanym do przeglądarki, historii poleceń ani logach.


Zasoby - kompletny przebieg integracji

  1. Ustal właściwy adres API. W On-Premise sprawdź, czy integracja może dotrzeć do adresu http://codenica.local:5150 albo do adresu opublikowanego przez administratora.
  2. Utwórz osobny klucz API dla tej integracji i wybierz minimalne zakresy.
  3. Zapisz Client ID i Client Secret w bezpiecznym magazynie.
  4. Wyślij GET /api/v1/context i sprawdź, czy odpowiedź dotyczy właściwej bazy, a także sprawdź caller, scope'y oraz limity.
  5. Wyślij GET /api/v1/assets/schema?itemType=computer i dopasuj body do aktualnych pól.
  6. Pobierz listę z paginacją, wyszukiwaniem lub filtrami.
  7. Utwórz zasób przez POST z nowym Idempotency-Key.
  8. Zapisz UUID i ETag.
  9. Przed każdą zmianą odczytaj aktualny rekord.
  10. Wykonuj edycję, relacje, operacje plikowe i usuwanie z konkretnym ETagiem oraz nowym kluczem idempotencji.
  11. Po każdej udanej mutacji zapisz nowy ETag i w razie potrzeby odczytaj wynik ponownie.
  12. Po 412 odczytaj rekord, rozstrzygnij konflikt i dopiero wtedy ponów operację.
  13. Przy większej liczbie zmian użyj batch, ale sprawdź status każdego elementu, ponieważ batch nie jest transakcją.
  14. Obsłuż 429 i nie loguj sekretów.
  15. Usuń klucz API, gdy integracja nie jest już używana.

Tak przygotowana integracja może korzystać z danych ewidencji bez uzależniania się od wewnętrznej struktury bazy. Gdy konfiguracja pól, uprawnień lub adres wdrożenia się zmieni, ponownie odczytaj kontekst i schemat zamiast opierać działanie na dawnych założeniach.