Skip to main content
Version: v12

Dataset Write API

The Dataset Write API lets you create, update, and delete records of your writable data models from your own scripts or agents, and bulk-update a single attribute across many records at once. It is the write counterpart to the read-only BQL API: reads stay on BQL, and every mutation goes through this surface.

Writes are subject to the same access control and validation as data entered through the Brinqa UI: model, row, and attribute permissions are enforced, and consolidated models route through manual entry. You never send the application; it is derived from the data model. The examples below use Vulnerability records to make the calls concrete, but the same calls work on any writable data model.

Authentication​

The Dataset Write API uses API tokens for authentication. See API Token Authentication for instructions on generating, using, and managing API tokens. Pass the token in the Authorization header using the ApiKey scheme:

Authorization: ApiKey <your-api-token>

The data model identifier​

Every endpoint takes an {identifier} path parameter that names the data model to write to. It is resolved flexibly, in this order:

  1. A numeric value is resolved as the internal data model id.
  2. Otherwise, a case-insensitive match against the resource name. The canonical resource name is camelCase plural (for example vulnerabilities), but case is ignored, so Vulnerabilities resolves too.
  3. Otherwise, a case-insensitive match against the data model name (for example Vulnerability or vulnerability).

An identifier that matches nothing returns 404. For create, update, and delete, use the specific concrete model that holds the records (for example Vulnerability), never an abstract parent (Finding, Asset, Ticket): abstract parents hold no records of their own and are rejected. Bulk update is the one exception (see Bulk-update an attribute).

Endpoints​

OperationMethod and path
Create a recordPOST /v1/api/datasets/{identifier}
Update a recordPUT /v1/api/datasets/{identifier}/{id}
Delete a recordDELETE /v1/api/datasets/{identifier}/{id}
Bulk-update an attributePOST /v1/api/datasets/{identifier}/bulk-update

The {id} path parameter is a numeric record id (the id, not the hex uid).

The request body for create and update​

Create and update take a flat JSON object mapping attribute names to values. There is no envelope.

{
"name": "OpenSSL CVE-2026-0001",
"severity": "High",
"cvssScore": 9.1
}

A few rules apply to every create and update:

  • The application is derived, never sent. Do not include appName, dataModel, or application: the API derives the model and its app for you. An app-scoped model with no owning application returns 400.
  • Unknown attributes are rejected, not ignored. Any key that is not a real attribute of the model returns 400, so a typo fails loudly instead of being silently dropped.
  • Relationships are set by record id. A single-valued relationship is {"id": <recordId>}; a multi-valued relationship is a list of {"id": <recordId>}. Clear a relationship by sending [] or null for that attribute. Resolve a related record's id with a BQL query first; relationships cannot be set by name or uid. The Ticket Creation API uses the same shape for its reference fields.
  • References to an abstract target need the concrete record id. When an attribute points at an abstract model (for example a relationship to Asset), pass the concrete record's numeric id, not its uid.

Create a record​

Creates one record of the given model. Returns the new record's id in the Location header; the response has no body.

POST /v1/api/datasets/{identifier}

Headers:

Content-Type: application/json
Authorization: ApiKey <your-api-token>

Request body: a flat attribute map (see The request body for create and update).

Response: 201 Created

The Location header points to the new record (/v1/api/datasets/{identifier}/{id}). There is no response body.

Example:

curl -i -X POST 'https://<your-brinqa-instance>/v1/api/datasets/Vulnerability' \
-H 'Content-Type: application/json' \
-H 'Authorization: ApiKey <your-api-token>' \
-d '{
"name": "OpenSSL CVE-2026-0001",
"severity": "High"
}'
note

Replace <your-brinqa-instance> with the URL of your Brinqa Platform and <your-api-token> with your API token.

Update a record​

Updates one record. Each attribute you send replaces the stored value; attributes you omit are left unchanged. For a multi-valued attribute, send the full list you want the record to end with (existing values plus new ones), not just the additions.

PUT /v1/api/datasets/{identifier}/{id}

Headers:

Content-Type: application/json
Authorization: ApiKey <your-api-token>

Request body: a flat attribute map with the attributes to change.

Response: 200 OK with an empty body.

Example:

curl -i -X PUT 'https://<your-brinqa-instance>/v1/api/datasets/Vulnerability/1847261953084' \
-H 'Content-Type: application/json' \
-H 'Authorization: ApiKey <your-api-token>' \
-d '{
"severity": "Critical"
}'

Delete a record​

Deletes one record.

DELETE /v1/api/datasets/{identifier}/{id}

Headers:

Authorization: ApiKey <your-api-token>

Response: 204 No Content with an empty body.

A consolidated record can be deleted only when its sole source is manual entry. A record fed by any external integration cannot be deleted through this API, because the next consolidation would simply recreate it; such a delete returns 400.

Example:

curl -i -X DELETE 'https://<your-brinqa-instance>/v1/api/datasets/Vulnerability/1847261953084' \
-H 'Authorization: ApiKey <your-api-token>'

