Notatki w Codenica API

Pracę z notatkami 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 notes, a typ pojedynczego obiektu to note. Notatka jest wpisem zapisanym w systemie Codenica. Może zawierać tytuł, opis, status, priorytet, kategorię, odnośnik i pliki. Flaga isPrivate określa widoczność zgodnie z istniejącymi uprawnieniami, a pin służy do przypięcia wpisu na określonym poziomie.

W kolejnych krokach znajdziesz adres, zakresy, context, schema, pola, listy, filtrowanie, tworzenie, idempotencję, ETag, edycję, pinowanie, relacje, autora, pliki, operacje batch oraz usuwanie.

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


Notatki - adres API i wybór instalacji

Wszystkie trasy dotyczące notatek zaczynają się od:

{BASE_URL}/api/v1/notes

BASE_URL oznacza adres serwera Codenica bez końcówki /api/v1. W wersji Cloud użyj publicznej domeny przypisanej do właściwej firmy:

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. Właściwa baza danych jest wybierana na podstawie adresu, z którym łączy się integracja. Nie przekazuj tenantId w body ani w query stringu.


Notatki - 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
Dostęp do API
Maksymalna liczba aktywnych kluczy
Starter
Brak
0
Plus
Tak
50
Enterprise
Tak
100

Usunięcie klucza usuwa jego rekord i zwalnia miejsce w limicie. Wygaśnięcie daty aktywności zatrzymuje uwierzytelnianie, ale nie zastępuje porządkowania listy kluczy. Jeżeli przy tworzeniu nie ustawisz daty końcowej, domyślny okres ważności wynosi 90 dni. Maksymalny czas aktywności jednego klucza to 5 lat.


Notatki - 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/notes?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 notatki i nie powinien być używany jako sekret.


Notatki - 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ść notes w data.capabilities.resources;
  • zakresy przypisane do klucza;
  • limity stron, relacji, 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.


Notatki - zakresy uprawnień

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

notes:read
notes:write
notes:delete
notes:schema
notes:stats
notes:relationships:read
notes:relationships:write
notes:users:read
notes:files:read
notes:files:write
notes:technical:read
notes:technical:write
notes:pin:write

Do zwykłego odczytu wystarczą notes:read i, jeżeli chcesz pobierać aktualny katalog pól, notes:schema. Przy tworzeniu, edycji i usuwaniu dodaj odpowiednio notes:write i notes:delete.

  • notes:relationships:read i notes:relationships:write dotyczą relacji obiektowych;
  • notes:users:read dotyczy odczytu autora;
  • notes:files:read i notes:files:write dotyczą listowania, pobierania, wysyłania, podłączania i usuwania plików;
  • notes:stats dotyczy statystyk i wartości używanych w filtrach;
  • notes:pin:write jest potrzebny do przypinania i odpinania;
  • zakresy techniczne stosuj tylko wtedy, gdy integracja korzysta z pól oznaczonych w schema jako techniczne albo z reguł customValues.

Jeżeli integracja sama wyszukuje cele relacji, przydziel także odpowiednie zakresy odczytu, na przykład assets:read, clients:read, vendors:read, documents:read, tickets:read, changes:read, problems:read, releases:read, approvals:read, confirmations:read, worktasks:read i requesteditems:read. Zakres klucza nie zastępuje uprawnień użytkownika ani dostępu do lokalizacji i działu.


Notatki - schema i pola

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/notes/schema" \
  --header "Accept: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Schema zwraca między innymi data.itemType, data.fields i data.relationshipTargets. Stała wartość itemType dla tego modułu to note. Dla każdego pola sprawdź readable, writable, required, technical, unique i maxLength. Nie buduj mapowania wyłącznie na podstawie przykładu z tego artykułu, ponieważ konfiguracja pól może różnić się między bazami.

W schemacie znajdziesz także informację, czy możesz używać relacji z danym zbiorem. Używaj tylko celów zwróconych dla aktualnego klucza i użytkownika.


Notatki - pola zapisywalne i systemowe

Publiczny katalog pól biznesowych Notatki obejmuje:

customId
location
department
isPrivate
tag
link
title
status
priority
category
description

Najważniejsze ograniczenia pól:

Pole
Typ
Maksymalna długość
customId
string
500
location, department
string
300 każde
isPrivate
boolean
-
tag, link
string
2000 każde
title
string
1000
status, priority, category
string
300 każde
description
string
10000

