Assets in Codenica API
Below you will find practical examples of working with assets stored in Codenica. In the Public API, the technical name of this object is assets. An individual asset can represent a computer, device, software, licence or another inventory item available in your database.
Before sending your first request, create the API key described in the Codenica API - introduction article. The sections below cover the full asset workflow: checking the schema and listing records, creating and editing them, managing relationships and files, using batch operations and deleting records.
- reading individual assets and paginated lists;
- searching and filtering inventory fields;
- creating records and applying partial updates;
- protecting changes with ETag and safely retrying requests with Idempotency-Key;
- linking assets with other assets and Codenica objects;
- uploading, downloading, attaching and deleting files;
- reading statistics and field values and processing several operations in one request.
The examples use itemType=computer. Every database can have a different set of fields. Read the schema for the type you are working with before writing data.
Assets - API address and deployment choice
Send requests to the public address where your Codenica installation is available. Do not use the database address, a container address or a port that can be reached only from inside the server. Asset paths begin with:
{BASE_URL}/api/v1/assetsFor Codenica Cloud, use the public domain assigned to your installation:
export BASE_URL="https://your-company.codenica.com"In the default On-Premise installation, the address registered locally by Codenica Discovery is:
export BASE_URL="http://codenica.local:5150"If the administrator has published the On-Premise installation through a company domain, reverse proxy, HTTPS or another external port, use the exact address provided for that installation:
export BASE_URL="https://api.your-company.example"Do not try to choose the database through an additional query-string or body field. The correct database is selected from the host address. Do not use localhost when the integrating application runs on a different computer from the API. In production, use HTTPS when the installation is published with a certificate.
Assets - API key scopes
Create the API key in Codenica under Settings - API - API Keys. For an integration that works with assets, select only the scopes it needs. API access does not extend the permissions of the user represented by the key or the data access configured in your database.
Basic asset scopes:
assets:read- listing and reading assets;assets:write- creating and editing assets;assets:delete- deleting assets;assets:schema- reading fields, their properties and relationship targets;assets:stats- statistics and field values used for filtering;assets:relationships:read- reading relationships;assets:relationships:write- adding and removing relationships;assets:files:read- listing and downloading files;assets:files:write- uploading, attaching, selecting the main file and deleting files;assets:technical:read- reading fields marked as technical;assets:technical:write- writing technical fields that are writable;assets:secrets:write- writing secret fields when the schema exposes them.
Technical and secret fields are not needed for ordinary inventory reads or updates. Secrets are written only when the appropriate scope is present and are not returned in responses.
After creating the key, copy the Client ID and Client Secret to the secure store used by the integrating application. The secret is shown only during key creation or rotation. The external application uses these two values, not the panel session or a Bearer JWT.
Assets - authentication and context
Send every request with the two API key headers:
export CLIENT_ID="cna_your_client_id"
export CLIENT_SECRET="cns_your_client_secret"
curl --request GET --url "$BASE_URL/api/v1/context" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"Before starting the actual integration, read /api/v1/context. Check that the response refers to the correct database, that caller.authentication is api_key and that the scopes include the operations you need.
In the capabilities object, confirm that assets is available and read the limits, including maxPageSize, maxUploadBytes and the request limit. Keep meta.requestId. This identifier helps locate a specific request in logs or when contacting the administrator.
If the context points to another database or does not contain a required scope, stop the integration and correct the key or API address. Do not try to change the database through data sent in the body.
Assets - fields and relationship schema
The schema shows what can be read and written in the database you are using. Retrieve it for the asset type you need:
curl --request GET --url "$BASE_URL/api/v1/assets/schema?itemType=computer" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"For each field, check at least:
- the name and data type;
readableandwritable;required;technicaland, if present,secretWriteOnly;- the values in
options; - maximum length and uniqueness;
- automatic generation and additional database requirements.
The schema can differ depending on itemType and the inventory configuration. For example, the category field can accept different values in two databases. Do not build the integration on the assumption that the field or option list is fixed.
The schema also contains the relationship target catalogue. Before sending a relationship, check that the selected object type, its targetItemType and the relationship type match the response.
Assets - available endpoints
The map below lists the main paths used by an integration. Replace {id}, {targetDataSet}, {targetId} and {fileId} with the correct identifiers.
GET /api/v1/assets- asset list;GET /api/v1/assets/schema- schema;GET /api/v1/assets/stats- statistics;GET /api/v1/assets/values- field values;GET /api/v1/assets/{id}- individual asset;POST /api/v1/assets- create;PATCH /api/v1/assets/{id}- partial update;DELETE /api/v1/assets/{id}- delete;POST /api/v1/assets:batch- create, update and delete operations;GET /api/v1/assets/{id}/relationships- relationship list;POST /api/v1/assets/{id}/relationships- add a relationship;POST /api/v1/assets/{id}/relationships:batch- group relationship changes;DELETE /api/v1/assets/{id}/relationships/{targetDataSet}/{targetId}- remove a relationship;GET /api/v1/assets/{id}/files- file list;POST /api/v1/assets/{id}/files- upload a file;POST /api/v1/assets/{id}/files/{fileId}- attach an existing file;PUT /api/v1/assets/{id}/files/{fileId}/main- select the main file;DELETE /api/v1/assets/{id}/files/{fileId}- delete a file;GET /api/v1/assets/{id}/files/{fileId}/content- download file content.
The scope required for a path follows the operation name. If you receive 403, first check the key scopes and the permissions of the user assigned to the key.
Assets - listing and pagination
Read the list page by page. This example returns the first twenty visible assets of type computer:
curl --request GET --url "$BASE_URL/api/v1/assets?itemType=computer&page=1&pageSize=20" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"A collection response has a structure similar to:
{
"data": {
"items": [
{
"id": "11111111-1111-1111-1111-111111111111",
"itemType": "computer",
"attributes": {
"customId": "CND-OFFICE-PC-01",
"name": "Office computer 01",
"category": "Hardware"
},
"meta": {
"dateUpdated": "2026-09-07T10:00:00Z",
"etag": "\"etag-v1\""
}
}
],
"page": 1,
"pageSize": 20,
"totalItems": 1,
"totalPages": 1,
"hasNextPage": false
},
"meta": {
"requestId": "request-id-from-response"
}
}Do not assume that the first page contains all data. Continue while hasNextPage is true, or use totalPages. Do not set pageSize above the limit returned in the context.
Assets - search and filters
Use search for a simple search. For more precise field selection, use the short parameters or the filter parameter:
curl --request GET --url "$BASE_URL/api/v1/assets?itemType=computer&search=office&page=1&pageSize=50" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"
curl --request GET --url "$BASE_URL/api/v1/assets?customId=CND-OFFICE-PC-01" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"
curl --request GET --url "$BASE_URL/api/v1/assets?filter=category:contains:Hardware" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"You can use parameters including itemType, ids, search, name, category, status, location, department, manufacturer, model, serialNumber, inventoryNumber, customId, tag, createdAfter, createdBefore, updatedAfter and updatedBefore.
The filter parameter supports operators including:
eq- equals;ne- not equal;in- one of the supplied values;contains- contains a fragment;startsWithandendsWith- starts or ends with the supplied text;emptyandnotEmpty- empty or non-empty field;gt,gte,lt,lte- comparisons.
filter=status:eq:In service
filter=serialNumber:contains:ABC
filter=category:in:Hardware,Software
filter=description:notEmpty:If a value contains spaces or special characters, encode it according to URL rules. When filtering by identifiers, remember that ids limits the result to the specified UUIDs.
Assets - selecting fields and including data
The fields parameter limits the fields returned in the response. It is useful when the integration needs only a few values:
curl --request GET --url "$BASE_URL/api/v1/assets?fields=id,itemType,name,category,status" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"Use include to read related data. For assets, the available values are files and relationships:
curl --request GET --url "$BASE_URL/api/v1/assets/$ASSET_ID?include=files,relationships" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"The scopes for included data must be allowed by the key. If the key does not have assets:files:read or assets:relationships:read, read the record without that include or extend the key according to the principle of least privilege.
fields=* does not reveal secret fields. Do not treat field selection as a way to bypass permissions. Technical and secret fields appear only when the scopes and schema allow them.
Assets - creating a record
Use POST /api/v1/assets to create a record. Send the technical itemType and writable fields in the attributes object. This example creates an office computer:
export IDEMPOTENCY_KEY="asset-create-20260907-0001"
curl --request POST --url "$BASE_URL/api/v1/assets" \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Idempotency-Key: $IDEMPOTENCY_KEY" \
--data-raw '{
"itemType": "computer",
"attributes": {
"customId": "CND-OFFICE-PC-01",
"name": "Office computer 01",
"category": "Hardware",
"manufacturer": "Lenovo",
"model": "ThinkCentre",
"location": "Warsaw",
"status": "In service"
}
}'In the basic model, at least name and category are required, but your database can have additional requirements, option values or uniqueness rules. Always compare the body with the current schema.
A successful response has status 201 Created. Save data.id, data.meta.etag and the HTTP ETag header. An example response fragment:
{
"data": {
"id": "11111111-1111-1111-1111-111111111111",
"itemType": "computer",
"attributes": {
"customId": "CND-OFFICE-PC-01",
"name": "Office computer 01",
"category": "Hardware"
},
"meta": {
"customId": "CND-OFFICE-PC-01",
"dateCreated": "2026-09-07T10:00:00Z",
"dateUpdated": "2026-09-07T10:00:00Z",
"etag": "\"etag-v1\""
}
},
"meta": {
"requestId": "request-id-from-response",
"etag": "\"etag-v1\""
}
}Do not send your own id unless the schema and integration require a controlled UUID. If you use your own identifier, it must be unused and meet the API requirements.
Assets - safely retrying a create request
After a timeout, you may not know whether the server created the record. Do not create a new idempotency key without checking. Send exactly the same request with the same Idempotency-Key and identical body:
curl --request POST --url "$BASE_URL/api/v1/assets" \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Idempotency-Key: $IDEMPOTENCY_KEY" \
--data-raw '{
"itemType": "computer",
"attributes": {
"customId": "CND-OFFICE-PC-01",
"name": "Office computer 01",
"category": "Hardware",
"manufacturer": "Lenovo",
"model": "ThinkCentre",
"location": "Warsaw",
"status": "In service"
}
}'Repeating the identical operation reproduces the first response and does not create a second record. The same key must not later describe a different body, endpoint or intention. Such reuse returns 422 idempotency_key_reused.
Idempotency also applies to other mutating requests: updates, relationship changes, file operations and deletions. Use a new value for every new intention.
Assets - reading one record
After creating or finding an asset, read it by UUID:
export ASSET_ID="11111111-1111-1111-1111-111111111111"
curl --request GET --url "$BASE_URL/api/v1/assets/$ASSET_ID?include=files,relationships" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"The response contains id, the technical itemType, fields in attributes and metadata in meta. You will find the ETag in the HTTP header and usually also in data.meta.etag and the envelope meta.etag.
Read the asset again before every change. This includes field updates, relationships, uploads, selecting the main file, deleting a file and deleting the whole record. This ensures that the operation uses the current version rather than a value kept in the integration's memory.
Assets - partial update with ETag
PATCH changes only the fields included in the body. You do not have to send the complete record. Add a fresh ETag from the latest read and a new idempotency key:
export ASSET_ETAG='"etag-v1"'
export IDEMPOTENCY_KEY="asset-update-20260907-0001"
curl --request PATCH --url "$BASE_URL/api/v1/assets/$ASSET_ID" \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Idempotency-Key: $IDEMPOTENCY_KEY" \
--header "If-Match: $ASSET_ETAG" \
--data-raw '{
"attributes": {
"name": "Office computer 01 - updated",
"description": "Asset updated by the integration."
}
}'After success, the response has status 200 OK and contains a new ETag. Replace the previous value before the next operation. Sending null clears a field when the field is not required and the schema allows an empty value.
The body must contain an actual change to a writable field, custom value or relationship. A read-only, technical or secret field may require a separate scope or endpoint.
Assets - protecting against an outdated version
ETag prevents a record from being overwritten by changes made in the meantime by another person or integration. Two situations need separate handling:
428 if_match_required- the requiredIf-Matchor, for a mutation,Idempotency-Keyis missing;412 if_match_failed- the supplied ETag is no longer current.
Example response for a stale ETag:
{
"type": "https://docs.codenica.com/errors/if_match_failed",
"title": "Precondition failed.",
"status": 412,
"detail": "The supplied ETag is not the current asset version.",
"instance": "/api/v1/assets/11111111-1111-1111-1111-111111111111",
"code": "if_match_failed",
"requestId": "request-id-from-response"
}After 412, read the asset again, compare the current values with the change you want to make and only then send a new PATCH with the new ETag. Do not endlessly retry the same request with a stale ETag. A specific If-Match value is the recommended integration pattern. The * value is a controlled scenario and should not replace version checks during ordinary synchronisation.
Assets - adding relationships
A relationship links an asset with another visible object. Available targets include:
assets, clients, documents, tickets, changes, problems, releases,
notes, worktasks, confirmations, requesteditemsThis example links two computers. If you send targetItemType, it must match the actual type of the target:
export TARGET_ASSET_ID="22222222-2222-2222-2222-222222222222"
export IDEMPOTENCY_KEY="asset-relation-add-20260907-0001"
curl --request POST --url "$BASE_URL/api/v1/assets/$ASSET_ID/relationships" \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Idempotency-Key: $IDEMPOTENCY_KEY" \
--header "If-Match: $ASSET_ETAG" \
--data-raw '{
"targetId": "22222222-2222-2222-2222-222222222222",
"targetDataSet": "assets",
"targetItemType": "computer",
"relationshipType": "related"
}'The target must exist and be visible to the user assigned to the key. An asset cannot point to itself. Depending on the target, the API may store relationshipType. For notes, worktasks and requesteditems, do not send this field because the current relationship model does not store it.
Adding a relationship changes the version of the source asset. After a 201 Created response, read the source again and use the new ETag for the next change.
Assets - reading and removing relationships
Read relationships through the collection endpoint, optionally limiting the result to a selected target dataset:
curl --request GET --url "$BASE_URL/api/v1/assets/$ASSET_ID/relationships?targetDataSet=assets&page=1&pageSize=50" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"A relationship item can include targetId, targetDataSet, targetItemType, relationshipType, customId and name. A relationship read does not return the complete target object unless you perform a separate read or use include=relationships.
To remove a relationship, you need a fresh ETag for the source:
export IDEMPOTENCY_KEY="asset-relation-delete-20260907-0001"
curl --request DELETE --url "$BASE_URL/api/v1/assets/$ASSET_ID/relationships/assets/$TARGET_ASSET_ID?relationshipType=related" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Idempotency-Key: $IDEMPOTENCY_KEY" \
--header "If-Match: $ASSET_ETAG"A successful removal returns 200 OK with data: true. When removing a relationship through the direct endpoint, the relationshipType query value must match the relationship you want to remove. Read the collection and the source asset again after the operation.
Assets - changing several relationships at once
Use relationships:batch when you need to add or remove several relationships. One request can contain both add and remove arrays:
export IDEMPOTENCY_KEY="asset-relations-batch-20260907-0001"
curl --request POST --url "$BASE_URL/api/v1/assets/$ASSET_ID/relationships:batch" \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Idempotency-Key: $IDEMPOTENCY_KEY" \
--header "If-Match: $ASSET_ETAG" \
--data-raw '{
"add": [
{
"targetId": "22222222-2222-2222-2222-222222222222",
"targetDataSet": "assets",
"targetItemType": "computer",
"relationshipType": "related"
}
],
"remove": [
{
"targetId": "33333333-3333-3333-3333-333333333333",
"targetDataSet": "clients",
"relationshipType": "owner"
}
]
}'The 200 OK response contains the added, removed and skipped counters. Repeating a relationship that already exists may be counted as skipped. A relationship batch also changes the source ETag, so read the asset again afterwards.
For items referring to notes, worktasks and requesteditems, omit relationshipType. Every target must be visible and match the relationship catalogue returned by the schema.
Assets - listing and uploading files
Files are stored alongside the asset and have their own identifiers. You can first read the current list:
curl --request GET --url "$BASE_URL/api/v1/assets/$ASSET_ID/files?page=1&pageSize=50" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"A list item contains fields including id, name, fileName, contentType, size, relationshipType, isMain and downloadUrl.
Upload uses multipart/form-data. To change the asset, you need a fresh ETag and a new idempotency key:
curl --request POST --url "$BASE_URL/api/v1/assets/$ASSET_ID/files?makeMain=true&relationshipType=documentation" \
--header "Accept: application/json, application/problem+json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Idempotency-Key: asset-file-upload-20260907-0001" \
--header "If-Match: $ASSET_ETAG" \
--form "file=@./asset-manual.txt;type=text/plain"makeMain=true selects the uploaded file as the main file. The relationshipType parameter describes the file's purpose, for example documentation or manual. The default upload limit is 20 MiB, but check the current maxUploadBytes value in the context.
The file name must not contain a path or a .. segment. Do not store secrets in the file name, metadata or content unless this is necessary.
Upload returns 201 Created and a file object. Read the asset again after the operation because its ETag has changed.
Assets - downloading and selecting the main file
Download file content through the /content endpoint. The response is binary content, not a JSON envelope:
export FILE_ID="44444444-4444-4444-4444-444444444444"
curl --request GET --url "$BASE_URL/api/v1/assets/$ASSET_ID/files/$FILE_ID/content" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--output ./asset-file-download.txtThe downloadUrl in a file object is a relative address. Add the deployment host to it and use the same authentication headers.
If an asset has several files, you can select the main file. This operation changes the asset and requires its current ETag:
curl --request PUT --url "$BASE_URL/api/v1/assets/$ASSET_ID/files/$FILE_ID/main" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Idempotency-Key: asset-set-main-20260907-0001" \
--header "If-Match: $ASSET_ETAG"A successful response has status 200 OK and normally returns data: true. Read the file list after the change and check that the selected item has isMain=true and the previous main file has isMain=false. Then read the asset's new ETag.
A small file can be rounded to 0 MB in the interface. Check the actual size in the size field or by counting the downloaded bytes.
Assets - attaching an existing file
If a file is already stored in the system, you can attach it to another asset without uploading its content again:
export TARGET_ASSET_ID="55555555-5555-5555-5555-555555555555"
export TARGET_ASSET_ETAG='"target-etag-v1"'
curl --request POST --url "$BASE_URL/api/v1/assets/$TARGET_ASSET_ID/files/$FILE_ID?makeMain=true&relationshipType=manual" \
--header "Accept: application/json, application/problem+json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Idempotency-Key: asset-attach-file-20260907-0001" \
--header "If-Match: $TARGET_ASSET_ETAG"A 201 Created response contains the attached file identifier and its metadata. If you used makeMain=true, read the list again and check that isMain is true.
Attaching a file also changes the version of the target asset. Read the current target ETag before the next file operation. Delete a file from one asset only after confirming that it is no longer needed there or in its other relationships.
Assets - deleting a file
Deleting a file changes the asset. Read the current ETag and use a separate idempotency key:
curl --request DELETE --url "$BASE_URL/api/v1/assets/$ASSET_ID/files/$FILE_ID" \
--header "Accept: application/json, application/problem+json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Idempotency-Key: asset-file-delete-20260907-0001" \
--header "If-Match: $ASSET_ETAG"A successful response has status 200 OK and data: true. Read the file list and the asset ETag after every deletion. If you delete several files, the ETag for the next operation must come from the previous completed change.
Deleting a file does not delete the whole asset. Trying to download deleted content returns 404 file_not_found. If a file is attached to several assets, check before deletion that you are acting on the correct relationship and that the file is no longer needed.
Assets - statistics and field values
The stats endpoint helps build a summary of visible data. You can limit the result to an asset type and specify the field for which you want values:
curl --request GET --url "$BASE_URL/api/v1/assets/stats?itemType=computer&field=category&limit=20" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"The response can contain the total number of visible assets, a breakdown by itemType, the field name and its values:
{
"data": {
"total": 11,
"byItemType": {
"computer": 11
},
"field": "category",
"values": [
"Laptop",
"Desktop",
"Hardware"
]
},
"meta": {
"requestId": "request-id-from-response"
}
}The values endpoint returns values useful for building filter lists:
curl --request GET --url "$BASE_URL/api/v1/assets/values?field=category&itemType=computer&search=hard&limit=20" \
--header "Accept: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET"For the search value hard, the result can contain Hardware. Both endpoints are read-only, require assets:stats and do not require an ETag. Results include only data visible to the user.
Assets - batch operations
Batch combines creation, updating and deletion in one request. Each item has its own operation, and update and delete pass their own ETag in the ifMatch field:
curl --request POST --url "$BASE_URL/api/v1/assets:batch" \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Idempotency-Key: assets-batch-20260907-0001" \
--data-raw '{
"items": [
{
"operation": "create",
"create": {
"itemType": "computer",
"attributes": {
"customId": "CND-BATCH-PC-01",
"name": "Computer created in a batch",
"category": "Hardware"
}
}
},
{
"operation": "update",
"id": "11111111-1111-1111-1111-111111111111",
"ifMatch": "\"current-etag\"",
"update": {
"attributes": {
"description": "Description updated in a batch."
}
}
},
{
"operation": "delete",
"id": "22222222-2222-2222-2222-222222222222",
"ifMatch": "\"current-etag\""
}
]
}'If all items succeed, the response has status 200 OK. The result contains succeeded, failed and the result of each item with its index, operation and status.
Batch is not an all-or-nothing transaction. When only some items succeed, the API returns 207 Multi-Status and does not roll back the successful items. Check every item. If the batch creates records, save their IDs and ETags from the individual results.
Each item requires the scope corresponding to its operation. A batch request does not extend the key's permissions.
Assets - deleting a record
Read the asset again before deletion and use its current ETag:
export IDEMPOTENCY_KEY="asset-delete-20260907-0001"
curl --request DELETE --url "$BASE_URL/api/v1/assets/$ASSET_ID" \
--header "Accept: application/json, application/problem+json" \
--header "X-Codenica-Client-Id: $CLIENT_ID" \
--header "X-Codenica-Client-Secret: $CLIENT_SECRET" \
--header "Idempotency-Key: $IDEMPOTENCY_KEY" \
--header "If-Match: $ASSET_ETAG"A successful deletion returns 200 OK with data: true. A later read of the UUID returns 404 asset_not_found. Deletion runs the existing domain cleanup, but the Public API does not automatically delete related business objects such as documents, tickets or clients.
After deletion, remove the identifier from the integration's local index or mark the record as inactive. Do not try to update the deleted UUID again.
Assets - errors, limits and security
API errors use the Problem Details format with additional Codenica fields:
{
"type": "https://docs.codenica.com/errors/asset_not_found",
"title": "Asset not found.",
"status": 404,
"detail": "The asset does not exist or is outside the caller's access scope.",
"instance": "/api/v1/assets/11111111-1111-1111-1111-111111111111",
"code": "asset_not_found",
"requestId": "request-id-from-response"
}In application logic, rely primarily on status and code. The detail text is a human-readable hint and can change.
400- invalid body, parameter or field value;401- missing or invalid authentication;403- missing scope or user permission;404- asset, file or relationship target does not exist or is not visible;409- data or domain-state conflict;412- outdated ETag;413- upload or body is too large;428- ETag or Idempotency-Key is required;429- request limit exceeded;500or503- server error or temporary unavailability.
Read X-RateLimit-Limit, X-RateLimit-Remaining and, for 429, Retry-After. Use controlled retries with increasing delays. Never store the Client Secret in a repository, URL, browser-delivered code, command history or logs.
Assets - complete integration workflow
- Establish the correct API address. For On-Premise, check that the integration can reach
http://codenica.local:5150or the address published by the administrator. - Create a separate API key for this integration and select the minimum required scopes.
- Store the Client ID and Client Secret in a secure store.
- Send
GET /api/v1/contextand check that the response refers to the correct database; also check the caller, scopes and limits. - Send
GET /api/v1/assets/schema?itemType=computerand adapt the body to the current fields. - Read the list with pagination, search or filters.
- Create an asset with
POSTand a newIdempotency-Key. - Save the UUID and ETag.
- Read the current record before every change.
- Perform updates, relationships, file operations and deletion with a specific ETag and a new idempotency key.
- After every successful mutation, save the new ETag and read the result again when needed.
- After
412, read the record, resolve the conflict and only then retry the operation. - For larger sets of changes, use batch but check every item because batch is not a transaction.
- Handle
429and never log secrets. - Delete the API key when the integration is no longer used.
This approach lets the integration use inventory data without depending on the internal structure of the database. If the field configuration, permissions or deployment address changes, read the context and schema again instead of relying on old assumptions.
