What this is about
You create a new object with POST {base}/create. The body contains two things:
| Part | Content |
|---|---|
data | the fields of the new object, without id |
response | which fields you want back in the response, as in Field selection with response |
POST /api/rest/crm/customer/create
{
"data": { "name": "Muster GmbH", "email": "info@muster.de" },
"response": ["+"]
}{
"data": {
"id": "5a2b…",
"_createdOn": "2026-09-21 10:15:02",
"_updatedOn": null,
"name": "Muster GmbH",
"email": "info@muster.de",
"status": "NEW"
},
"meta": { "error": false }
}The response is 200. id, _createdOn and _updatedOn are always included. The client did not send status: the value NEW is the field’s default value.
The stations of a create
-
CIASFilter chainIs the token valid?↳ no 401
-
CDMSField selectionIs there a
responsein the body?↳ no 400response -
CDMSModel roleMay the person create
customer? The same applies to every child that is created along with it.↳ no 403missing-permission|<rolle> -
CDMSTransfer fieldsSet system fields, take values from
data, fill empty fields with default values, create or link children, collect violations↳ no 400 / 404 for children, see below -
HookBefore hooksHooks see the new object and may still change it. It does not have an
idyet. -
CDMSValidationAre all rules met after the hooks?↳ no 422
validation-failedwith all violations -
DatabaseSaveThe row is written, and the database assigns the
id. Then the after hooks run.↳ no 409already-exists, e.g. a duplicate unique value -
CDMSRead backThe new object is read with the
response, using the person's read permissions.↳ no 403 / 404, and the create is rolled back as well - 200 with the new object
What CDMS sets on its own when creating
| Field | Value |
|---|---|
id | a new UUID, on save |
_createdOn | now |
_updatedOn | stays empty until the first change |
_userId | the logged-in person, only for models with the scope “user” |
@type | the concrete type; for an abstract model, the client chooses it |
| Fields with a default | the default value, if the client sends no value |
If the client sends an id or a field starting with _, CDMS ignores it without an error. See System fields that the server sets. The database where the object ends up follows from the tenant of the request. There is no separate tenant field. See Which database? The persistence target
The flow in detail
sequenceDiagram
participant C as Client
participant R as REST layer
participant S as System layer
participant H as Hooks
participant DB as Database
C->>R: POST /create { data, response }
R->>R: resolve response, take over files
R->>S: createObject(DTO)
S->>S: check role, set _createdOn
S->>S: transfer fields, insert defaults,<br/>create children, collect violations
S->>H: Before hooks (parents before children)
S->>S: check violations again → 422?
S->>DB: INSERT, id is assigned
S->>H: After hooks
S->>DB: flush
S->>DB: read back with response
S-->>R: DTO
R-->>C: 200 { data, meta }
The hooks run before validation. So a before hook may fill a required field that the client does not even know about, such as a customer number. More in Hooks: types and timing.
All variants
When: The normal case.
-
1Client→CDMSsends
POST /crm/customer/createwithdataandresponse -
2CDMSchecks the role, takes over the fields, sets defaults
-
3HookBefore hooks
-
4CDMS→Databasechecks the rules, saves, reads back
-
5CDMS→Clientreturns the new object
Result: 200 with the new object and its id.
When: The model is a file model or has file fields.
There are two ways. Multipart: POST /create/upload with a part data (the JSON) and the files in the part files. A file object in data finds its file by name: name in the object must equal the file name of the part. Base64: POST /create as usual, and the content is text in content of the file object. If the matching file is missing for a file model, you get 400 file-part-missing|<name>.
Result: 200, the file is in storage. See Uploading.
When: The model has exactly one object per scope, e.g. settings. Path: POST /create, without id.
-
1Client→CDMSsends
POST /crm/einstellungen/create -
2CDMS→DatabaseIs there already an object in this scope?
-
3CDMS→Clientyes → 400
object-already-exists|use-update -
4CDMSno → creates it like a normal object
Result: 200. After that, you change it with PUT /update or PATCH /update. See Singletons: exactly one object.
When: You create through the hub API of an abstract model, e.g. /crm/kunde/create.
-
1Client→CDMSsends
{ "data": { "@type": "crm.privatkunde", "name": "Anna Muster" }, "response": ["+"] } -
2CDMSreads
@typeand with it the fields of the subtype -
3CDMS→Client
@typemissing → 400missing-type-for-abstract-field|data; unknown type → 400unknown-type-for-abstract-field|data|<typ> -
4CDMSpasses the request on to the subtype's API, with its roles, rules and hooks
Result: 200 with "@type": "crm.privatkunde". See Abstract models and @type.
When: You create a company with its employees in one request, or link them to existing objects.
-
1Client→CDMSsends
"employees": [{ "firstname": "Anna", "lastname": "Schmidt" }], "mainAddress": { "id": "a7…" } -
2CDMSchild without
id→ is created if the relation allows it, with its own role check, its own defaults and_createdOn -
3CDMS→Clientrelation does not allow creating → 400
recursive-create-not-allowed|employees -
4CDMSchild with
id→ is linked -
5CDMS→Client
iddoes not exist → 404missing-object|a7…|mainAddress -
6CDMS→Databasesaves everything in one transaction
Result: 200. If one child fails, the company is not created either. See The four cases in nested writing.
Decision table
| response in the body | role to create | rules met | unique values free | read role for reading back | Response |
|---|---|---|---|---|---|
| no | – | – | – | – | 400 response |
| yes | no | – | – | – | 403 missing-permission|<rolle> |
| yes | yes | no | – | – | 422 validation-failed |
| yes | yes | yes | no | – | 409 already-exists |
| yes | yes | yes | yes | no | 403 missing-permission|<leserolle>, nothing created |
| yes | yes | yes | yes | yes | 200 with the new object |
The table describes the standard: strict mode on and reading back in STRICT mode. In LENIENT mode, CDMS saves first and then reads. If only the read fails, the object stays created and the response names its id. See Create and read back: STRICT or LENIENT.
Pitfalls
Where to go next
- Fields that fill themselves: Default values
- What is checked: Validation
- Changing afterwards: Replacing with PUT and Changing with PATCH
- What happens in a transaction: One request, one transaction