Create or update an action item
const url = 'https://safe-api.safetyradar.com/v2/action-items';const options = { method: 'POST', headers: { 'x-team': 'my-team-slug', Authorization: 'Bearer <token>', 'Content-Type': 'application/json' }, body: '{"title":"example","description":"example","assignedToUserId":"2489E9AD-2EE2-8E00-8EC9-32D5F69181C0","assignedToUserExternalId":"example","assignedToDepartmentId":"2489E9AD-2EE2-8E00-8EC9-32D5F69181C0","assignedToRoleSlug":"example","dueDate":"2026-04-15T12:00:00Z","priority":"low","status":"open","completedAt":"2026-04-15T12:00:00Z","completedByExternalId":"example","externalId":"example","eventExternalId":"example","locationExternalId":"example","statusExternalId":"example","fields":{"crew":"A-shift","corrective_cost":1250},"metadata":{"additionalProperty":"example"}}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://safe-api.safetyradar.com/v2/action-items \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --header 'x-team: my-team-slug' \ --data '{ "title": "example", "description": "example", "assignedToUserId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "assignedToUserExternalId": "example", "assignedToDepartmentId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "assignedToRoleSlug": "example", "dueDate": "2026-04-15T12:00:00Z", "priority": "low", "status": "open", "completedAt": "2026-04-15T12:00:00Z", "completedByExternalId": "example", "externalId": "example", "eventExternalId": "example", "locationExternalId": "example", "statusExternalId": "example", "fields": { "crew": "A-shift", "corrective_cost": 1250 }, "metadata": { "additionalProperty": "example" } }'Create an action item, or update an existing one. externalId is the action item’s own correlation ID (unique per organization) and acts as an upsert key: if an action item already carries it, that record is updated with the supplied fields and the response is 200 — otherwise a new item is created and the response is 201. Use eventExternalId to link the item to an event (by the event’s external ID, verified against your org); omit it for a floating action item. locationExternalId sets the location/equipment and statusExternalId sets the status from your organization’s Action Item flow — both are ignored if unrecognised, so check assetName / statusName on the response to confirm what was mapped. statusExternalId takes precedence over status. On the update path the event linkage and the completion fields are ignored. The team is taken from the X-Team header.
Send your organization’s custom fields in fields, keyed by definition key (GET /v2/modules/action_item/fields lists them). They are validated against the organization’s definitions in the same transaction as the record: a refused envelope is a 400 with a per-key list and the item is not created. On the upsert path fields is a partial patch — an omitted key keeps its stored value.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Header Parameters
Section titled “Header Parameters”Deprecated — accepted but ignored; the v2 API is org-scoped.
Example
my-team-slugDeprecated — accepted but ignored; the v2 API is org-scoped.
Request Bodyrequired
Section titled “Request Bodyrequired”object
The organization’s admin-defined custom fields, keyed by definition key. Validated against the organization’s own definitions: an unknown key, a bad enum value or a missing required field is a 400 carrying a per-key list. Does not merge with metadata — the two are stored separately and neither overwrites the other. Discover the contract at GET /v2/modules/action_item/fields.
object
Example
{ "crew": "A-shift", "corrective_cost": 1250}Verbatim, unvalidated. Use fields — typed, admin-defined, validated. See GET /v2/modules/action_item/fields.
object
Responses
Section titled “Responses”Existing action item updated (matched on externalId)
object
object
object
The organization’s custom module fields, keyed by definition key. Always present; {} when the organization has configured none, and a defined key this item holds no value for is absent rather than null. Discover the keys, types and filter operators at GET /v2/modules/action_item/fields.
object
Verbatim, unvalidated. Use fields — typed, admin-defined, validated. See GET /v2/modules/action_item/fields.
object
Example
{ "data": { "priority": "low", "statusGroup": "new", "status": "open", "fields": { "crew": "A-shift", "corrective_cost": 1250 } }}Action item created
object
object
object
The organization’s custom module fields, keyed by definition key. Always present; {} when the organization has configured none, and a defined key this item holds no value for is absent rather than null. Discover the keys, types and filter operators at GET /v2/modules/action_item/fields.
object
Verbatim, unvalidated. Use fields — typed, admin-defined, validated. See GET /v2/modules/action_item/fields.
object
Example
{ "data": { "priority": "low", "statusGroup": "new", "status": "open", "fields": { "crew": "A-shift", "corrective_cost": 1250 } }}The fields envelope does not satisfy the organization’s definitions
object
object
object
Example
{ "code": "invalid_fields"}Unauthorized
object
object
Examplegenerated
{ "code": "example", "message": "example", "details": { "additionalProperty": "example" }}Referenced event or assignee not found
object
object
Examplegenerated
{ "code": "example", "message": "example", "details": { "additionalProperty": "example" }}ExternalId is already in use by another action item
object
object
Examplegenerated
{ "code": "example", "message": "example", "details": { "additionalProperty": "example" }}
