Confirmations in Codenica API
Start working with Confirmations through Codenica API by creating an API key in Codenica settings. If you have not created one yet, open Codenica API - introduction in a new tab. That article explains the common key creation, secret storage and authentication rules.
A Confirmation is a process record in which a specific Client is expected to make a decision. An integration can prepare the data, assign the Client, attach documents, assets, notes and files, and then make the decision available to the appropriate Client context.
The technical name of one record is confirmation, while the collection name in the API is confirmations. A normal update changes the descriptive part of the record. Do not write the decision result directly to status - approve or decline a Confirmation through the dedicated /decision endpoint.
The examples use PUBLIC-API-CONFIRMATION-20260908-0001. Replace it with an identifier from your integrating application and replace values in braces with data from your database.
Confirmations - API address and installation choice
All Confirmation routes start with:
{BASE_URL}/api/v1/confirmationsBASE_URL is the Codenica server address without the /api/v1 suffix. In Codenica Cloud, use the domain or subdomain assigned to the relevant company:
export BASE_URL="https://{company-domain}"In the default On-Premise installation, Codenica Discovery registers the local address:
export BASE_URL="http://codenica.local:5150"If the administrator exposed the installation under a company domain, HTTPS, a reverse proxy or another port, use the exact address provided for that installation:
export BASE_URL="https://{actual-installation-address}"Use localhost only when the integration and API run on the same computer. The http://localhost:5050 example is for local development, not the standard On-Premise address. Do not send tenantId in the body or query string. The target database is selected from the request host.
Confirmations - API key scopes
The key used for Confirmations should contain only the scopes required by the integration. The complete module scope set is:
confirmations:read
confirmations:write
confirmations:delete
confirmations:schema
confirmations:stats
confirmations:relationships:read
confirmations:relationships:write
confirmations:users:read
confirmations:files:read
confirmations:files:write
confirmations:technical:read
confirmations:technical:write
confirmations:pin:write
confirmations:decision:write
users:readUse confirmations:read for lists and records. Creating and normally editing a record requires confirmations:write, while deletion requires confirmations:delete. Add relationship, file, statistics, technical-field, pinning and decision scopes only when the integration actually performs those operations.
If the integration selects relationship targets from another collection, it also needs the relevant read scope, such as assets:read, documents:read, clients:read or notes:read. A key scope does not replace the permissions of the user associated with the key.
Confirmations - request authentication
Authenticate every Codenica API request with two headers:
X-Codenica-Client-Id: {CLIENT_ID}
X-Codenica-Client-Secret: {CLIENT_SECRET}
Accept: application/jsonExample of the first request:
export PUBLIC_API_CLIENT_ID="cna_example"
export PUBLIC_API_CLIENT_SECRET="cns_example"
curl --request GET --url "$BASE_URL/api/v1/context" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET"An external integration does not need an administrator Bearer JWT or Codenica panel cookies. Store the Client Secret on the server in a secrets store. Do not put it in browser code, a repository, a URL, command history or logs. Use HTTPS outside local development.
Store meta.requestId from responses. It helps locate a request in logs, but it is not the Confirmation UUID and is not a secret.
Confirmations - verify the connection context
Read the context before the first write. This confirms that the address reaches the intended database and that the key has the required scopes and limits:
curl --fail-with-body --silent --show-error \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET" \
"$BASE_URL/api/v1/context"Check, among other things, data.apiVersion, data.contractVersion, data.tenant, data.caller.authentication equal to api_key, the caller role and clientId, the presence of confirmations in data.capabilities.resources, the scopes and the limits.
{
"data": {
"caller": {
"role": "Administrator",
"authentication": "api_key",
"scopes": [
"confirmations:read",
"confirmations:write",
"confirmations:decision:write"
]
},
"capabilities": {
"supportsETag": true,
"supportsIdempotency": true,
"supportsRelationships": true,
"supportsFiles": true
}
},
"meta": { "requestId": "{REQUEST_ID}" }
}If the context identifies the wrong company or does not contain a required scope, correct the address or key. Do not try to select another database by sending a foreign identifier.
Confirmations - schema and relationship targets
Schema is the source of truth for the current fields, their types, writeability and permitted relationship targets:
curl --fail-with-body --silent --show-error \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET" \
"$BASE_URL/api/v1/confirmations/schema"The response includes data.itemType, data.fields and data.relationshipTargets. For this module, itemType is always confirmation. For each field, check readable, writable, required, technical, unique and maxLength.
{
"data": {
"itemType": "confirmation",
"fields": [
{ "name": "customId", "type": "string", "writable": true },
{ "name": "status", "type": "string", "writable": false },
{ "name": "pin", "type": "integer", "writable": false }
],
"relationshipTargets": [
{ "targetDataSet": "assets" },
{ "targetDataSet": "clients", "targetItemType": "client" },
{ "targetDataSet": "documents", "targetItemType": "document" },
{ "targetDataSet": "notes", "targetItemType": "note" }
]
}
}For assets, schema does not impose one object type. If a target has itemType=computer, send computer in the relationship request instead of assuming asset. Do not build the mapping from one example alone - read the current schema before running the integration.
Confirmations - business and process fields
The main fields that can be sent in attributes are:
customIdlocation, departmenttag, linkinfo, descriptiontype, categorystatus, dateConfirmed, dateDeclined, dateEnd, remark, pinImportant maximum lengths include: customId 500, location 300, department 300, tag 2000, link 2000, info 10000, type 300, category 300 and description 10000 characters. The current schema for the database takes priority.
Do not write status, dateConfirmed, dateDeclined, dateEnd, remark or pin through a normal PATCH. Do not send audit fields either:
creator
updater
dateCreated
dateUpdated
importId
importSource
dateImportedConfirmations - available endpoints
The main routes in the confirmations module are:
GET /api/v1/confirmations
POST /api/v1/confirmations
GET /api/v1/confirmations/{CONFIRMATION_ID}
PATCH /api/v1/confirmations/{CONFIRMATION_ID}
DELETE /api/v1/confirmations/{CONFIRMATION_ID}
GET /api/v1/confirmations/schema
GET /api/v1/confirmations/stats
GET /api/v1/confirmations/values
POST /api/v1/confirmations:batch
GET /api/v1/confirmations/{CONFIRMATION_ID}/relationships
POST /api/v1/confirmations/{CONFIRMATION_ID}/relationships
POST /api/v1/confirmations/{CONFIRMATION_ID}/relationships:batch
DELETE /api/v1/confirmations/{CONFIRMATION_ID}/relationships/{DATASET}/{TARGET_ID}
GET /api/v1/confirmations/{CONFIRMATION_ID}/user-relationships
GET /api/v1/confirmations/{CONFIRMATION_ID}/files
POST /api/v1/confirmations/{CONFIRMATION_ID}/files
POST /api/v1/confirmations/{CONFIRMATION_ID}/files/{FILE_ID}
DELETE /api/v1/confirmations/{CONFIRMATION_ID}/files/{FILE_ID}
GET /api/v1/confirmations/{CONFIRMATION_ID}/files/{FILE_ID}/content
POST /api/v1/confirmations/{CONFIRMATION_ID}/pin
POST /api/v1/confirmations/{CONFIRMATION_ID}/decisionReads require read scopes, while each mutation requires the additional scope assigned to its operation. Every request that changes data requires Idempotency-Key; an operation on an existing record also requires the current If-Match.
Confirmations - listing and pagination
Read Confirmations in pages. You may send the fixed itemType=confirmation, although the API uses this type for the entire module:
curl --fail-with-body --silent --show-error \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET" \
"$BASE_URL/api/v1/confirmations?itemType=confirmation&page=1&pageSize=25"The response contains the data.items collection and page information:
{
"data": {
"items": [
{
"id": "{CONFIRMATION_ID}",
"itemType": "confirmation",
"attributes": {
"customId": "ERP-CONFIRMATION-2026-0042",
"category": "Procurement",
"status": "Pending"
},
"meta": { "etag": "{ETAG}" }
}
],
"page": 1,
"pageSize": 25,
"totalItems": 1,
"totalPages": 1,
"hasNextPage": false
},
"meta": { "requestId": "{REQUEST_ID}" }
}Move to the next page based on hasNextPage. Read the maximum page size from data.capabilities.limits.maxPageSize instead of hard-coding it.
Confirmations - search and filters
Use search to find text in descriptive fields. For synchronization, a stable customId or UUID is usually better:
curl --silent --show-error -G \
--data-urlencode "search=procurement" \
--data-urlencode "page=1" \
--data-urlencode "pageSize=20" \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET" \
"$BASE_URL/api/v1/confirmations"You can combine field filters in one request:
curl --silent --show-error -G \
--data-urlencode "status=Pending" \
--data-urlencode "category=Procurement" \
--data-urlencode "customId=ERP-CONFIRMATION-2026-0042" \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET" \
"$BASE_URL/api/v1/confirmations"For more precise filtering, use the structural form field:operator:value:
category:eq:Procurement
status:ne:Declined
description:contains:monitor
customId:startswith:ERP-CONFIRMATION-
link:notempty:Useful operators include eq, ne, contains, startswith, endswith and notempty. URL-encode values that contain spaces, colons or special characters.
Confirmations - field selection and included data
The fields parameter limits the attributes returned in the response. When synchronizing a list, request only what the integration needs:
curl --fail-with-body --silent --show-error \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET" \
"$BASE_URL/api/v1/confirmations?fields=id,customId,status,category&page=1&pageSize=20"To receive files, relationships and the creating user in the same response, use include:
curl --fail-with-body --silent --show-error \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET" \
"$BASE_URL/api/v1/confirmations/{CONFIRMATION_ID}?fields=%2A&include=files%2Crelationships%2Cusers"Including files requires confirmations:files:read, relationships require confirmations:relationships:read, and users require confirmations:users:read. Keep fields and include narrow when the integration does not need the full record.
Confirmations - statistics and field values
The stats endpoint helps build a summary of visible Confirmations, while values supplies values for filter controls:
curl --fail-with-body --silent --show-error \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET" \
"$BASE_URL/api/v1/confirmations/stats?field=category&limit=20"curl --fail-with-body --silent --show-error \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET" \
"$BASE_URL/api/v1/confirmations/values?field=category&search=proc&limit=20"Both endpoints are read-only and require confirmations:stats. Results include only records visible to the user associated with the key and do not require an ETag. Check the current API contract for the maximum limit value.
Confirmations - create a record and assign a Client
A Confirmation that requires a decision should point to a business Client. This is the Client record in the database, not the technical AppUser identity used for sign-in:
{
"targetId": "{CLIENT_ID}",
"targetDataSet": "clients",
"targetItemType": "client"
}A minimal payload contains the fixed itemType, descriptive attributes and a relationship to the Client:
{
"itemType": "confirmation",
"attributes": {
"customId": "ERP-CONFIRMATION-2026-0042",
"category": "Procurement",
"description": "Confirmation of a workstation purchase."
},
"relationships": [
{
"targetId": "{CLIENT_ID}",
"targetDataSet": "clients",
"targetItemType": "client"
}
]
}The assignment can be sent during creation. Do not add relationshipType to this relationship.
Confirmations - complete creation example
For a larger integration, save the body to a file so that the identical request can be safely retried after a temporary connection failure:
{
"itemType": "confirmation",
"attributes": {
"customId": "PUBLIC-API-CONFIRMATION-20260908-0001",
"location": "London",
"department": "IT",
"tag": "integration,procurement,confirmation",
"link": "https://erp.example.com/requests/0001",
"info": "Request received from the procurement system.",
"type": "Hardware purchase",
"category": "Procurement",
"description": "Confirmation of a new workstation purchase for the IT department."
},
"relationships": [
{
"targetId": "{CLIENT_ID}",
"targetDataSet": "clients",
"targetItemType": "client"
}
]
}curl --fail-with-body --silent --show-error \
--request POST \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "Idempotency-Key: erp-confirmation-create-0001" \
--data-binary @confirmation-create.json \
"$BASE_URL/api/v1/confirmations"A successful creation returns 201 Created. The response contains the UUID, itemType, attributes, date metadata, ETag and requestId. Store the UUID and ETag because the following steps need them.
Confirmations - Idempotency-Key and safe retries
Every request that changes data through an API key must have its own Idempotency-Key. If the connection breaks after the request was sent, repeat exactly the same request with the same key:
curl --fail-with-body --silent --show-error \
--request POST \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: erp-confirmation-create-0001" \
--data-binary @confirmation-create.json \
"$BASE_URL/api/v1/confirmations"Repeating the identical request with the same key must not create a second Confirmation. Do not reuse one key for different bodies or operations. An idempotency key represents one business operation.
Creation: Idempotency-Key = erp-confirmation-create-0001
Retry: Idempotency-Key = erp-confirmation-create-0001
New update: Idempotency-Key = erp-confirmation-update-0001Use separate keys for PATCH, pinning, decisions, relationships, files and deletion. After every successful change, store the ETag returned by the operation.
Confirmations - read one record
After creating a Confirmation or receiving its UUID, retrieve the complete record:
curl --fail-with-body --silent --show-error \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET" \
"$BASE_URL/api/v1/confirmations/{CONFIRMATION_ID}?fields=%2A"Keep the ETag from the HTTP ETag header or from data.meta.etag. Keep meta.requestId as well for diagnostics.
curl --fail-with-body --silent --show-error \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET" \
"$BASE_URL/api/v1/confirmations/{CONFIRMATION_ID}?fields=%2A&include=files%2Crelationships%2Cusers"The version with include shows the assigned Client, object relationships, requester and files in one read. If you only need synchronization data, narrow the response with fields.
Confirmations - edit with the current ETag
A safe edit always follows the same sequence: read the record, get its current ETag, prepare a small PATCH, send If-Match and a new Idempotency-Key, then store the new ETag:
{
"attributes": {
"info": "Information added after verification in the procurement system.",
"category": "IT procurement",
"description": "Confirmation updated by the integration."
}
}curl --fail-with-body --silent --show-error \
--request PATCH \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET" \
--header "Content-Type: application/json" \
--header "If-Match: {CURRENT_ETAG}" \
--header "Idempotency-Key: erp-confirmation-update-0001" \
--data-binary @confirmation-update.json \
"$BASE_URL/api/v1/confirmations/{CONFIRMATION_ID}"Success returns 200 OK and a new ETag. A normal PATCH can change descriptive fields, but do not use it for status, decision dates, dateEnd, remark or pin.
Confirmations - concurrent edit protection
If you omit If-Match, the API rejects the change:
HTTP 428 Precondition Required
code: if_match_requiredIf you send an ETag older than the current record version, you receive:
HTTP 412 Precondition Failed
code: if_match_failedAfter 412, retrieve the record again, compare its values with the change you intend to make, and only then send a new PATCH. Do not keep retrying the same request with an old ETag.
Do not try to bypass version control by putting process fields in the body:
{
"attributes": {
"status": "Confirmed",
"dateConfirmed": "2026-09-08T10:30:00Z"
}
}Use the dedicated /decision endpoint. This lets the system verify the correct Client, the current process state and concurrency.
Confirmations - pinning and unpinning
Pinning is a separate operation and is not part of a normal PATCH. Allowed values are null or a number from 0 to 3:
curl --fail-with-body --silent --show-error \
--request POST \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET" \
--header "Content-Type: application/json" \
--header "If-Match: {CURRENT_ETAG}" \
--header "Idempotency-Key: erp-confirmation-pin-0001" \
--data '{"pin":3}' \
"$BASE_URL/api/v1/confirmations/{CONFIRMATION_ID}/pin"To unpin a record, send null:
curl --fail-with-body --silent --show-error \
--request POST \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET" \
--header "Content-Type: application/json" \
--header "If-Match: {PINNED_ETAG}" \
--header "Idempotency-Key: erp-confirmation-unpin-0001" \
--data '{"pin":null}' \
"$BASE_URL/api/v1/confirmations/{CONFIRMATION_ID}/pin"Both operations require confirmations:pin:write. After each action, read the new ETag and verify the pin value.
Confirmations - the Client decision
A decision is a business action, not an ordinary record edit. Before it is made, the Confirmation must be assigned to a Client. The request must come from a key representing that Client and must contain confirmations:decision:write. The API also checks the current ETag.
Approve a Confirmation with this payload:
{
"confirmed": true,
"remark": "I confirm the request can be fulfilled."
}curl --fail-with-body --silent --show-error \
--request POST \
--header "X-Codenica-Client-Id: $PUBLIC_API_DECISION_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_DECISION_CLIENT_SECRET" \
--header "Content-Type: application/json" \
--header "If-Match: {DECISION_ETAG}" \
--header "Idempotency-Key: erp-confirmation-decision-0001" \
--data '{"confirmed":true,"remark":"I confirm the request can be fulfilled."}' \
"$BASE_URL/api/v1/confirmations/{CONFIRMATION_ID}/decision"Decline it through the same route with false:
curl --fail-with-body --silent --show-error \
--request POST \
--header "X-Codenica-Client-Id: $PUBLIC_API_DECISION_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_DECISION_CLIENT_SECRET" \
--header "Content-Type: application/json" \
--header "If-Match: {DECISION_ETAG}" \
--header "Idempotency-Key: erp-confirmation-decision-0002" \
--data '{"confirmed":false,"remark":"I decline the request."}' \
"$BASE_URL/api/v1/confirmations/{CONFIRMATION_ID}/decision"After a positive decision, the status becomes Confirmed and the system writes dateConfirmed, dateEnd and the comment. After a negative decision, the status is Declined and the system writes dateDeclined, dateEnd and the comment. Do not set these fields manually.
Confirmations - Client and requester
The Client relationship identifies the business Client who is expected to decide. It is not the technical AppUser identifier. Read the assignment together with object relationships or from one record using include=relationships.
The API also exposes a separate, read-only user collection. It contains the automatic requester, the user who created the Confirmation:
curl --fail-with-body --silent --show-error \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET" \
"$BASE_URL/api/v1/confirmations/{CONFIRMATION_ID}/user-relationships?relationshipType=requester&page=1&pageSize=20"{
"targetId": "{REQUESTER_USER_ID}",
"targetDataSet": "users",
"relationshipType": "requester",
"displayName": "{REQUESTER_NAME}",
"email": "{REQUESTER_EMAIL}",
"role": "{REQUESTER_ROLE}"
}The requester is assigned by the system. Do not set this relationship in attributes or try to change it through object relationship endpoints. Reading it requires confirmations:users:read.
Confirmations - permitted object relationships
The current Confirmation relationship catalog contains four collections:
assetscomputerclientsclientdocumentsdocument or the type returned by the targetnotesnoteEach target must exist, be visible to the user associated with the key and match the relationshipTargets list returned by schema. Confirmations do not support arbitrary collections from this catalog.
Confirmations - ordinary relationship format and Client assignment
A relationship to an asset, document or note has a relationshipType. Example for a document:
{
"targetId": "{DOCUMENT_ID}",
"targetDataSet": "documents",
"targetItemType": "invoice",
"relationshipType": "related"
}Client assignment is the exception. It has targetDataSet=clients and targetItemType=client, but no relationshipType:
{
"targetId": "{CLIENT_ID}",
"targetDataSet": "clients",
"targetItemType": "client"
}For assets, read the actual object type and send it exactly in targetItemType:
assets - targetItemType: computer
documents - targetItemType: invoice
notes - targetItemType: noteThe values above are examples. The correct type may be different in your database.
Confirmations - add, read and remove relationships
Add one relationship with a POST containing the relationship object without an additional wrapper:
curl --fail-with-body --silent --show-error \
--request POST \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET" \
--header "Content-Type: application/json" \
--header "If-Match: {CURRENT_ETAG}" \
--header "Idempotency-Key: erp-confirmation-relation-add-0001" \
--data '{"targetId":"{DOCUMENT_ID}","targetDataSet":"documents","targetItemType":"invoice","relationshipType":"related"}' \
"$BASE_URL/api/v1/confirmations/{CONFIRMATION_ID}/relationships"Read relationships as a collection:
curl --fail-with-body --silent --show-error \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET" \
"$BASE_URL/api/v1/confirmations/{CONFIRMATION_ID}/relationships?targetDataSet=documents&relationshipType=related&page=1&pageSize=50"Removing a relationship requires the current Confirmation ETag. Put the collection and target UUID in the path, and send the relationship type in the query:
curl --fail-with-body --silent --show-error \
--request DELETE \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET" \
--header "If-Match: {CURRENT_ETAG}" \
--header "Idempotency-Key: erp-confirmation-relation-delete-0001" \
"$BASE_URL/api/v1/confirmations/{CONFIRMATION_ID}/relationships/documents/{DOCUMENT_ID}?relationshipType=related"Adding or removing a relationship returns a new record version or data=true. Read the new ETag after every successful change.
Confirmations - change several relationships at once
To add or remove several relationships in one request, use relationships:batch. The body contains add and remove arrays:
{
"add": [
{
"targetId": "{ASSET_ID}",
"targetDataSet": "assets",
"targetItemType": "computer",
"relationshipType": "related"
}
],
"remove": [
{
"targetId": "{NOTE_ID}",
"targetDataSet": "notes",
"targetItemType": "note",
"relationshipType": "related"
}
]
}curl --fail-with-body --silent --show-error \
--request POST \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET" \
--header "Content-Type: application/json" \
--header "If-Match: {CURRENT_ETAG}" \
--header "Idempotency-Key: erp-confirmation-relationships-batch-0001" \
--data-binary @confirmation-relationships-batch.json \
"$BASE_URL/api/v1/confirmations/{CONFIRMATION_ID}/relationships:batch"The response contains added, removed and skipped counters. The relationship batch limit comes from context, requires the current ETag and changes the Confirmation version. For Client assignment, use the format without relationshipType.
Confirmations - file list and upload
First, you can read the files currently assigned to a Confirmation:
curl --fail-with-body --silent --show-error \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET" \
"$BASE_URL/api/v1/confirmations/{CONFIRMATION_ID}/files?page=1&pageSize=50"A list item includes, among other things, id, fileName, contentType, size, relationshipType, isMain and downloadUrl. Add a new file as multipart/form-data:
curl --fail-with-body --silent --show-error \
--request POST \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET" \
--header "If-Match: {CURRENT_ETAG}" \
--header "Idempotency-Key: erp-confirmation-file-upload-0001" \
--form "[email protected];type=application/pdf" \
"$BASE_URL/api/v1/confirmations/{CONFIRMATION_ID}/files?relationshipType=decision-form"{
"data": {
"id": "{FILE_ID}",
"fileName": "decision-form.pdf",
"contentType": "application/pdf",
"size": 48231,
"relationshipType": "decision-form",
"isMain": false,
"downloadUrl": "/api/v1/confirmations/{CONFIRMATION_ID}/files/{FILE_ID}/content"
}
}Upload requires confirmations:files:write, the current ETag and a new idempotency key. Read the size limit from data.capabilities.limits.maxUploadBytes. The Confirmations API has no main-file selection operation - do not build an integration that expects a /main endpoint.
Confirmations - download, attach and remove files
Download file content through the content endpoint and save it in binary mode:
curl --fail-with-body --silent --show-error \
--output downloaded-decision-form.pdf \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET" \
"$BASE_URL/api/v1/confirmations/{CONFIRMATION_ID}/files/{FILE_ID}/content"If the file is already stored in Codenica, attach it to a second Confirmation without uploading its content again:
curl --fail-with-body --silent --show-error \
--request POST \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET" \
--header "If-Match: {SECOND_CONFIRMATION_ETAG}" \
--header "Idempotency-Key: erp-confirmation-file-attach-0001" \
"$BASE_URL/api/v1/confirmations/{SECOND_CONFIRMATION_ID}/files/{FILE_ID}?relationshipType=reference"Detach a file from one Confirmation, or delete its final relationship, through the same DELETE route:
curl --fail-with-body --silent --show-error \
--request DELETE \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET" \
--header "If-Match: {CONFIRMATION_ETAG}" \
--header "Idempotency-Key: erp-confirmation-file-delete-0001" \
"$BASE_URL/api/v1/confirmations/{CONFIRMATION_ID}/files/{FILE_ID}"Attach creates a relationship to an existing file. If a file is still assigned to the source Confirmation, detaching it from a second record must not remove the source relationship. Before deleting the final relationship, read the file list and confirm that the selected file is the one you intend to remove.
Confirmations - batch operations
The /api/v1/confirmations:batch endpoint combines record creation, editing and deletion. The format uses an items array and separate create and update objects:
{
"items": [
{
"operation": "create",
"create": {
"itemType": "confirmation",
"attributes": {
"customId": "ERP-BATCH-CONFIRMATION-A",
"category": "Access",
"description": "First Confirmation created in a batch."
},
"relationships": [
{
"targetId": "{CLIENT_ID}",
"targetDataSet": "clients",
"targetItemType": "client"
}
]
}
},
{
"operation": "update",
"id": "{EXISTING_ID}",
"ifMatch": "{EXISTING_ETAG}",
"update": {
"attributes": {
"description": "Description updated in a batch operation."
}
}
},
{
"operation": "delete",
"id": "{RECORD_TO_DELETE_ID}",
"ifMatch": "{RECORD_TO_DELETE_ETAG}"
}
]
}curl --fail-with-body --silent --show-error \
--request POST \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: erp-confirmations-batch-0001" \
--data-binary @confirmations-batch.json \
"$BASE_URL/api/v1/confirmations:batch"{
"data": {
"items": [
{
"index": 0,
"operation": "create",
"status": 201,
"id": "{CREATED_ID}",
"data": { "meta": { "etag": "{CREATED_ETAG}" } }
}
],
"succeeded": 1,
"failed": 0
}
}Each update and delete item needs its own current ifMatch. Batch is not all-or-nothing. For a partial result, the API may return 207 Multi-Status, so inspect every item separately and do not repeat operations that already succeeded.
Confirmations - delete a record
Before deletion, retrieve the record again, verify the UUID and current ETag, then send the request with a separate idempotency key:
curl --fail-with-body --silent --show-error \
--request DELETE \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET" \
--header "If-Match: {CURRENT_ETAG}" \
--header "Idempotency-Key: erp-confirmation-delete-0001" \
"$BASE_URL/api/v1/confirmations/{CONFIRMATION_ID}"A successful response returns 200 OK and data=true. After deletion, verify that the UUID is no longer available:
curl --fail-with-body --silent --show-error \
--header "X-Codenica-Client-Id: $PUBLIC_API_CLIENT_ID" \
--header "X-Codenica-Client-Secret: $PUBLIC_API_CLIENT_SECRET" \
"$BASE_URL/api/v1/confirmations/{CONFIRMATION_ID}"The expected result is 404 Not Found with code confirmation_not_found. Deleting a Confirmation does not automatically delete related documents, assets or notes.
Confirmations - errors, limits and a safe sequence
Errors use the Problem Details format. Log status, code and requestId, but never the Client Secret or complete headers:
validation_failedauthentication_required or authentication_failedconfirmation_client_requiredconfirmation_not_foundconfirmation_unique_constraint or confirmation_concurrency_conflictif_match_failed, if_match_requiredconfirmation_decision_rejected, confirmation_pin_rejectedrate_limit_exceededRetry-After.Read X-RateLimit-Limit and X-RateLimit-Remaining. Cache schema and field values, limit concurrency and use backoff after 429.
A safe sequence is: context, schema, choose the Client, list or read, create with Idempotency-Key, store the UUID and ETag, add relationships or files, edit with If-Match, pin, decide through /decision, verify by reading the record and only then delete it. The same sequence can be implemented in n8n by passing the UUID, ETag and idempotency keys between steps.
