What this is about
Every response from CDMS has one of a few fixed shapes. If you know them, you can handle them in one place in the client.
The four shapes
| Request | Success? | Shape of the response |
|---|---|---|
| create, read, update, patch, rollback | yes | SingleResponse: data is one object |
| query | yes | QueryResponse: data is a list, meta holds the match counts |
| history | yes | AuditQueryResponse: data is a list of revisions |
| delete | yes | empty body, status 200 |
| file download | yes | the file itself, not JSON |
| any | no | error response, see below |
Single object
POST /api/rest/crm/customer/read/5a2b…
{ "response": ["name", "email"] }{
"data": {
"id": "5a2b…",
"@type": "crm.customer",
"_createdOn": "2026-09-21 10:12:00",
"_updatedOn": null,
"name": "Muster GmbH",
"email": "info@muster.de",
"address": null
},
"meta": { "error": false, "errorMessage": null, "notNull": false }
}dataholds the DTO. Requested fields have their value; fields that were not requested arenull.id,@type,_createdOnand_updatedOnare always included.- On a success response,
metais alwayserror: false. The fields have no further meaning for the client.
List
POST /api/rest/crm/customer/query
{ "response": ["name"],
"parameter": { "page": 1, "limit": 2 } }{
"data": [
{ "id": "…", "name": "Beta AG", … },
{ "id": "…", "name": "Gamma KG", … }
],
"meta": {
"totalCount": 5,
"currentPage": 1,
"currentPageSize": 2,
"currentLimit": 2,
"error": false,
"errorMessage": null
}
}meta field | Meaning |
|---|---|
totalCount | number of all matches across all pages. With "meta": false in the request, nothing is counted |
currentPage | the page returned, starting at 0 |
currentLimit | the requested page size |
currentPageSize | how many objects are actually on this page |
Page count in the client: Math.ceil(totalCount / currentLimit). No matches is not an error: data is then an empty list. More in Paging and match count.
History
POST /api/rest/crm/customer/5a2b…/history
{ "response": ["name"] }{
"data": [
{
"revision": { "id": "5a2b…", "name": "Muster GmbH", … },
"revisionMeta": {
"ref": 42,
"ts": 1790000000000,
"ip": "10.0.0.7",
"useragent": "Mozilla/5.0 …",
"username": "anna"
},
"revisionType": "MOD"
}
],
"meta": { "error": false, … }
}| Field | Meaning |
|---|---|
revision | the object as it looked after this change |
revisionMeta.ref | revision number, which you need for a rollback |
revisionMeta.ts | time in milliseconds since 1970 |
revisionMeta.ip, useragent, username | who made the change, from where |
revisionType | ADD created, MOD changed, DEL deleted |
The newest revision comes first. See Reading the history.
Errors
Errors have a flat shape of their own, without data:
POST /api/rest/crm/customer/create
{ "data": { "name": "" }, "response": ["id"] }{
"error": "ApiValidationException",
"messageKey": "validation-failed",
"code": "422",
"layer": "API",
"violations": [
{ "field": "name", "rule": "cannot-be-empty" },
{ "field": "email", "rule": "cannot-be-null" }
]
}| Field | Meaning | In the client |
|---|---|---|
error | kind of error | for logging |
messageKey | fixed key, e.g. missing-permission|customer-read | branch on this, not on the text |
message | readable text | for humans only |
code | HTTP status as text | same as the response status |
layer | layer where the error occurred | for debugging |
violations | validation errors only: all violations with field path and rule | map them to the form fields |
id | only in the special case below | – |
What each code means is in Map of status codes. How violations get into the form is in Getting validation errors into the form.
The special case: created, but not read back
After a create, CDMS reads the object back for the response. In LENIENT mode, creating can succeed while only the read-back fails. You then get a response in error shape, but with status 200 and the id of the created object:
{
"error": "CreateSucceededReadFailedException",
"messageKey": "CDMS_CREATE_SUCCEEDED_READ_FAILED",
"code": "200",
"layer": "system",
"id": "5a2b…"
}The object exists.
Read it again later using the id,
do NOT create it a second time.See Create and read back: STRICT or LENIENT.
One handler for everything
-
1ClientStatus 2xx?
-
2Clientyes, and
messageKeyisCDMS_CREATE_SUCCEEDED_READ_FAILED→ created, remember theid, read later -
3Clientyes, otherwise → use
data, for lists alsometa -
4Clientno → evaluate
messageKey; on 422 map theviolationsto the fields; on 401 renew the token and retry once