pin jest zwracane w atrybutach, ale nie można go zmieniać przez attributes. Do tego służy osobny endpoint. Pola systemowe i techniczne tylko do odczytu to między innymi:

id
itemType
pin
creator
updater
dateCreated
dateUpdated
importId
importSource
dateImported

id i itemType są częścią zasobu, a daty, autor i edytor są ustalane przez system. Nie próbuj zmieniać ich przez attributes.


Notatki - podstawowe endpointy

Najważniejsze trasy modułu notes to:

GET    /api/v1/notes
POST   /api/v1/notes
GET    /api/v1/notes/{NOTE_ID}
PATCH  /api/v1/notes/{NOTE_ID}
DELETE /api/v1/notes/{NOTE_ID}
GET    /api/v1/notes/schema
GET    /api/v1/notes/stats
GET    /api/v1/notes/values
POST   /api/v1/notes:batch
GET    /api/v1/notes/{NOTE_ID}/relationships
POST   /api/v1/notes/{NOTE_ID}/relationships
POST   /api/v1/notes/{NOTE_ID}/relationships:batch
DELETE /api/v1/notes/{NOTE_ID}/relationships/{DATASET}/{TARGET_ID}
GET    /api/v1/notes/{NOTE_ID}/user-relationships
GET    /api/v1/notes/{NOTE_ID}/files
POST   /api/v1/notes/{NOTE_ID}/files
POST   /api/v1/notes/{NOTE_ID}/files/{FILE_ID}
DELETE /api/v1/notes/{NOTE_ID}/files/{FILE_ID}
GET    /api/v1/notes/{NOTE_ID}/files/{FILE_ID}/content
POST   /api/v1/notes/{NOTE_ID}/pin

Każda trasa wymaga uwierzytelnienia. Operacje zmieniające dane wymagają również Idempotency-Key, a operacje chronione wersją wymagają aktualnego If-Match. Konkretne wymagania sprawdzaj w odpowiedzi context i w schema.


Notatki - listowanie i paginacja

Lista jest stronicowana. Przykładowe żądanie pobiera pierwszą stronę i sortuje notatki od najnowszych:

curl --request GET --url "$BASE_URL/api/v1/notes?itemType=note&page=1&pageSize=20&sort=dateCreated&direction=desc" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

W odpowiedzi znajdziesz między innymi:

data.items
data.page
data.pageSize
data.totalItems
data.totalPages
data.hasNextPage

Maksymalny pageSize wynika z kontekstu i standardowo wynosi 100. Pobieraj kolejne strony, dopóki data.hasNextPage ma wartość true. Nie zakładaj, że liczba rekordów zwrócona na pierwszej stronie oznacza kompletną listę.


Notatki - wyszukiwanie, filtry i sortowanie

Do filtrów równościowych możesz użyć między innymi customId, location, department, isPrivate, tag, link, title, status, priority i category. Przykład wyszukania prywatnych otwartych notatek z działu IT:

curl --request GET --url "$BASE_URL/api/v1/notes?isPrivate=true&department=IT&status=Open&page=1&pageSize=50" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

search przeszukuje tekstowe pola notatki, między innymi customId, tag, link, title, status, priority, category i description:

curl --request GET --url "$BASE_URL/api/v1/notes?search=integracja&page=1&pageSize=20" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Parametr filter może wystąpić wielokrotnie. Format to field:operator:value:

filter=status:eq:Open
filter=status:ne:Closed
filter=title:contains:serwer
filter=title:startswith:Public API
filter=isPrivate:eq:true
filter=description:notempty:

Obsługiwane są między innymi operatory eq, ne, gt, gte, lt, lte, contains, startswith, endswith, empty i notempty. Dostępne są także skróty =, !=, ge, le, sw i ew. Możesz dodać zakresy createdAfter, createdBefore, updatedAfter i updatedBefore. Sortuj tylko po polu dopuszczonym przez schema, podając direction=asc albo direction=desc. Wartości zawierające spacje i znaki specjalne koduj w URL.


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

Jeżeli integracja potrzebuje tylko części danych, ogranicz odpowiedź przez fields:

curl --request GET --url "$BASE_URL/api/v1/notes?fields=customId%2Ctitle%2Cstatus%2Cpriority%2CisPrivate&page=1&pageSize=20" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Pojedynczą notatkę możesz pobrać razem z plikami, relacjami i informacją o autorze:

