Skip to main content
The inventory endpoints return your assets in every category: cloud resources, computers, custom assets, information assets, and employees. You can read and filter all of them. You can create, update, and delete only custom and information assets. Reads require Read access (all:read). Writes require Write access (all:write). See Scopes.

Categories

Every asset has a categoryKey: List the categories with GET /v1/inventory/categories.

What you can write

You can create, update, and delete only CUSTOM and INFORMATION assets. Every other category, including CLOUD, COMPUTER, and EMPLOYEE, is read-only. Their data comes from the Secfix integrations that discover them, so the API can’t change their owner, description, classification, or tags either.
  • An unknown categoryKey returns 400 validation_failed.
  • In a batch, an asset in a read-only category fails only that record, with resource_not_writable.
  • Your workspace’s category settings and the Secfix tags on an asset can stop some fields from changing. See Update an asset and Update assets in a batch.

List and filter assets

GET /v1/inventory/assets returns a cursor-paginated list. Narrow it with query parameters:
To get one asset by its id, call GET /v1/inventory/assets/{id}. An unknown id returns 404 not_found. Every asset carries two read-only status fields:
  • ownerStatus is COMPLETE when an owner is assigned, else INCOMPLETE.
  • auditStatus is the audit status the Secfix app shows: COMPLETE when every field the asset’s category requires for an audit is set, else INCOMPLETE. It’s left out when Secfix hasn’t calculated it yet.

Create an asset

POST /v1/inventory/assets creates one CUSTOM or INFORMATION asset:
The response is 201 Created with the full asset, including its new id. If an asset with the same externalSource and externalAssetId already exists, it is updated instead and the response is 200 OK. See Create or update by your own id.
  • customIdentifier is the serial number or asset ID shown in Secfix as ID/Serial No. You can edit it later.
  • customIdentifier is not a deduplication key. Two assets can share the same customIdentifier or name. To identify an asset in your own system, use externalSource and externalAssetId.
  • A create body has no tags field. If you send tags, the API ignores them. Set tags afterwards with the single-asset PATCH.
  • Without an owner, the asset is still created. It shows as incomplete in Secfix until you assign one.
  • The asset looks exactly like one added in the Secfix app.

Set the owner

Set the owner with either field:
  • ownerId: the employee’s id from GET /v1/employees.
  • ownerEmail: the owner’s email address, matched case-insensitively. It must belong to an active member of your workspace who is included in Secfix.
Sending both returns 400 validation_failed on ownerEmail. If no member matches the email, the request fails with validation_failed (unknown owner). If more than one member matches, it fails with validation_failed (ambiguous owner). Send ownerId instead.
Without externalSource and externalAssetId, duplicates are allowed, so a create that runs twice makes two assets. After a 5xx, nothing may be stored under your Idempotency-Key, so the same key doesn’t stop a retry from creating the asset again. After a 5xx or a timeout, wait a few minutes. Then check whether the asset exists before you retry. See Idempotency.

Create or update by your own id

Send externalSource and externalAssetId on a create to tie the asset to its record in your own system:
  • externalSource names the system the asset comes from. You choose the value. Use the same value every time.
  • externalAssetId is the asset’s id in that system.
When an asset in the same category already has that pair, POST /v1/inventory/assets updates it instead of creating a new one:
  • No match: the asset is created, and the response is 201 Created.
  • A match: that asset is updated, and the response is 200 OK with the same id. Only the fields you send change.
  • A match on an asset that’s hidden in the Secfix app returns 403 resource_not_writable, and the asset isn’t changed.
  • Send both fields or neither. Sending only one returns 400 validation_failed naming the missing one.
  • The pair is unique per workspace, category, and externalSource, among assets that haven’t been deleted. Values are matched exactly, so acme-cmdb and ACME-CMDB are different sources.
  • The same pair in the other category is a different asset.
  • The pair is set on create and can’t be changed. A PATCH that sends externalSource or externalAssetId returns 400 validation_failed.
  • After you delete the asset, the pair is free again: the next create with it makes a new asset.
  • If two requests create the same pair at the same moment, one of them gets 409 write_conflict. Retry it after the Retry-After header: it then updates the asset the other request created.
