Create new item
Creates an item. The name must be unique within the type. A caller without the create permission on items is refused with 403 `common.rbac_no_rec_access`. Accept-Language is not read on this route: only GetItem and ListItems pull constants.AcceptLanguage from the request, and this 201 body carries no localised fields.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Body of POST /v1/items. type, name, title and description carry validate:"required" on models.CreateItemRequest, but NOTHING IN THIS MODULE RUNS A VALIDATOR: the handler only json.Decode's the body. Omitting one of them is therefore not a 400 — the insert proceeds with the zero value (an empty name, or a title of JSON null, both of which satisfy the NOT NULL columns) and answers 201. required here is the contract callers should honour, not a check the server performs.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/v1/items" \ -H "Content-Type: application/json" \ -d '{ "type": "product", "name": "premium-savings-account", "title": { "en": "Premium Savings Account", "de": "Premium-Sparkonto" }, "description": { "en": "Premium Savings Account", "de": "Premium-Sparkonto" } }'{
"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": 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"
}Description
Previous Page
Lists set items in the standard envelope. Read scope is enforced in the query, not by an early check: the service passes RbacRecordType into GetAllTotal, which asks for the read-all (A) mask on the record type and, when the caller does not hold it, resolves the record ids they may read and merges them into the query as a scope predicate. So a caller without A sees only their permitted rows, and a caller with no permitted rows gets an empty list with total 0 — not a 403. Accept-Language is NOT read on this route. Only GetItem and ListItems pull constants.AcceptLanguage from the request; set items carry no localised fields, so the header is ignored here exactly as it is on the two POSTs. WARNING: there is no working way to filter set items by their modification time. validSetItemFields declares the field as updated_at mapped to column misc.set_items.updated_at, but the table names it modified_at — so search.updated_at reaches Postgres and errors, which is a 500, while search.modified_at is rejected by validateFieldName as an unknown field, which on this route is a 400 (see the responses). Neither spelling returns rows, and there is no third one. sort=modified_at is a 500 here as well, for the reason given on the sort parameter. Operators are eq, ne, gt, gte, lt, lte, in, nin, like, start_with, end_with — not neq, and not ilike or contains, which belong to the reserved text-search set and are rejected with 400 query_m.invalid_operator.