curl --request GET --url "$BASE_URL/api/v1/notes/{NOTE_ID}?fields=customId%2Ctitle%2Cdescription%2Cstatus&include=files%2Crelationships%2Cusers" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Dozwolone wartości include to files, relationships i users. Każda wymaga osobnego zakresu odczytu. fields=* pozwala zażądać wszystkich pól dostępnych dla klucza, ale pola techniczne pojawią się dopiero przy odpowiednim zakresie.


Notatki - statystyki i wartości pól

Statystyki służą do policzenia widocznych notatek i pogrupowania ich po wybranym polu:

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

Przykładowa odpowiedź:

{
  "data": {
    "total": 42,
    "field": "category",
    "values": [
      {
        "value": "Integration",
        "count": 12
      },
      {
        "value": "Hardware",
        "count": 8
      }
    ]
  },
  "meta": {
    "requestId": "request-id-from-response"
  }
}

Bez parametru field endpoint zwraca łączną liczbę notatek. limit przyjmuje wartości od 1 do 500. Wyniki respektują zakres widoczności użytkownika.

Endpoint values zwraca unikalne wartości przydatne do budowania list wyboru:

curl --request GET --url "$BASE_URL/api/v1/notes/values?field=status&search=Open&limit=20" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Przykładowa odpowiedź:

{
  "data": {
    "field": "status",
    "values": [
      "Open",
      "Open - waiting"
    ]
  },
  "meta": {
    "requestId": "request-id-from-response"
  }
}

Oba endpointy są odczytowe i nie zmieniają notatek. Odpowiedź values nie jest pełną listą rekordów, tylko listą unikalnych wartości konkretnego pola.


Notatki - tworzenie rekordu

Przy tworzeniu umieść techniczny typ note w body, a pola biznesowe w attributes. W praktycznej integracji warto zapisywać tytuł i opis, nawet jeśli schema konkretnej bazy nie oznacza ich jako wymaganych:

{
  "itemType": "note",
  "attributes": {
    "customId": "NOTE-ERP-2026-0001",
    "location": "Warsaw",
    "department": "IT",
    "isPrivate": true,
    "tag": "erp,public-api,notes",
    "link": "https://erp.example.com/notes/0001",
    "title": "Kontrola integracji serwera",
    "status": "Open",
    "priority": "Normal",
    "category": "Integration",
    "description": "Notatka utworzona przez zewnętrzny system ERP."
  }
}

Zapisz body jako note-create.json i wyślij je z unikalnym kluczem idempotencji:

curl --request POST --url "$BASE_URL/api/v1/notes" \
  --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: notes-create-20260905-0001" \
  --data-binary @note-create.json

Prawidłowe utworzenie zwraca 201 Created. Odpowiedź zawiera UUID w data.id, data.itemType=note, zapisane atrybuty, daty systemowe i data.meta.etag. Najbezpieczniej pozostawić nadanie id systemowi.

isPrivate jest flagą widoczności, a nie szyfrowaniem. Nie zapisuj w notatce haseł, tokenów, Client Secret ani innych poufnych danych.


Notatki - bezpieczne ponowienie tworzenia

Jeżeli klient nie wie, czy pierwsze żądanie dotarło, ponów dokładnie ten sam request z tym samym Idempotency-Key:

curl --request POST --url "$BASE_URL/api/v1/notes" \
  --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: notes-create-20260905-0001" \
  --data-binary @note-create.json

Powtórzenie logicznie tego samego żądania nie powinno utworzyć drugiej notatki. Odpowiedź powinna wskazać ten sam UUID i ten sam wynik operacji. Nie używaj tego samego klucza dla innego body, innego endpointu ani innej operacji. Każda nowa mutacja musi otrzymać nowy Idempotency-Key.

Przy timeoutcie nie twórz od razu kolejnego rekordu. Najpierw ponów poprzednie żądanie z tym samym body i kluczem idempotencji.


Notatki - odczyt i ETag

Po utworzeniu albo przed zmianą pobierz pojedynczą notatkę i zachowaj jej UUID oraz aktualny ETag:

export NOTE_ID="d7a83ba0-41ce-44f6-b2e9-7ddcec716234"

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