Find the asset by its pair with GET /v1/inventory/assets?externalSource=acme-cmdb&externalAssetId=printer-0042.

Create assets in a batch

POST /v1/inventory/assets/batch-create creates up to 100 assets in one request. Each record in records has the same shape as a single create:
The response is 200 OK with one result per record. For each created record, id is the new asset’s id. See Read a batch result.
  • A batch can contain several records with the same name.
  • A record whose externalSource and externalAssetId match an asset in its category updates that asset instead. Its result has action: UPDATED, so you can resend a whole list without creating duplicates.
  • The same categoryKey, externalSource, and externalAssetId twice in one request rejects the whole request with 400 validation_failed on records. Nothing is created.
  • An owner mistake fails only that record, with validation_failed and field set to ownerEmail or ownerId. Owner mistakes are: sending both ownerId and ownerEmail, an unknown owner, or an ambiguous owner. The batch still returns 200.

Update an asset

PATCH /v1/inventory/assets/{id} updates one CUSTOM or INFORMATION asset. Send only the fields you want to change:
The response is 200 OK with the updated asset. You can update these fields:
  • name: 1–255 characters. Surrounding spaces are removed, and a blank name is rejected.
  • customIdentifier: up to 255 characters.
  • dataStored: containsUserData, containsPatientData, and userDataInfo. Fields you leave out stay as they are.
  • ownerId or ownerEmail: the new owner. Send one of them, not both. The owner rules are the same as on create.
  • description: up to 500 characters.
  • classification: RESTRICTED, CONFIDENTIAL, INTERNAL, PUBLIC, or UNKNOWN, in any case.
  • tags: up to 20 entries. Each key must be the name of a tag that already exists in your workspace. Create tags in the Secfix app first: the API can’t create them, and an unknown key returns 400 validation_failed. Each tag gets the value you send. tags replaces the asset’s tags: a tag you leave out is removed, so send every tag you want to keep. [] removes them all. Leave tags out to keep the current tags.
  • Tags that Secfix manages, such as SecfixOwner, come back on reads with readOnly: true. You can’t write them: sending one in tags returns 400 validation_failed. Send only keys that reads return with readOnly: false.
externalSource and externalAssetId are set on create and can’t be changed. Sending either one in a PATCH returns 400 validation_failed.
  • Updating an asset in any other category (a computer, a cloud resource, or an employee) returns 403 resource_not_writable.
  • Changing the owner, description, or a dataStored field returns 400 validation_failed naming the field when your category settings don’t include that field, or a Secfix tag on the asset sets it, as in the Secfix app. Sending a field with the value it already has isn’t a change, so it’s never rejected. A rejected request changes nothing.
Every write except DELETE requires an Idempotency-Key header.

Update assets in a batch

PATCH /v1/inventory/assets/batch-update updates up to 100 assets in one request. Each record in records carries an asset id and its own values:
The response is 200 OK with one result per record. Each result’s id is the id you sent. See Read a batch result.
  • Each record accepts the same fields as the single-asset PATCH, except tags.
  • A record that includes tags fails with field set to tags. Set tags with the single-asset PATCH.
  • An asset outside CUSTOM and INFORMATION (a computer, a cloud resource, or an employee) fails with resource_not_writable.
  • Records follow the Secfix app’s bulk edit. Some fields can’t be bulk-edited on an asset: fields not in your category settings, fields a Secfix tag sets, and fields marked not editable. This can include classification. Such a field is skipped, not rejected:
    • The other fields are saved, and the result is SUCCESS with the skipped fields in skippedFields.
    • When every field you sent is skipped, nothing is saved and the record fails with not_editable.
    The single-asset PATCH checks fewer fields: it rejects only an owner, description, or dataStored change that your category settings don’t include or a Secfix tag sets, and saves the other fields.
  • A record with no fields to change fails with field set to body.
  • An owner mistake fails only that record, with validation_failed and field set to ownerEmail or ownerId.
  • An unknown id fails with not_found.
  • An id can appear only once. A repeated id returns 400 validation_failed.