Bulk-update an attribute​

Sets a single attribute to one value on every record matched by a BQL query. The query selects the records; the attribute/value pair is what gets written. This launches the platform's autogenerated data-update flow and runs asynchronously.

POST /v1/api/datasets/{identifier}/bulk-update

Here {identifier} is the model you are querying (the main entity of your BQL query). You can update an attribute that the model inherits from a parent (for example description, defined on a parent model): pass the model you are querying and the API resolves the attribute's owning model for you. You do not have to know or name the parent.

Headers:

Content-Type: application/json
Authorization: ApiKey <your-api-token>

Request body:

{
"attribute": "severity",
"value": "Critical",
"query": "FIND Vulnerability WHERE cvssScore >= 9.0"
}
FieldTypeRequiredDescription
attributestringYesThe single attribute to set on every matched record. The attribute must have Bulk updating enabled in its data model configuration and be of a supported type; an attribute without Bulk updating enabled is rejected with 400.
valueanyYesThe value to set. A scalar for a single-valued attribute; a JSON array for a multi-valued attribute; {"id": <recordId>} (or a list of them) for a relationship. Use null or [] to clear.
strategystringNoHow to apply value to a multi-valued attribute: REPLACE (default) overwrites the list, ADD appends, REMOVE deletes the given values. Meaningful only for multi-valued attributes.
querystringYesA BQL query whose main entity is {identifier}. The attribute is written to every record the query matches.

Response: 202 Accepted

The update runs asynchronously. The Location header points to the launched flow's status (/v1/api/automation/management/{transactionId}); poll it to follow progress and see per-record results. See Flow and Automation Management API for the status shape.

Values are validated before the flow launches: an invalid value, an invalid choice or status option, a non-existent reference, or a strategy other than REPLACE on a single-valued attribute returns 400 and the flow is not launched.

Example:

curl -i -X POST 'https://<your-brinqa-instance>/v1/api/datasets/Vulnerability/bulk-update' \
-H 'Content-Type: application/json' \
-H 'Authorization: ApiKey <your-api-token>' \
-d '{
"attribute": "severity",
"value": "Critical",
"query": "FIND Vulnerability WHERE cvssScore >= 9.0"
}'

Example (add to a multi-valued attribute):

curl -i -X POST 'https://<your-brinqa-instance>/v1/api/datasets/Vulnerability/bulk-update' \
-H 'Content-Type: application/json' \
-H 'Authorization: ApiKey <your-api-token>' \
-d '{
"attribute": "tags",
"value": ["exploited-in-wild"],
"strategy": "ADD",
"query": "FIND Vulnerability WHERE cvssScore >= 9.0"
}'

Value validation​

Create, update, and bulk update validate every value against the attribute before writing:

  • A value that cannot be converted to the attribute's type (for example an unparseable date or a non-numeric value for a number attribute) returns 400.
  • A value that is not in the allowed set of a choice or status attribute returns 400.
  • A relationship to a record that does not exist returns 400.

Required-attribute, maximum-length, and unique-identifier enforcement are not applied by this API.

Permissions and access control​

Writes enforce the same model-, row-, and attribute-level access control as the UI, with read-before-write:

  • Creating, updating, or deleting a record requires the corresponding create, update, or delete permission on the model, plus access to the specific row and attributes involved.
  • A caller without permission receives 403; an unknown model or record receives 404.

Rate limits​

Each operation is independently rate limited at 60 requests per minute. If you exceed a limit, the API returns 429 Too Many Requests; wait for the interval given in the Retry-After response header before retrying.

Error handling​

HTTP StatusMeaningCommon cause
200 OKUpdate succeeded.Normal response for update.
201 CreatedRecord created.Normal response for create. The Location header holds the new record URL.
202 AcceptedBulk update launched.Normal response for bulk update. The Location header points to the flow status.
204 No ContentRecord deleted.Normal response for delete.
400 Bad RequestThe request was rejected before writing.Unknown attribute (a typo); invalid value for a choice or status attribute; unparseable scalar (date, dateTime, time); reference to a non-existent record; a reference to an abstract model given by uid instead of the concrete record id; the target model is abstract, a cluster, or an application event log; a consolidated model on create or update that does not route to manual entry; delete of a consolidated record whose source is not manual entry only; update or delete of a system-managed record; an app-scoped model with no owning application; a bulk-update attribute that does not have Bulk updating enabled or is of an unsupported type; a strategy other than REPLACE on a single-valued attribute; or a bulk-update query whose main entity is not the path model.
401 UnauthorizedAuthentication failed.Missing, invalid, expired, or revoked API token.
403 ForbiddenNot permitted.The caller lacks model-, row-, or attribute-level permission for the operation.
404 Not FoundTarget not found.Unknown data model identifier, or unknown record id.
429 Too Many RequestsRate limit exceeded.Too many requests in a short period. Wait for the Retry-After interval and retry.