ETag pojawia się w nagłówku HTTP ETag, w data.meta.etag oraz w kopercie meta.etag. Przykładowa odpowiedź pojedynczego zasobu:

{
  "data": {
    "id": "d7a83ba0-41ce-44f6-b2e9-7ddcec716234",
    "itemType": "note",
    "attributes": {
      "customId": "NOTE-ERP-0001",
      "title": "Kontrola integracji serwera",
      "isPrivate": true
    },
    "meta": {
      "customId": "NOTE-ERP-0001",
      "etag": "\"etag-value\""
    }
  },
  "meta": {
    "requestId": "request-id-from-response",
    "etag": "\"etag-value\""
  }
}

Po każdej udanej mutacji ETag może się zmienić, także po operacji na relacji, pliku albo pinie. Zastąp poprzednią wartość nową, zanim wykonasz kolejną zmianę.


Notatki - częściowa edycja z If-Match

PATCH zmienia tylko pola przesłane w attributes. Użyj aktualnego ETag-u oraz osobnego klucza idempotencji:

export NOTE_ETAG='"etag-z-ostatniej-odpowiedzi"'

curl --request PATCH --url "$BASE_URL/api/v1/notes/$NOTE_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 "If-Match: $NOTE_ETAG" \
  --header "Idempotency-Key: notes-update-20260905-0001" \
  --data-raw '{
    "attributes": {
      "title": "Zaktualizowana kontrola integracji",
      "description": "Notatka została zmieniona przez workflow API.",
      "status": "In progress",
      "priority": "High",
      "isPrivate": false
    }
  }'

Nie musisz wysyłać wszystkich pól. Możesz wyczyścić opcjonalną wartość przez null, jeśli schema tej bazy na to pozwala:

{
  "attributes": {
    "link": null,
    "description": null
  }
}

Puste żądanie PATCH bez atrybutów, reguł wartości i zmian relacji jest odrzucane. Pola systemowe oraz pin nie należą do zwykłej edycji.


Notatki - nieaktualny ETag i brak If-Match

Mutacje Notatki wymagają nagłówka If-Match. Brak nagłówka zwraca 428 Precondition Required:

{
  "type": "https://docs.codenica.com/errors/if_match_required",
  "title": "Precondition required.",
  "status": 428,
  "detail": "Send the ETag returned by GET in the If-Match header.",
  "instance": "/api/v1/notes/{id}",
  "code": "if_match_required",
  "requestId": "request-id-from-response"
}

Jeżeli wysłany ETag jest stary, API zwróci 412 Precondition Failed:

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

Po 412 pobierz notatkę ponownie, porównaj jej aktualny stan 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 starą wartością.


Notatki - pinowanie i odpinanie

Pole pin jest read-only przy zwykłej edycji. Do ustawienia poziomu przypięcia użyj osobnej trasy:

curl --request POST --url "$BASE_URL/api/v1/notes/$NOTE_ID/pin" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $NOTE_ETAG" \
  --header "Idempotency-Key: notes-pin-20260905-0001" \
  --data-raw '{"pin":3}'

Dozwolone są liczby całkowite od 0 do 3. Aby odpiąć notatkę, prześlij null:

curl --request POST --url "$BASE_URL/api/v1/notes/$NOTE_ID/pin" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $NOTE_ETAG" \
  --header "Idempotency-Key: notes-unpin-20260905-0001" \
  --data-raw '{"pin":null}'

Operacja wymaga notes:pin:write, istniejącego uprawnienia do notatki oraz aktualnego ETag-u. Po sukcesie pobierz nowy ETag. Nie ustawiaj pinu przez attributes.pin i nie wysyłaj pustego body.

Przypięte notatki możesz wyszukać filtrem:

curl --request GET --url "$BASE_URL/api/v1/notes?pin=3&page=1&pageSize=20" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Notatki - dostępne relacje z obiektami

Notatka może być połączona z celami zwróconymi przez schema. Aktualny katalog obejmuje:

assets        - asset
clients       - client
vendors       - vendor
documents     - document
tickets       - ticket
changes       - change
problems      - problem
releases      - release
approvals     - approval
confirmations - confirmation
worktasks     - worktask
requesteditems - requesteditem

Notatka nie tworzy relacji z samą sobą. Dla większości celów relacja składa się z identyfikatora, zbioru i typu obiektu, dlatego relationshipType należy pominąć. Aktualny model relacji z confirmations przechowuje ten parametr. Przykład celu potwierdzenia:

{
  "targetId": "6efaebb6-8650-4674-8478-34fd3e601427",
  "targetDataSet": "confirmations",
  "targetItemType": "confirmation",
  "relationshipType": "client"
}

API sprawdza UUID, zgodność targetDataSet i targetItemType, istnienie oraz widoczność celu, uprawnienia i duplikaty. Jeżeli schema nie zwraca danego celu, nie używaj go w integracji.


Notatki - dodawanie, odczyt i usuwanie relacji

Relacje odczytuj przez kolekcję:

curl --request GET --url "$BASE_URL/api/v1/notes/$NOTE_ID/relationships?targetDataSet=assets&targetItemType=asset&page=1&pageSize=50" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Dodanie relacji z zasobem wymaga notes:relationships:write, aktualnego ETag-u i klucza idempotencji:

curl --request POST --url "$BASE_URL/api/v1/notes/$NOTE_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 "If-Match: $NOTE_ETAG" \
  --header "Idempotency-Key: notes-asset-relationship-20260905-0001" \
  --data-raw '{
    "targetId": "71ce005d-4cb8-4c9d-8239-ffe7e5e9f3e9",
    "targetDataSet": "assets",
    "targetItemType": "asset"
  }'

Element kolekcji może zawierać targetId, targetDataSet, targetItemType, customId i name. Ponowne dodanie tej samej relacji jest bezpieczne i nie powinno tworzyć duplikatu.

Usunięcie jednej relacji:

curl --request DELETE --url "$BASE_URL/api/v1/notes/$NOTE_ID/relationships/assets/71ce005d-4cb8-4c9d-8239-ffe7e5e9f3e9" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $NOTE_ETAG" \
  --header "Idempotency-Key: notes-asset-relationship-delete-20260905-0001"

Dla confirmations dodaj w query parametr relationshipType=client. Poprawna odpowiedź ma status 200 i data=true. Po każdej zmianie relacji odczytaj notatkę ponownie, ponieważ jej ETag może się zmienić.


Notatki - 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:

curl --request POST --url "$BASE_URL/api/v1/notes/$NOTE_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 "If-Match: $NOTE_ETAG" \
  --header "Idempotency-Key: notes-relationships-batch-20260905-0001" \
  --data-raw '{
    "add": [
      {
        "targetId": "71ce005d-4cb8-4c9d-8239-ffe7e5e9f3e9",
        "targetDataSet": "assets",
        "targetItemType": "asset"
      }
    ],
    "remove": [
      {
        "targetId": "385b51cc-fb4d-4599-9b82-3c5b66705ccd",
        "targetDataSet": "clients",
        "targetItemType": "client"
      }
    ]
  }'

Odpowiedź zawiera liczniki:

{
  "data": {
    "added": 1,
    "removed": 1,
    "skipped": 0
  },
  "meta": {
    "requestId": "request-id-from-response"
  }
}

Każdy cel musi być widoczny i zgodny z katalogiem relacji. Ponowienie relacji już istniejącej może zostać policzone jako skipped. Puste tablice add i remove są odrzucane, gdy nie zawierają żadnej operacji. Batch relacji również zmienia ETag źródłowej notatki.


Notatki - relacja autora

Autor jest ustawiany przez istniejący przepływ tworzenia notatki. Możesz go odczytać przez relację użytkownikową:

curl --request GET --url "$BASE_URL/api/v1/notes/$NOTE_ID/user-relationships?relationshipType=author&page=1&pageSize=20" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Przykładowy element odpowiedzi:

{
  "targetId": "8e9cbff3-340f-41f6-97ec-6997bb915829",
  "targetDataSet": "users",
  "relationshipType": "author",
  "displayName": "Fred Savage",
  "email": "[email protected]",
  "role": "Administrator"
}

Odczyt wymaga notes:users:read oraz odpowiedniego uprawnienia do listowania notatek. Aktualny kontrakt udostępnia tylko relację author. Nie ma publicznego POST ani DELETE do zmiany lub usunięcia autora. Nie wysyłaj autora w relationships ani w attributes.


Notatki - pliki

Notatki mogą mieć pliki, ale nie mają operacji ustawiania pliku głównego. W każdym zasobie pliku isMain jest równe false. Dostępne trasy to:

GET    /api/v1/notes/{NOTE_ID}/files
POST   /api/v1/notes/{NOTE_ID}/files
POST   /api/v1/notes/{NOTE_ID}/files/{FILE_ID}
DELETE /api/v1/notes/{NOTE_ID}/files/{FILE_ID}
GET    /api/v1/notes/{NOTE_ID}/files/{FILE_ID}/content

Najpierw możesz sprawdzić listę plików:

curl --request GET --url "$BASE_URL/api/v1/notes/$NOTE_ID/files?page=1&pageSize=50" \
  --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. Lista i pobranie wymagają notes:files:read. Upload, podłączenie i usuwanie wymagają notes:files:write, uprawnień systemowych, aktualnego ETag-u i klucza idempotencji.

Wysłanie pliku odbywa się jako multipart/form-data:

curl --request POST --url "$BASE_URL/api/v1/notes/$NOTE_ID/files?relationshipType=documentation" \
  --header "Accept: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $NOTE_ETAG" \
  --header "Idempotency-Key: notes-file-upload-20260905-0001" \
  --form "file=@./note-evidence.txt;type=text/plain"

Poprawny upload zwraca 201 Created i identyfikator pliku. Parametr relationshipType może opisywać przeznaczenie, na przykład documentation, manual albo evidence. Limit rozmiaru odczytaj z data.capabilities.limits.maxUploadBytes.

Treść pobierzesz przez uwierzytelnioną ścieżkę:

curl --request GET --url "$BASE_URL/api/v1/notes/$NOTE_ID/files/$FILE_ID/content" \
  --header "Accept: application/octet-stream" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --output ./note-evidence.downloaded.txt

downloadUrl traktuj jako ścieżkę API, a nie jako publiczny anonimowy link. Odpowiedź endpointu content zawiera bajty pliku, a nie kopertę JSON.

Jeśli plik znajduje się już w magazynie Codenica, możesz podłączyć istniejący identyfikator:

curl --request POST --url "$BASE_URL/api/v1/notes/$NOTE_ID/files/$FILE_ID?relationshipType=manual" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $NOTE_ETAG" \
  --header "Idempotency-Key: notes-file-attach-20260905-0001"

Usunięcie relacji pliku:

curl --request DELETE --url "$BASE_URL/api/v1/notes/$NOTE_ID/files/$FILE_ID" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $NOTE_ETAG" \
  --header "Idempotency-Key: notes-file-delete-20260905-0001"

Po każdej operacji na pliku odczytaj notatkę ponownie i pobierz nowy ETag. Dla Notatek nie wywołuj trasy files/{FILE_ID}/main, ponieważ nie jest częścią kontraktu tego obiektu.


Notatki - operacje batch

Batch pozwala połączyć tworzenie, aktualizację i usuwanie notatek w jednym żądaniu. Każda pozycja jest rozliczana osobno:

curl --request POST --url "$BASE_URL/api/v1/notes: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: notes-batch-create-20260905-0001" \
  --data-raw '{
    "items": [
      {
        "operation": "create",
        "create": {
          "itemType": "note",
          "attributes": {
            "customId": "NOTE-BATCH-A",
            "title": "Notatka batch A",
            "description": "Pierwsza notatka z operacji batch.",
            "category": "Integration",
            "status": "Open",
            "priority": "Normal",
            "isPrivate": false
          }
        }
      },
      {
        "operation": "create",
        "create": {
          "itemType": "note",
          "attributes": {
            "customId": "NOTE-BATCH-B",
            "title": "Notatka batch B",
            "description": "Druga notatka z operacji batch.",
            "category": "Integration",
            "status": "Open",
            "priority": "Low",
            "isPrivate": true
          }
        }
      }
    ]
  }'

Przykładowa odpowiedź zawiera succeeded, failed oraz wynik każdej pozycji:

{
  "data": {
    "succeeded": 2,
    "failed": 0,
    "items": [
      {
        "index": 0,
        "operation": "create",
        "status": 201,
        "id": "note-id-a"
      },
      {
        "index": 1,
        "operation": "create",
        "status": 201,
        "id": "note-id-b"
      }
    ]
  },
  "meta": {
    "requestId": "request-id-from-response"
  }
}