In this example, the first record sent description and classification, and its category doesn’t let you bulk-edit description. The second record sent only classification, which its category doesn’t let you bulk-edit:
Response

Delete an asset

DELETE /v1/inventory/assets/{id} deletes one CUSTOM or INFORMATION asset.
  • The response is 204 No Content.
  • DELETE doesn’t take an Idempotency-Key header.
  • Deleting an asset that was already deleted returns 404 not_found. So does an unknown id.
  • Deleting an asset in any other category returns 403 resource_not_writable.

Delete assets in a batch

POST /v1/inventory/assets/batch-delete deletes up to 100 assets in one request. Each record in records carries the id of one asset:
The response is 200 OK with one result per record. Each result’s id is the id you sent. See Read a batch result.
  • An unknown id, or one already deleted, fails with not_found.
  • An asset outside CUSTOM and INFORMATION fails with resource_not_writable.
  • An id can appear only once. A repeated id returns 400 validation_failed.

Read a batch result

The three batch endpoints (create, update, and delete) share these rules:
  • A request carries 1–100 records.
  • Every batch request requires an Idempotency-Key header.
  • If the request itself is invalid, the API answers 400 and writes nothing. That covers an empty list, more than 100 records, a malformed body, and a repeated id.
  • An id in records that isn’t a UUID fails the whole request with 400 malformed_request.
  • Otherwise the response is always 200 OK, even when some or all records fail.
  • Each record is saved on its own. A failing record never undoes the others.
The response lists one result per record, in request order:
Response
Check status on every result. A 200 doesn’t mean every record succeeded.

Retry failed records

To retry, resend only the failed records under a new Idempotency-Key. Match them by index to the records you sent.
  • Fix validation_failed, resource_not_writable, not_editable, and not_found records before you resend them. A not_editable record needs a change in the asset’s category settings in the Secfix app, or a single-asset PATCH after that.
  • You can resend internal_error records as they are.
  • Wait a second or two before you resend write_conflict records. The record result has no Retry-After.
  • Reusing the original key replays the stored response, which is kept for at least 24 hours. It doesn’t run the records again.
  • The index values in the new response refer to positions in the new request.

When a batch fails or times out

A batch that answers 5xx or times out may have saved some records already, because each record is saved on its own. Only a 2xx response is stored under your Idempotency-Key. After a 5xx, or a request that never finished, nothing may be stored, and a resend under the same key can run every record again, exactly like a new key. Running a batch update or delete again is safe for your data. Wait a few minutes, then resend it under the same key. A delete that runs again reports the assets the first run already deleted as ERROR not_found. An update that runs again overwrites any edits made in Secfix in the meantime. If every record in a batch create carries externalSource and externalAssetId, resend the whole batch under a new Idempotency-Key. Records the first request already created are updated, not created again (action: UPDATED). Without them, a batch create can create an asset twice if the first request is still running when you resend it. A request can keep running on our side after your client times out. To avoid duplicates:
  1. Wait a few minutes, then list your assets in that category and find the records from your request that already exist. Names and customIdentifier values don’t have to be unique, so match them carefully, or send externalSource and externalAssetId next time.
  2. List again a minute later. If the results changed, the first request is still running: wait and list again until two lists agree.
  3. Send only the records that don’t exist yet, under a new Idempotency-Key. Don’t reuse the original key: if the first request finished with 200, a changed body under that key returns 409 idempotency_conflict.
  4. Check results in the response, as described in Read a batch result.