Update item
Updates the fields present in the body; absent fields are left alone. A caller without the update permission on items is refused with 403 `common.rbac_no_rec_access`. system is writable here. Sending "system": false on an item that had it set clears the delete protection described on DELETE /v1/items/{id}; the field is only skipped when the key is absent from the body.
Path Parameters
Item UUID
id path parameter
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Body of PUT /v1/items/{id}. Every field is optional and only the ones present are applied — unlike some modules in this API, this really is a patch. Read the three states per field carefully, because they differ between metadata and the two locale maps. metadata is a pointer: absent leaves it alone, null CLEARS it. title and description are plain maps and the service branches on nil, not on presence: absent and null are both no-ops, while {} is non-nil and marshals to {} — so {"title": {}} answers 200 and replaces every stored locale with an empty map. There is no way to recover the previous value from the response.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X PUT "https://example.com/v1/items/string" \ -H "Content-Type: application/json" \ -d '{}'{
"type": "product",
"name": "premium-savings-account",
"title": {
"en": "Premium Savings Account",
"de": "Premium-Sparkonto"
},
"description": {
"property1": "string",
"property2": "string"
},
"title_loc": "string",
"description_loc": "string",
"sort_order": 0,
"system": false,
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"created_at": "2019-08-24T14:15:22Z",
"created_by": "ee824cad-d7a6-4f48-87dc-e8461a9201c4",
"modified_at": "2019-08-24T14:15:22Z",
"modified_by": "e8d4374d-93a1-4e98-a6c6-fdcf00c5059f",
"active": true,
"metadata": {}
}{
"status": 409,
"message": "Item with this name already exists",
"code": "items_m.item_name_exists",
"class": "business",
"retryable": false,
"details": [
{
"field": "title",
"rule": "required",
"param": "string",
"message": "title is required"
}
]
}{
"status": 409,
"message": "Item with this name already exists",
"code": "items_m.item_name_exists",
"class": "business",
"retryable": false,
"details": [
{
"field": "title",
"rule": "required",
"param": "string",
"message": "title is required"
}
]
}{
"status": 409,
"message": "Item with this name already exists",
"code": "items_m.item_name_exists",
"class": "business",
"retryable": false,
"details": [
{
"field": "title",
"rule": "required",
"param": "string",
"message": "title is required"
}
]
}{
"status": 409,
"message": "Item with this name already exists",
"code": "items_m.item_name_exists",
"class": "business",
"retryable": false,
"details": [
{
"field": "title",
"rule": "required",
"param": "string",
"message": "title is required"
}
]
}{
"status": 409,
"message": "Item with this name already exists",
"code": "items_m.item_name_exists",
"class": "business",
"retryable": false,
"details": [
{
"field": "title",
"rule": "required",
"param": "string",
"message": "title is required"
}
]
}{
"status": 429,
"message": "rate limit exceeded",
"code": "rate_limits_m.exceeded",
"class": "temporary",
"retryable": true
}{
"status": 409,
"message": "Item with this name already exists",
"code": "items_m.item_name_exists",
"class": "business",
"retryable": false,
"details": [
{
"field": "title",
"rule": "required",
"param": "string",
"message": "title is required"
}
]
}{
"overall_status": "unhealthy",
"message": "Service is shutting down",
"timestamp": "2026-08-27T15:04:05Z"
}Returns each distinct item type with how many items carry it. A bare array, not the list envelope. The count is over ACTIVE items only (WHERE active = true), so it does not match the totals from GET /v1/items unless that list is filtered the same way. This route performs no record-permission check and takes no query parameters.
Deletes the item. System items cannot be deleted. A caller without the delete permission on items is refused with 403 `common.rbac_no_rec_access`. THE DELETE IS PERMANENT. models.Item embeds models.BaseModel, which carries no gorm.DeletedAt, so this issues a real DELETE FROM misc.items — the row is gone, not deactivated, and setting active=false is a different operation with a different outcome. A system item is refused with 400 items_m.system_item_cannot_be_deleted, but that protection is not durable: PUT /v1/items/{id} accepts "system": false, so a caller with update rights can clear the flag and then delete the item.