Akceptacje w Codenica API
Pracę z Akceptacjami 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 tworzenia klucza, przechowywania sekretu i uwierzytelniania.
Techniczna nazwa obiektu to approval, a nazwa jego zbioru w API to approvals. Akceptacja przechowuje wniosek, osobę odpowiedzialną za decyzję, dane opisowe i powiązania z obiektami procesu. Może również mieć pliki oraz przypięcie.
Najważniejsza różnica względem zwykłej edycji polega na tym, że wyniku decyzji nie zapisuje się bezpośrednio w polu status. Akceptację zatwierdza się albo odrzuca przez dedykowany endpoint decyzji. Dzięki temu API sprawdza, czy decyzję wykonuje właściwy approver i czy rekord nie został zmieniony po ostatnim odczycie.
Przykłady używają identyfikatora PUBLIC-API-APPROVAL-20260906060644. Zastąp go własnym identyfikatorem pochodzącym z systemu integrującego, a UUID-y i wartości pól dopasuj do danych w swojej bazie.
Akceptacje - adres API i wybór instalacji
Wszystkie trasy dotyczące Akceptacji zaczynają się od:
{BASE_URL}/api/v1/approvalsBASE_URL oznacza adres serwera Codenica bez końcówki /api/v1. W wersji Cloud użyj rzeczywistej domeny przypisanej do firmy:
export BASE_URL="https://{rzeczywista-domena-firmy}"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://{rzeczywisty-adres-instalacji}"Nie używaj localhost, jeżeli program integrujący działa na innym komputerze niż API. Właściwa baza danych jest wybierana na podstawie hosta żądania. Nie przekazuj tenantId w body, query stringu ani dodatkowym nagłówku.
Akceptacje - zakresy klucza API
Klucz używany do pracy z Akceptacjami powinien mieć tylko zakresy potrzebne przez konkretną integrację. Pełny zestaw zakresów modułu wygląda tak:
approvals:read
approvals:write
approvals:delete
approvals:schema
approvals:stats
approvals:relationships:read
approvals:relationships:write
approvals:users:read
approvals:files:read
approvals:files:write
approvals:technical:read
approvals:technical:write
approvals:pin:write
approvals:decision:write
users:readDo odczytu list i rekordów wybierz approvals:read. Tworzenie i edycja wymagają approvals:write, usuwanie wymaga approvals:delete. Zakresy relacji, plików, statystyk, pól technicznych, pinowania i decyzji dodaj tylko wtedy, gdy integracja będzie wykonywać te operacje.
Jeśli integracja wyszukuje cele relacji, potrzebuje również odpowiednich zakresów odczytu dla zbiorów, z których wybiera cele, na przykład notes:read, worktasks:read, requesteditems:read, tickets:read, changes:read, problems:read albo releases:read. Zakres klucza nie zastępuje uprawnień użytkownika.
Akceptacje - uwierzytelnianie
Każde żądanie Codenica API uwierzytelniaj dwoma nagłówkami:
export CLIENT_ID="cna_twoj_client_id"
export CLIENT_SECRET="cns_twoj_client_secret"
curl --request GET --url "$BASE_URL/api/v1/approvals?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. Sekret przechowuj w magazynie sekretów po stronie serwera. Nie umieszczaj go w kodzie dostarczanym do przeglądarki, repozytorium, adresie URL, historii poleceń ani logach. Poza lokalnymi testami korzystaj z HTTPS.
W odpowiedziach zapisuj meta.requestId. Ten identyfikator pomaga znaleźć konkretne żądanie w logach, ale nie zastępuje UUID Akceptacji i nie jest sekretem.
Akceptacje - sprawdzenie kontekstu połączenia
Przed pierwszym zapisem pobierz kontekst. Sprawdzisz w ten sposób, czy adres prowadzi do właściwej bazy danych, a klucz ma wymagane zakresy i limity:
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, data.contractVersion, dane data.tenant, wartość data.caller.authentication równą api_key, obecność approvals w data.capabilities.resources, zakresy klucza i limity.
Jeżeli kontekst wskazuje inną firmę albo nie zawiera potrzebnego zakresu, popraw adres lub utwórz klucz z właściwymi uprawnieniami. Nie próbuj kierować żądania do innej bazy przez przesłanie obcego tenantId.
Akceptacje - schema i cele relacji
Schema jest źródłem informacji o aktualnych polach, ich typach, zapisywalności i dopuszczalnych celach relacji:
curl --request GET --url "$BASE_URL/api/v1/approvals/schema" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"W odpowiedzi znajdziesz między innymi data.itemType, data.fields i data.relationshipTargets. Dla tego modułu itemType ma wartość approval. Dla każdego pola sprawdź readable, writable, required, technical, unique, maxLength i hasAutoGeneration.
Przykładowy fragment schematu:
{
"data": {
"itemType": "approval",
"fields": [
{ "name": "description", "type": "string", "writable": true },
{ "name": "level", "type": "string", "writable": true },
{ "name": "status", "type": "string", "writable": false },
{ "name": "pin", "type": "integer", "writable": false }
],
"relationshipTargets": [
{ "targetDataSet": "notes", "targetItemType": "note" },
{ "targetDataSet": "tickets", "targetItemType": "ticket" }
]
}
}Nie buduj mapowania wyłącznie na podstawie przykładu. Przed uruchomieniem integracji pobierz schema dla właściwej bazy i używaj tylko zwróconych pól oraz celów.
Akceptacje - pola biznesowe i systemowe
Najważniejsze pola Akceptacji to:
customIdlocation, departmenttag, linkinfo, descriptionlevel, categorystatus, dateApproved, dateRejectedremark, pinid, itemType, creator, updater, dateCreated, dateUpdated, importId, importSource i dateImported są ustalane przez system albo przeznaczone do odczytu technicznego. Nie wysyłaj ich w attributes.
creator
updater
dateCreated
dateUpdated
importId
importSource
dateImportedAkceptacje - dostępne endpointy
Najważniejsze trasy modułu approvals to:
GET /api/v1/approvals
POST /api/v1/approvals
GET /api/v1/approvals/{APPROVAL_ID}
PATCH /api/v1/approvals/{APPROVAL_ID}
DELETE /api/v1/approvals/{APPROVAL_ID}
GET /api/v1/approvals/schema
GET /api/v1/approvals/stats
GET /api/v1/approvals/values
POST /api/v1/approvals:batch
GET /api/v1/approvals/{APPROVAL_ID}/relationships
POST /api/v1/approvals/{APPROVAL_ID}/relationships
POST /api/v1/approvals/{APPROVAL_ID}/relationships:batch
DELETE /api/v1/approvals/{APPROVAL_ID}/relationships/{DATASET}/{TARGET_ID}
GET /api/v1/approvals/{APPROVAL_ID}/user-relationships
GET /api/v1/approvals/{APPROVAL_ID}/files
POST /api/v1/approvals/{APPROVAL_ID}/files
POST /api/v1/approvals/{APPROVAL_ID}/files/{FILE_ID}
DELETE /api/v1/approvals/{APPROVAL_ID}/files/{FILE_ID}
GET /api/v1/approvals/{APPROVAL_ID}/files/{FILE_ID}/content
POST /api/v1/approvals/{APPROVAL_ID}/pin
POST /api/v1/approvals/{APPROVAL_ID}/decisionOdczyty wymagają zakresów read, a poszczególne mutacje dodatkowych zakresów zgodnych z tabelą uprawnień. Każde żądanie zmieniające dane wymaga również Idempotency-Key, a operacje na istniejącym rekordzie dodatkowo aktualnego If-Match.
Akceptacje - listowanie i paginacja
Listę Akceptacji pobieraj stronami:
curl --request GET --url "$BASE_URL/api/v1/approvals?itemType=approval&page=1&pageSize=25" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"Odpowiedź ma kolekcję data.items oraz informacje o stronie:
{
"data": {
"items": [
{
"id": "approval-uuid",
"itemType": "approval",
"attributes": {
"customId": "ERP-APPROVAL-2026-0042",
"category": "Procurement",
"status": "Open",
"level": "Supervisor"
},
"meta": {
"etag": "\"etag-value\""
}
}
],
"page": 1,
"pageSize": 25,
"totalItems": 1,
"totalPages": 1,
"hasNextPage": false
},
"meta": {
"requestId": "request-id"
}
}Przechodź do następnej strony na podstawie hasNextPage. Maksymalny rozmiar strony odczytaj z data.capabilities.limits.maxPageSize, zamiast zakładać go na stałe.
Akceptacje - wyszukiwanie i filtry
Do wyszukiwania tekstowego użyj parametru search. Do synchronizacji najlepiej stosować stabilny customId albo UUID:
curl --silent --show-error -G \
--data-urlencode "search=zakup" \
--data-urlencode "page=1" \
--data-urlencode "pageSize=20" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/approvals"Proste filtry mogą korzystać z nazw pól:
curl --silent --show-error -G \
--data-urlencode "status=Open" \
--data-urlencode "category=Procurement" \
--data-urlencode "customId=ERP-APPROVAL-2026-0042" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/approvals"Filtr strukturalny ma postać field:operator:value:
category:eq:Procurement
level:ne:Assistant
description:contains:monitor
customId:startswith:ERP-
link:notempty:Obsługiwane operatory to między innymi eq, ne, gt, gte, lt, lte, contains, startswith, endswith i notempty. Wartość filtra URL-encode’uj, zwłaszcza gdy zawiera spację, dwukropek lub znak specjalny.
Akceptacje - wybór pól i dołączanie danych
Jeżeli potrzebujesz tylko części odpowiedzi, użyj fields. Dołączanie plików, relacji i użytkowników wykonuje się przez include:
curl --silent --show-error -G \
--data-urlencode "fields=id,itemType,customId,location,department,level,category,status" \
--data-urlencode "include=files,relationships,users" \
--data-urlencode "ids={APPROVAL_ID}" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/approvals"Dostępne wartości include to files, relationships i users. Każda z nich może wymagać osobnego zakresu. fields=* nie omija uprawnień do pól technicznych i nie zmienia reguł dostępu.
Do filtrowania możesz wykorzystać także createdAfter, createdBefore, updatedAfter, updatedBefore, sort i direction. Nazwy pól w fields, sort i filter sprawdzaj względem aktualnego schema.
Akceptacje - statystyki i wartości pól
Endpoint stats pomaga sprawdzić rozkład danych, a values zwraca wartości przydatne do budowy filtrów:
curl --silent --show-error -G \
--data-urlencode "field=category" \
--data-urlencode "limit=20" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/approvals/stats"
curl --silent --show-error -G \
--data-urlencode "field=level" \
--data-urlencode "search=super" \
--data-urlencode "limit=20" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/approvals/values"Oba żądania są odczytowe i nie zmieniają Akceptacji. Pole musi być dopuszczone w schema, a zakres wartości zależy od rekordów widocznych dla użytkownika.
Akceptacje - minimalne utworzenie
Minimalny praktyczny rekord zawiera typ, identyfikator po stronie integracji, kategorię, opis oraz użytkownika, który ma wykonać decyzję:
{
"itemType": "approval",
"attributes": {
"customId": "ERP-APPROVAL-0001",
"category": "Procurement",
"description": "Akceptacja zakupu monitora"
},
"approverId": "{USER_ID_APPROVERA}"
}Prześlij go jako JSON:
curl --fail-with-body --silent --show-error \
--request POST \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Idempotency-Key: erp-approval-create-0001" \
--data-binary @approval.json \
"$BASE_URL/api/v1/approvals"approverId wskazuje aktywnego użytkownika Codenica, który ma podjąć decyzję. Nie jest to identyfikator klienta w kartotece ani dowolny adres e-mail.
Akceptacje - kompletne utworzenie z przykładem danych
Poniższy przykład pokazuje rekord z opisem procesu, oznaczeniami, poziomem akceptacji i regułą wartości technicznej:
{
"itemType": "approval",
"attributes": {
"customId": "PUBLIC-API-APPROVAL-20260906060644-SOURCE",
"location": "Warsaw",
"department": "IT",
"tag": "public-api,approvals,PUBLIC-API-APPROVAL-20260906060644",
"link": "https://codenica.com",
"info": "Approval request created by the Public API complete flow.",
"level": "Supervisor",
"category": "Procurement",
"description": "Approval created through the Codenica Public API."
},
"approverId": "{USER_ID_APPROVERA}",
"customValues": [
{
"name": "description",
"valuePattern": "[approval-test] PUBLIC-API-APPROVAL-20260906060644"
}
]
}approverId wymaga approvals:technical:write. customValues jest opcjonalne i również wymaga zakresu technicznego. Używaj go tylko dla pól dopuszczonych przez schema.
W praktycznej integracji wybierz approvera zgodnie z procesem firmy. Użytkownik, który tworzy rekord, zostaje requesterem.
Akceptacje - odpowiedź create i klucz idempotencji
Udane utworzenie zwraca 201 Created, identyfikator rekordu i początkowy ETag. Zapisz oba identyfikatory po stronie integracji:
{
"data": {
"id": "{APPROVAL_ID}",
"itemType": "approval",
"attributes": {
"customId": "PUBLIC-API-APPROVAL-20260906060644-SOURCE",
"level": "Supervisor",
"category": "Procurement",
"status": "Open"
},
"meta": {
"customId": "PUBLIC-API-APPROVAL-20260906060644-SOURCE",
"etag": "\"{ETAG_AFTER_CREATE}\""
}
},
"meta": {
"requestId": "{REQUEST_ID}",
"etag": "\"{ETAG_AFTER_CREATE}\""
}
}Każde mutujące żądanie musi mieć własny Idempotency-Key. Jeżeli klient nie wie, czy pierwsze żądanie dotarło do serwera, wyślij ponownie identyczne body z identycznym kluczem:
curl --fail-with-body --silent --show-error \
--request POST \
--header "Content-Type: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Idempotency-Key: public-api-approval-source-create-20260906060644" \
--data-binary @approval.json \
"$BASE_URL/api/v1/approvals"Powtórzenie tego samego żądania nie tworzy drugiej Akceptacji. Zmienione body z tym samym kluczem zostanie odrzucone, ponieważ jeden klucz nie może oznaczać dwóch różnych operacji.
Akceptacje - odczyt pojedynczego rekordu i ETag
Po utworzeniu albo przed każdą kolejną zmianą pobierz rekord po UUID:
curl --fail-with-body --silent --show-error \
--request GET \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/approvals/{APPROVAL_ID}?fields=*"Odpowiedź zawiera data.attributes oraz data.meta.etag. Serwer zwraca tę samą wartość także w nagłówku HTTP:
HTTP/1.1 200 OK
ETag: "{ETAG_AFTER_GET}"Po każdej udanej mutacji ETag może się zmienić, również po zmianie relacji, pinowaniu, decyzji i operacji na plikach. Zawsze zapisuj wartość zwróconą przez ostatnią udaną operację.
Akceptacje - edycja pól z If-Match
Zwykła edycja zmienia tylko pola biznesowe. Nie zapisuj przez nią statusu, dat decyzji ani pinu:
curl --fail-with-body --silent --show-error \
--request PATCH \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header 'If-Match: "{ETAG_AFTER_GET}"' \
--header "Idempotency-Key: public-api-approval-update-20260906060644" \
--data '{
"attributes": {
"info": "Updated approval information from the integration.",
"level": "Manager",
"category": "Approved procurement",
"description": "Approval edited through the Codenica Public API."
}
}' \
"$BASE_URL/api/v1/approvals/{APPROVAL_ID}"Sukces zwraca 200 OK i nowy ETag. Zmień tylko te pola, które rzeczywiście uległy zmianie. Ułatwia to rozwiązywanie konfliktów i ogranicza ryzyko nadpisania danych.
Akceptacje - wymagany If-Match i ochrona przed konfliktem
Aktualny ETag jest warunkiem zmiany istniejącego rekordu. PATCH bez tego nagłówka kończy się odpowiedzią:
{
"type": "https://docs.codenica.com/errors/if_match_required",
"title": "Precondition required.",
"status": 428,
"code": "if_match_required",
"detail": "Send the ETag returned by GET in the If-Match header."
}Jeżeli przesłany ETag jest nieaktualny, API zwraca 412 Precondition Failed i kod if_match_failed:
{
"type": "https://docs.codenica.com/errors/if_match_failed",
"title": "Precondition failed.",
"status": 412,
"code": "if_match_failed",
"detail": "The supplied ETag is not the current approval version."
}Żądanie odrzucone przez 412 nie zapisuje zmian. Pobierz Akceptację ponownie, porównaj dane i dopiero wtedy przygotuj świadomą aktualizację. Nie nadpisuj automatycznie zmian wykonanych przez drugą osobę lub integrację.
Akceptacje - pinowanie
Pin jest polem odczytowym zmienianym przez osobny endpoint. Dozwolone wartości to liczby całkowite od 0 do 3:
curl --fail-with-body --silent --show-error \
--request POST \
--header "Content-Type: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header 'If-Match: "{AKTUALNY_ETAG}"' \
--header "Idempotency-Key: public-api-approval-pin-20260906060644" \
--data '{"pin":3}' \
"$BASE_URL/api/v1/approvals/{APPROVAL_ID}/pin"Aby usunąć pin, wyślij null przez ten sam endpoint:
curl --fail-with-body --silent --show-error \
--request POST \
--header "Content-Type: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header 'If-Match: "{ETAG_AFTER_PIN}"' \
--header "Idempotency-Key: public-api-approval-unpin-20260906060644" \
--data '{"pin":null}' \
"$BASE_URL/api/v1/approvals/{APPROVAL_ID}/pin"Obie operacje wymagają aktualnego ETag oraz approvals:pin:write. Nie wysyłaj pin w zwykłym PATCH.
Akceptacje - wykonanie decyzji Approved albo Rejected
Decyzja ma dedykowany endpoint:
/api/v1/approvals/{APPROVAL_ID}/decisionPozytywna decyzja ustawia status=Approved, dateApproved i dateEnd:
curl --fail-with-body --silent --show-error \
--request POST \
--header "Content-Type: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header 'If-Match: "{AKTUALNY_ETAG}"' \
--header "Idempotency-Key: public-api-approval-decision-approved-20260906060644" \
--data '{"approved":true,"remark":"Approved through the Public API integration."}' \
"$BASE_URL/api/v1/approvals/{APPROVED_APPROVAL_ID}/decision"Negatywna decyzja ustawia status=Rejected, dateRejected i dateEnd:
curl --fail-with-body --silent --show-error \
--request POST \
--header "Content-Type: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header 'If-Match: "{AKTUALNY_ETAG}"' \
--header "Idempotency-Key: public-api-approval-decision-rejected-20260906060644" \
--data '{"approved":false,"remark":"Rejected through the Public API integration."}' \
"$BASE_URL/api/v1/approvals/{REJECTED_APPROVAL_ID}/decision"Nie zmieniaj statusu przez PATCH, aby ominąć tę procedurę. Decyzja wymaga approvals:decision:write, właściwego uprawnienia biznesowego (Approval_Accept albo Approval_Reject), aktualnego ETag oraz wywołania przez dokładnie tego użytkownika, który został przypisany jako approver.
Akceptacje - requester i approver
Relacje z użytkownikami odczytuje się przez osobny endpoint:
curl --fail-with-body --silent --show-error \
--request GET \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/approvals/{APPROVAL_ID}/user-relationships?page=1&pageSize=20"W odpowiedzi znajdziesz relację requester oraz, jeżeli wskazano approvera, relację approver:
{
"data": {
"items": [
{
"userId": "{USER_ID_REQUESTERA}",
"relationshipType": "requester"
},
{
"userId": "{USER_ID_APPROVERA}",
"relationshipType": "approver"
}
]
}
}Requester jest ustawiany automatycznie na użytkownika tworzącego Akceptację. Obie relacje są odczytowe. Nie próbuj zmieniać approvera przez POST na user-relationships; przypisanie approvera należy do kontrolowanego procesu tworzenia lub operacji systemowej.
Akceptacje - dozwolone relacje z obiektami
Akceptacja ma ograniczony katalog celów relacji:
W tym katalogu nie ma relacji z assets, clients, vendors, documents, confirmations ani z samą Akceptacją.
{
"targetId": "{TARGET_ID}",
"targetDataSet": "notes",
"targetItemType": "note"
}Najpierw wybierz rekord celu z listy odpowiedniego zbioru. Nie zakładaj, że każda baza zawiera rekord w każdym z siedmiu zbiorów.
Akceptacje - ważna różnica w formacie relacji
W relacjach obiektowych Akceptacji nie przechowuje się relationshipType. Body zawiera wyłącznie identyfikator celu, nazwę zbioru i techniczny typ obiektu:
{
"targetId": "7bdda87a-6c37-49ae-9e40-272a7a9b8616",
"targetDataSet": "notes",
"targetItemType": "note"
}Nie wysyłaj takiego pola:
{
"targetId": "{TARGET_ID}",
"targetDataSet": "notes",
"targetItemType": "note",
"relationshipType": "related"
}relationshipType jest używane przez inne modele relacji oraz przez pliki, ale dla relacji Akceptacji z obiektami procesowymi zostanie odrzucone.
curl --fail-with-body --silent --show-error \
--request GET \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/notes?page=1&pageSize=10"Do wyboru celu potrzebujesz zakresu read danego zbioru, na przykład notes:read.
Akceptacje - dodanie, odczyt i usunięcie relacji
Do bezpośredniego dodawania relacji potrzebujesz aktualnego ETag Akceptacji oraz approvals:relationships:write:
curl --fail-with-body --silent --show-error \
--request POST \
--header "Content-Type: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header 'If-Match: "{AKTUALNY_ETAG}"' \
--header "Idempotency-Key: public-api-approval-relation-add-0001" \
--data '{"targetId":"{NOTE_ID}","targetDataSet":"notes","targetItemType":"note"}' \
"$BASE_URL/api/v1/approvals/{APPROVAL_ID}/relationships"Odczytaj relacje po dodaniu:
curl --fail-with-body --silent --show-error \
--request GET \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/approvals/{APPROVAL_ID}/relationships?targetDataSet=notes&page=1&pageSize=100"Usunięcie pojedynczej relacji wymaga nowego ETag otrzymanego po dodaniu:
curl --fail-with-body --silent --show-error \
--request DELETE \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header 'If-Match: "{ETAG_AFTER_RELATION_ADD}"' \
--header "Idempotency-Key: public-api-approval-relation-delete-0001" \
"$BASE_URL/api/v1/approvals/{APPROVAL_ID}/relationships/notes/{NOTE_ID}"Po każdym zapisie ponownie pobierz kolekcję i potwierdź, że cel został dodany albo usunięty.
Akceptacje - relacje batch i relacje w PATCH
Wiele relacji możesz zmienić jednym żądaniem:
{
"add": [
{
"targetId": "{NOTE_ID}",
"targetDataSet": "notes",
"targetItemType": "note"
}
],
"remove": []
}curl --fail-with-body --silent --show-error \
--request POST \
--header "Content-Type: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header 'If-Match: "{AKTUALNY_ETAG}"' \
--header "Idempotency-Key: public-api-approval-relationship-batch-0001" \
--data-binary @relationship-batch.json \
"$BASE_URL/api/v1/approvals/{APPROVAL_ID}/relationships:batch"Odpowiedź zawiera liczniki added, removed i skipped. Możesz też użyć w PATCH pól relationshipsToAdd i relationshipsToRemove:
{
"attributes": {
"info": "Updated together with a relationship."
},
"relationshipsToAdd": [
{
"targetId": "{TICKET_ID}",
"targetDataSet": "tickets",
"targetItemType": "ticket"
}
],
"relationshipsToRemove": []
}W obu wariantach obowiązują aktualny ETag, idempotencja i zakres relacji.
Akceptacje - lista plików i upload
Pliki są odrębnymi zasobami powiązanymi z Akceptacją. Najpierw odczytaj bieżącą listę:
curl --fail-with-body --silent --show-error \
--request GET \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/approvals/{APPROVAL_ID}/files?page=1&pageSize=100"Wyślij plik jako multipart/form-data. Rola pliku jest przekazywana w query stringu:
curl --fail-with-body --silent --show-error \
--request POST \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header 'If-Match: "{AKTUALNY_ETAG}"' \
--header "Idempotency-Key: public-api-approval-file-upload-0001" \
--form "[email protected];type=application/pdf" \
"$BASE_URL/api/v1/approvals/{APPROVAL_ID}/files?relationshipType=decision-form"Nazwa pliku powinna być pojedynczą nazwą bez ścieżki. Przed wysłaniem sprawdź rozmiar i świadomie ustaw typ MIME. Upload wymaga approvals:files:write.
{
"data": {
"id": "{FILE_ID}",
"fileName": "formularz-akceptacji.pdf",
"contentType": "application/pdf",
"size": 48231,
"relationshipType": "decision-form",
"isMain": false,
"downloadUrl": "/api/v1/approvals/{APPROVAL_ID}/files/{FILE_ID}/content"
}
}Dla Akceptacji API nie udostępnia operacji ustawienia pliku głównego. Zwracane pliki mają isMain=false. Nie buduj integracji, która oczekuje endpointu /main dla tego obiektu.
Akceptacje - pobieranie, podpinanie i usuwanie plików
Treść pliku pobierz przez endpoint content i zapisz w trybie binarnym:
curl --fail-with-body --silent --show-error \
--output pobrany-formularz-akceptacji.pdf \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
"$BASE_URL/api/v1/approvals/{APPROVAL_ID}/files/{FILE_ID}/contentJeżeli plik istnieje już w systemie i masz jego File ID, możesz podpiąć go do Akceptacji bez ponownego uploadu:
curl --fail-with-body --silent --show-error \
--request POST \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header 'If-Match: "{ETAG_AKCEPTACJI}"' \
--header "Idempotency-Key: public-api-approval-file-attach-0001" \
"$BASE_URL/api/v1/approvals/{TARGET_APPROVAL_ID}/files/{FILE_ID}?relationshipType=reference"Usunięcie pliku z Akceptacji:
curl --fail-with-body --silent --show-error \
--request DELETE \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header 'If-Match: "{AKTUALNY_ETAG}"' \
--header "Idempotency-Key: public-api-approval-file-delete-0001" \
"$BASE_URL/api/v1/approvals/{APPROVAL_ID}/files/{FILE_ID}"Attach tworzy powiązanie z istniejącym plikiem, ale nie przesyła nowej kopii. Upload, attach i delete zmieniają ETag Akceptacji. Download jest operacją odczytową.
Akceptacje - operacje batch
Endpoint /api/v1/approvals:batch pozwala tworzyć, edytować i usuwać wiele rekordów. Nie zastępuje operacji decyzji, pinowania, relacji ani plików:
{
"items": [
{
"operation": "create",
"create": {
"itemType": "approval",
"approverId": "{USER_ID_APPROVERA}",
"attributes": {
"customId": "PUBLIC-API-APPROVAL-BATCH-A",
"location": "Warsaw",
"department": "IT",
"level": "Supervisor",
"category": "Procurement",
"description": "Batch-created Approval A"
}
}
},
{
"operation": "create",
"create": {
"itemType": "approval",
"approverId": "{USER_ID_APPROVERA}",
"attributes": {
"customId": "PUBLIC-API-APPROVAL-BATCH-B",
"location": "Warsaw",
"department": "IT",
"level": "Manager",
"category": "Procurement",
"description": "Batch-created Approval B"
}
}
}
]
}curl --fail-with-body --silent --show-error \
--request POST \
--header "Content-Type: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Idempotency-Key: public-api-approval-batch-create-0001" \
--data-binary @approvals-batch-create.json \
"$BASE_URL/api/v1/approvals:batch"W jednym batchu możesz mieszać operacje create, update i delete. Każda aktualizacja i usunięcie musi mieć własny id oraz aktualny ifMatch.
{
"data": {
"items": [
{
"index": 0,
"operation": "create",
"status": 201,
"id": "{BATCH_ID_A}",
"data": {
"id": "{BATCH_ID_A}",
"meta": { "etag": "{ETAG_A}" }
}
}
],
"succeeded": 2,
"failed": 0
}
}Batch nie jest transakcją all-or-nothing. Przy częściowym wyniku możesz otrzymać 207 Multi-Status. Analizuj każdy element odpowiedzi i nie ponawiaj operacji, które już zakończyły się sukcesem.
Akceptacje - usunięcie rekordu
Przed usunięciem pobierz rekord ponownie, sprawdź UUID i aktualny ETag oraz upewnij się, że proces biznesowy pozwala na usunięcie:
curl --fail-with-body --silent --show-error \
--request DELETE \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header 'If-Match: "{AKTUALNY_ETAG}"' \
--header "Idempotency-Key: public-api-approval-delete-0001" \
"$BASE_URL/api/v1/approvals/{APPROVAL_ID}"Poprawna odpowiedź zwraca 200 OK i data=true. Po usunięciu ponowny odczyt UUID powinien zwrócić 404 Not Found z kodem approval_not_found. Kontrolę możesz wykonać także przez listę filtrowaną po customId i oczekiwać totalItems=0.
Nie usuwaj Akceptacji bez potwierdzenia ETag. Chroni to integrację przed skasowaniem nowszej wersji rekordu przez proces pracujący na starej kopii.
Akceptacje - błędy, limity i bezpieczna kolejność pracy
Błędy mają format Problem Details. W logach zapisuj status, code i requestId, ale nie zapisuj Client Secret ani pełnych nagłówków:
authentication_failedapproval_approver_requiredapproval_not_foundapproval_unique_constraint lub approval_concurrency_conflictif_match_failed, if_match_requiredvalidation_failed, approval_decision_rejected, approval_pin_rejectedrate_limit_exceededRetry-After.Odczytuj X-RateLimit-Limit i X-RateLimit-Remaining. Cache’uj schema i wartości, ogranicz równoległość, a przy 429 stosuj backoff.
Bezpieczna kolejność pracy to: context, schema, wybór approvera, lista lub odczyt, utworzenie z Idempotency-Key, zapisanie UUID i ETagu, relacje lub pliki, edycja z If-Match, decyzja przez /decision, odczyt weryfikacyjny i dopiero na końcu usunięcie. Ten sam układ można wykorzystać w n8n, przekazując UUID, ETag i klucze idempotencji między kolejnymi krokami.