Przed update i delete pobierz osobno aktualny ETag każdej notatki. W pozycji batch przekaż id, ifMatch oraz odpowiednio blok update. Do usunięcia użyj operacji delete. Batch nie jest transakcją all-or-nothing. Przy częściowym sukcesie API może zwrócić 207 Multi-Status, dlatego sprawdzaj każdą pozycję.


Notatki - usunięcie rekordu

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

curl --request DELETE --url "$BASE_URL/api/v1/notes/$NOTE_ID" \
  --header "Accept: application/json" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
  --header "If-Match: $NOTE_ETAG" \
  --header "Idempotency-Key: notes-delete-20260905-0001"

Poprawne usunięcie wymaga notes:delete i zwraca 200 OK z data=true. Istniejący przepływ usuwania obsługuje również sprzątnięcie powiązań zgodnie z konfiguracją systemu.

Po operacji sprawdź pojedynczy rekord:

curl --request GET --url "$BASE_URL/api/v1/notes/$NOTE_ID" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Oczekiwany status to 404 z kodem note_not_found. Dodatkowo sprawdź własny identyfikator:

curl --request GET --url "$BASE_URL/api/v1/notes?customId=NOTE-ERP-2026-0001&page=1&pageSize=10" \
  --header "X-Codenica-Client-Id: $CLIENT_ID" \
  --header "X-Codenica-Client-Secret: $CLIENT_SECRET"

Po poprawnym usunięciu totalItems powinno wynosić 0. Usuń identyfikator z lokalnego indeksu integracji albo oznacz go jako nieaktywny.


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

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

{
  "type": "https://docs.codenica.com/errors/note_not_found",
  "title": "Note not found.",
  "status": 404,
  "detail": "The note does not exist or is outside the caller's access scope.",
  "instance": "/api/v1/notes/{id}",
  "code": "note_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, UUID albo wartość pola;
  • 401 - brak lub nieprawidłowe uwierzytelnienie;
  • 403 - brak scope'u albo uprawnień użytkownika;
  • 404 - notatka, plik, relacja lub cel jest niedostępny;
  • 409 - konflikt identyfikatora, duplikat albo zmiana równoczesna;
  • 412 - nieaktualny ETag;
  • 413 - plik albo body przekracza limit;
  • 422 - istniejący przepływ domenowy odrzucił operację;
  • 428 - brakuje If-Match albo Idempotency-Key;
  • 429 - przekroczono 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. isPrivate nie zastępuje szyfrowania.


Notatki - kolejność pracy integracji

  1. Ustal właściwy adres Cloud albo On-Premise i ustaw BASE_URL.
  2. Utwórz osobny klucz dla aplikacji i środowiska w Ustawienia - API - API Keys.
  3. Nadaj tylko zakresy potrzebne do odczytu, zapisu, relacji, plików, statystyk lub pinowania.
  4. Wyślij GET /api/v1/context i sprawdź bazę, caller, zakresy oraz limity.
  5. Pobierz GET /api/v1/notes/schema i zbuduj mapowanie pól oraz celów relacji.
  6. Pobierz listę notatek z paginacją, wyszukiwaniem lub filtrami.
  7. Utwórz rekord przez POST z unikalnym Idempotency-Key.
  8. Zapisz UUID i ETag z odpowiedzi.
  9. Przy timeoutcie powtórz identyczne żądanie z tym samym kluczem idempotencji.
  10. Przed każdą mutacją pobierz świeży ETag.
  11. Używaj PATCH do zwykłych pól, a pin do endpointu /pin.
  12. Do relacji używaj wyłącznie celów zwróconych przez schema i poprawnego targetItemType.
  13. Dla confirmations przekazuj relationshipType=client, a dla pozostałych zbiorów pomiń ten parametr.
  14. Relację autora tylko odczytuj, ponieważ nie ma publicznego zapisu.
  15. Przy plikach pamiętaj, że Notatki nie mają pliku głównego.
  16. W batch sprawdzaj wynik każdej pozycji, ponieważ częściowy błąd nie cofa sukcesów.
  17. Po 412 pobierz rekord ponownie i rozstrzygnij konflikt.
  18. Przy 429 respektuj Retry-After.
  19. Loguj requestId, status i kod błędu, ale nigdy sekret.
  20. Po zakończeniu integracji usuń nieużywany klucz API.

Taki przebieg pozwala synchronizować notatki z innym systemem bez opierania integracji na założeniach o polach, widoczności, relacjach lub danych systemowych.