crud — entity lifecycle API
cyoda-go version 0.7.1
crud — entity create, read, update, delete, and transition REST API.
SYNOPSIS
Section titled “SYNOPSIS”POST /api/entity/{format}/{entityName}/{modelVersion}POST /api/entity/{format}GET /api/entity/{entityId}PUT /api/entity/{format}/{entityId}PUT /api/entity/{format}/{entityId}/{transition}PUT /api/entity/{format}DELETE /api/entity/{entityId}DELETE /api/entity/{entityName}/{modelVersion}GET /api/entity/{entityName}/{modelVersion}GET /api/entity/{entityId}/changesGET /api/entity/{entityId}/transitionsGET /api/entity/statsGET /api/entity/stats/statesGET /api/entity/stats/{entityName}/{modelVersion}GET /api/entity/stats/states/{entityName}/{modelVersion}GET /api/platform-api/entity/fetch/transitionsContext path prefix is CYODA_CONTEXT_PATH (default /api). All endpoints require Authorization: Bearer <token> except when CYODA_IAM_MODE=mock.
DESCRIPTION
Section titled “DESCRIPTION”Entities are instances of models. Each entity has a UUID, a model reference (entityName, modelVersion), and a lifecycle state managed by the workflow engine. Creating an entity requires the referenced model to be in LOCKED state. All write operations run within a Cyoda transaction and return a transactionId alongside the affected entity IDs.
Body size limit on all write endpoints: 10 MiB.
ENDPOINTS
Section titled “ENDPOINTS”POST /api/entity/{format}/{entityName}/{modelVersion} — Create a single entity
format(path):JSONorXMLentityName(path): string — model namemodelVersion(path): int32transactionWindow(query, optional): int32, default100, max1000— applies only when the request body is a JSON array. Maximum entities per transactional batch. Values outside (0, 1000] are rejected with400 BAD_REQUEST. Array bodies exceeding the window are split into multiple transactional batches committed sequentially; each chunk is one transaction. The response is then an array with one element per chunk in commit order; chunks committed before any later failure remain durable.waitForConsistencyAfter(query, optional): boolean, defaultfalse— accepted for Cyoda Cloud parity; parsed but currently has no behavioural effect in cyoda-go.transactionTimeoutMillis(query, optional): int64, default10000— accepted for Cyoda Cloud parity; parsed but currently has no behavioural effect in cyoda-go.
If the request body is a JSON array, each element is treated as a separate entity of the same model and the collection-create chunking contract applies (see transactionWindow above and the POST /api/entity/{format} partial-success shape below).
Response: 200 OK, application/json. Single-object body returns a one-element array; an array body returns one element per committed chunk in commit order:
[{ "transactionId": "cb91fa80-d4a8-11ee-a357-ae468cd3ed16", "entityIds": ["74807f00-ed0d-11ee-a357-ae468cd3ed16"]}]POST /api/entity/{format} — Create a collection (mixed models)
format(path):JSONorXMLtransactionWindow(query, optional): int32, default100, max1000— maximum entities per transactional batch. Values outside (0, 1000] are rejected with400 BAD_REQUEST. Collections exceeding the window are split into multiple transactional batches committed sequentially; each chunk is one transaction. The response is an array with one element per chunk in commit order.transactionTimeoutMillis(query, optional): int64, default10000— accepted for Cyoda Cloud parity; parsed but currently has no behavioural effect in cyoda-go.waitForConsistencyAfter(query, optional): boolean, defaultfalse— accepted for Cyoda Cloud parity; parsed but currently has no behavioural effect in cyoda-go.
IMPORTANT — payload is a JSON-encoded string, not an object.
The payload field must be a string containing the JSON-encoded entity body, not a nested JSON object. This is a deliberate API contract — it preserves the payload as an opaque blob through the pipeline.
Correct: "payload": "{\"category\":\"physics\"}"
Wrong: "payload": {"category":"physics"} (will be rejected with errors.BAD_REQUEST)
Request body: JSON array of CreatePayload objects:
[ { "model": { "name": "nobel-prize", "version": 1 }, "payload": "{\"category\":\"physics\",\"year\":\"2024\"}" }]Each item may reference a different model. The collection is committed in transactional batches of at most transactionWindow items. Within a single chunk the create is all-or-nothing; chunks committed before any later failure remain durable.
Response: 200 OK, application/json, EntityTransactionResponse array — one element per committed chunk in commit order:
[{ "transactionId": "cb91fa80-d4a8-11ee-a357-ae468cd3ed16", "entityIds": [ "74807f00-ed0d-11ee-a357-ae468cd3ed16", "72428380-0704-11ef-a357-ae468cd3ed16" ]}]Partial-success on chunk failure. If a later chunk fails after earlier chunks have committed, the response is still HTTP 200 carrying the durable chunks plus an error element marking the failed chunk’s index. Subsequent chunks are not attempted.
[ { "transactionId": "tx-0", "entityIds": ["..."] }, { "transactionId": "tx-1", "entityIds": ["..."] }, { "error": { "code": "MODEL_NOT_FOUND", "message": "...", "chunkIndex": 2 } }]When the very first chunk fails (no durable progress), the response is the standard application/problem+json 4xx error envelope instead.
GET /api/entity/{entityId} — Read a single entity by UUID
entityId(path): UUID stringpointInTime(query, optional): RFC 3339 date-time — load entity state at this instanttransactionId(query, optional): UUID — load entity state as of the end of this transaction
pointInTime and transactionId are mutually exclusive; supplying both returns 400 BAD_REQUEST.
Response: 200 OK, application/json:
{ "type": "ENTITY", "data": { "category": "physics", "year": "2024" }, "meta": { "id": "74807f00-ed0d-11ee-a357-ae468cd3ed16", "state": "NEW", "creationDate": "2025-08-01T10:00:00Z", "lastUpdateTime": "2025-08-01T10:00:00Z", "transactionId": "cb91fa80-d4a8-11ee-a357-ae468cd3ed16", "transitionForLatestSave": "loopback" }}PUT /api/entity/{format}/{entityId} — Update a single entity (loopback transition)
format(path):JSONorXMLentityId(path): UUIDIf-Match(header, optional): transaction ID of last read — optimistic concurrency; if the entity was modified since, returns412 Precondition FailedtransactionTimeoutMillis(query, optional): int64, default10000— accepted for Cyoda Cloud parity; parsed but currently has no behavioural effect in cyoda-go.waitForConsistencyAfter(query, optional): boolean, defaultfalse— accepted for Cyoda Cloud parity; parsed but currently has no behavioural effect in cyoda-go.
Request body: updated entity JSON/XML payload.
Response: 200 OK, application/json:
{ "transactionId": "733e7180-c055-11ef-a357-ae468cd3ed16", "entityIds": ["cdcff600-bab1-11ee-a357-ae468cd3ed16"]}PUT /api/entity/{format}/{entityId}/{transition} — Update a single entity with a named transition
format(path):JSONorXMLentityId(path): UUIDtransition(path): string — transition name defined in the model’s workflowIf-Match(header, optional): transaction IDtransactionTimeoutMillis(query, optional): int64, default10000— accepted for Cyoda Cloud parity; parsed but currently has no behavioural effect in cyoda-go.waitForConsistencyAfter(query, optional): boolean, defaultfalse— accepted for Cyoda Cloud parity; parsed but currently has no behavioural effect in cyoda-go.
Response: 200 OK, same shape as loopback update.
PUT /api/entity/{format} — Update a collection (mixed entities)
format(path):JSON(only supported format today; single-item PUT endpoints still accept XML)transactionWindow(query, optional): int32, default100, max1000— maximum entities per transactional batch. Values outside (0, 1000] are rejected with400 BAD_REQUEST. Collections exceeding the window are split into multiple transactional batches committed sequentially; each chunk is one transaction. The response is an array with one element per chunk in commit order; chunks committed before any later failure remain durable.transactionTimeoutMillis(query, optional): int64, default10000— accepted for Cyoda Cloud parity; parsed but currently has no behavioural effect in cyoda-go.waitForConsistencyAfter(query, optional): boolean, defaultfalse— accepted for Cyoda Cloud parity; parsed but currently has no behavioural effect in cyoda-go.
IMPORTANT — payload is a JSON-encoded string, not an object.
The payload field in each update item must be a string containing the JSON-encoded entity body, not a nested JSON object (same contract as collection create).
Correct: "payload": "{\"category\":\"physics\"}"
Wrong: "payload": {"category":"physics"} (will be rejected with errors.BAD_REQUEST)
Each item may also carry an optional ifMatch field (issue #228) — the entity’s last-known meta.transactionId from a prior read. Items with ifMatch get a per-item cross-request optimistic-concurrency precondition: if the entity has been modified since, the item is rejected with code=ENTITY_MODIFIED and surfaces in the chunk’s failed array, without rolling the chunk back. Items in the same chunk without ifMatch (or with a still-valid one) commit as usual. This mirrors the If-Match header on the single-item PUT endpoints, scoped per-item.
Request body: JSON array of update items:
[ { "id": "8824c480-c166-11ee-9e63-ae468cd3ed16", "payload": "{\"category\":\"physics\",\"year\":\"2024\"}", "transition": "UPDATE", "ifMatch": "733e7180-c055-11ef-a357-ae468cd3ed16" }]Failure handling within a chunk:
- Per-item
ENTITY_MODIFIED(only whenifMatchis supplied): the item surfaces infailed[]; siblings still commit; the chunk’stransactionIdis reported. Per-item ENTITY_MODIFIED conflicts surface inside the200response body via thefailed[]array, not as a4xxenvelope. Inspectfailed[]to detect them. The4xxenvelope is reserved for chunk-wide infrastructure failures. - Any other per-item failure (missing entity, validation, non-conflict engine error): the entire chunk rolls back, matching the pre-#228 contract. Earlier chunks remain durable; if the first chunk fails the response is a standard
application/problem+json4xx envelope.
Each per-item ENTITY_MODIFIED is also reflected in the entity’s state-machine audit log: the engine emits a paired STATE_MACHINE_START plus TRANSITION_ABORTED event (with data.reason = "ENTITY_MODIFIED", data.expectedTxId, and data.actualTxId) so consumers can correlate the failure cleanly without orphaned start events.
Response: 200 OK, application/json, EntityTransactionResponse array — one element per committed chunk in commit order. The optional failed array is omitted on chunks with no per-item ENTITY_MODIFIED failures:
[ { "transactionId": "733e7180-c055-11ef-a357-ae468cd3ed16", "entityIds": ["8824c480-c166-11ee-9e63-ae468cd3ed16"], "failed": [ { "entityId": "31134900-d9cb-11ee-9e63-ae468cd3ed16", "error": { "code": "ENTITY_MODIFIED", "message": "entity has been modified since last read", "itemIndex": 1 } } ] }]itemIndex is the failing item’s zero-based position within its chunk’s request slice (per-chunk relative). When every item in a chunk fails its ifMatch precondition, the chunk still commits as a zero-write transaction — entityIds is empty, failed[] lists every item, and transactionId remains meaningful for audit correlation.
DELETE /api/entity/{entityId} — Delete a single entity by UUID
entityId(path): UUID
Response: 200 OK, application/json:
{ "id": "a2242880-8d30-11ef-9e63-ae468cd3ed16", "modelKey": { "name": "nobel-prize", "version": 4 }, "transactionId": "9fe62d00-a727-11ef-9e63-ae468cd3ed16"}DELETE /api/entity/{entityName}/{modelVersion} — Delete all entities for a model
entityName(path): stringmodelVersion(path): int32
Response: 200 OK, application/json:
[{ "deleteResult": { "idToError": {}, "numberOfEntitites": 42, "numberOfEntititesRemoved": 42 }, "entityModelClassId": "31134900-d9cb-11ee-b913-ae468cd3ed16"}]GET /api/entity/{entityName}/{modelVersion} — List all entities for a model (paginated)
entityName(path): stringmodelVersion(path): int32pageSize(query, optional): int32, default20pageNumber(query, optional): int32, default0
Response: 200 OK, application/json, array of entity envelopes (same shape as single-entity GET).
GET /api/entity/{entityId}/changes — Get entity change history metadata
entityId(path): UUIDpointInTime(query, optional): RFC 3339 — view history as it existed at this time
Response: 200 OK, application/json, array of change entries:
[ { "changeType": "CREATED", "timeOfChange": "2025-08-01T10:00:00Z", "user": "admin", "transactionId": "cb91fa80-d4a8-11ee-a357-ae468cd3ed16" }, { "changeType": "UPDATED", "timeOfChange": "2025-08-02T09:00:00Z", "user": "admin", "transactionId": "733e7180-c055-11ef-a357-ae468cd3ed16" }]changeType:CREATED,UPDATED, orDELETEDtransactionId: present only whenhasEntityis true (i.e., entity payload exists at that version)
GET /api/entity/{entityId}/transitions — List available transitions for an entity
entityId(path): UUIDpointInTime(query, optional): RFC 3339transactionId(query, optional): UUID — derive point-in-time from transaction submit time
pointInTime and transactionId are mutually exclusive; supplying both returns 400 BAD_REQUEST. When neither is provided, the current time is used.
Response: 200 OK, application/json, array of available transition names (as returned by the workflow engine).
GET /api/platform-api/entity/fetch/transitions — List available transitions (platform-api format)
entityClass(query, required): string inName.Versionformat, e.g.,Offer.1entityId(query, required): UUID string
Response: 200 OK, application/json, array of available transition names.
GET /api/entity/stats — Entity count statistics across all models
Response: 200 OK, application/json:
[ { "modelName": "nobel-prize", "modelVersion": 1, "count": 42 }, { "modelName": "family-member", "modelVersion": 3, "count": 7 }]GET /api/entity/stats/states — Entity count by state across all models
states(query, optional): comma-separated list of state names to filter by; maximum 1000 entries
Response: 200 OK, application/json:
[ { "modelName": "nobel-prize", "modelVersion": 1, "state": "NEW", "count": 10 }, { "modelName": "nobel-prize", "modelVersion": 1, "state": "APPROVED", "count": 32 }]GET /api/entity/stats/{entityName}/{modelVersion} — Entity count for a specific model
entityName(path): stringmodelVersion(path): int32
Response: 200 OK, application/json, single ModelStatsDto.
GET /api/entity/stats/states/{entityName}/{modelVersion} — Entity count by state for a specific model
entityName(path): stringmodelVersion(path): int32states(query, optional): list of state names to filter by; maximum 1000 entries
Response: 200 OK, application/json, array of ModelStateStatsDto.
ENTITY ENVELOPE
Section titled “ENTITY ENVELOPE”All entity read operations return entities in the standard envelope:
{ "type": "ENTITY", "data": { ... }, "meta": { "id": "74807f00-ed0d-11ee-a357-ae468cd3ed16", "modelKey": { "name": "nobel-prize", "version": 1 }, "state": "NEW", "creationDate": "2025-08-01T10:00:00.000000000Z", "lastUpdateTime": "2025-08-01T10:00:00.000000000Z", "transactionId": "cb91fa80-d4a8-11ee-a357-ae468cd3ed16", "transitionForLatestSave": "UPDATE" }}type— always"ENTITY"data— the entity’s JSON payload (decoded withjson.Numberfor numeric precision)meta.id— UUID stringmeta.modelKey— object withname(string) andversion(int32) identifying the model; present in single-entityGET /entity/{id}responses. Omitted from list/search results because the model is already part of the request path (/api/entity/{entityName}/{modelVersion}).meta.state— current workflow state stringmeta.creationDate— RFC 3339 with nanosecondsmeta.lastUpdateTime— RFC 3339 with nanosecondsmeta.transactionId— present when a transaction ID existsmeta.transitionForLatestSave— transition name that produced the latest save. Valid values:"loopback"(loopback update with no transition supplied by the client) or the named transition string. Known bug (#94): the server currently stores the literal"workflow"for engine-driven initial-state writes; there is no valid"workflow"value and this is tracked for fix.
OPTIMISTIC CONCURRENCY
Section titled “OPTIMISTIC CONCURRENCY”Entity writes are protected by two independent guards:
- Transaction-level (always on): every write runs in a SERIALIZABLE transaction with first-committer-wins (SI+FCW) read-set validation at commit time. A concurrent committer who changes an entity this transaction read will cause this transaction to abort at commit with
409 CONFLICT, retryable: true(seeerrors.CONFLICT). PostgreSQL’s own SQLSTATE 40001 detection covers write-write races equivalently. Callers do not opt in to this; it cannot be disabled. - Cross-request precondition (opt-in via
If-Match): theIf-Matchheader carries themeta.transactionIdfrom the caller’s earlier read in a separate HTTP request. If the entity’s currentmeta.transactionIddoes not match, the server returns412 Precondition Failed(seeerrors.ENTITY_MODIFIED). This catches the race window between the caller’s GET and PUT — a window the transaction-level guard cannot see, because the GET and PUT happen in different transactions.
To use the cross-request precondition: read the entity (GET /entity/{id}), note meta.transactionId, include it in If-Match on the subsequent update. Omitting If-Match does not turn off transaction-level conflict detection, but it does mean the PUT will reconcile against whatever state the entity has at PUT-time — including any concurrent commits that happened between the caller’s GET and PUT.
See cyoda help errors ENTITY_MODIFIED for the recovery flow on a 412.
ERRORS
Section titled “ERRORS”errors.ENTITY_NOT_FOUND—404— entity UUID does not existerrors.ENTITY_MODIFIED—412—If-Match-guarded update rejected; supplied transaction ID does not match the entity’s current versionerrors.MODEL_NOT_FOUND—404— model referenced during create does not existerrors.MODEL_NOT_LOCKED—409— model exists but is not inLOCKEDstate; entities cannot be created until the model is lockederrors.VALIDATION_FAILED—400— payload fails schema validation against the modelerrors.INCOMPATIBLE_TYPE—400— entity payload’s leaf value type is not assignable to the schema’s declared DataType for that field; carriesfieldPath,expectedType,actualTypeinpropertieserrors.CONFLICT—409— storage-level transaction serialization conflict (retryable)errors.IDEMPOTENCY_CONFLICT—409— reserved; not yet implemented (#91). Future contract: returned on collection create/update when theIdempotency-Keyheader is re-used with a different payload bodyerrors.TRANSITION_NOT_FOUND—404— named transition does not exist in the workflowerrors.BAD_REQUEST—400— malformed request, invalid UUID, conflicting query parameters, states filter exceeds 1000 entries
EXAMPLES
Section titled “EXAMPLES”Create a single entity:
curl -s -X POST \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"category":"physics","year":"2024"}' \ "http://localhost:8080/api/entity/JSON/nobel-prize/1"Read an entity:
curl -s -H "Authorization: Bearer $TOKEN" \ "http://localhost:8080/api/entity/74807f00-ed0d-11ee-a357-ae468cd3ed16"Read an entity at a point in time:
curl -s -H "Authorization: Bearer $TOKEN" \ "http://localhost:8080/api/entity/74807f00-ed0d-11ee-a357-ae468cd3ed16?pointInTime=2025-08-01T10:00:00Z"Update an entity with loopback transition:
curl -s -X PUT \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -H "If-Match: cb91fa80-d4a8-11ee-a357-ae468cd3ed16" \ -d '{"category":"chemistry","year":"2024"}' \ "http://localhost:8080/api/entity/JSON/74807f00-ed0d-11ee-a357-ae468cd3ed16"Update an entity with a named transition:
curl -s -X PUT \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"category":"chemistry","year":"2024"}' \ "http://localhost:8080/api/entity/JSON/74807f00-ed0d-11ee-a357-ae468cd3ed16/APPROVE"Delete a single entity:
curl -s -X DELETE \ -H "Authorization: Bearer $TOKEN" \ "http://localhost:8080/api/entity/74807f00-ed0d-11ee-a357-ae468cd3ed16"Delete all entities for a model:
curl -s -X DELETE \ -H "Authorization: Bearer $TOKEN" \ "http://localhost:8080/api/entity/nobel-prize/1"List all entities for a model (page 0, size 20):
curl -s -H "Authorization: Bearer $TOKEN" \ "http://localhost:8080/api/entity/nobel-prize/1?pageSize=20&pageNumber=0"Get entity change history:
curl -s -H "Authorization: Bearer $TOKEN" \ "http://localhost:8080/api/entity/74807f00-ed0d-11ee-a357-ae468cd3ed16/changes"Get available transitions:
curl -s -H "Authorization: Bearer $TOKEN" \ "http://localhost:8080/api/entity/74807f00-ed0d-11ee-a357-ae468cd3ed16/transitions"Create a multi-model collection:
curl -s -X POST \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '[{"model":{"name":"nobel-prize","version":1},"payload":"{\"category\":\"physics\",\"year\":\"2024\"}"}]' \ "http://localhost:8080/api/entity/JSON"Get statistics by state for a model:
curl -s -H "Authorization: Bearer $TOKEN" \ "http://localhost:8080/api/entity/stats/states/nobel-prize/1"SEE ALSO
Section titled “SEE ALSO”- models
- search
- workflows
- errors.ENTITY_NOT_FOUND
- errors.ENTITY_MODIFIED
- errors.MODEL_NOT_FOUND
- errors.MODEL_NOT_LOCKED
- errors.VALIDATION_FAILED
- errors.INCOMPATIBLE_TYPE
- errors.CONFLICT
- errors.TRANSITION_NOT_FOUND
- openapi
See also
Section titled “See also”cyoda help models— A model is a named, versioned schema registered per tenant. Every entity in the system is an instance of exactly one model. Models are identified by(entityName, modelVersion). The model ID is a deterministic UUID v5 derived from that key:UUID.newSHA1(NameSpaceURL, "{entityName}.{modelVersion}").cyoda help search— Search operates against a specific entity model(entityName, modelVersion). Two modes are supported:cyoda help workflows— A workflow definition is a named finite state machine attached to an entity model. Workflows are stored per model reference(entityName, modelVersion). A model may have multiple workflow definitions; the engine selects the matching one per entity using the workflow-levelcriterionfield evaluated at entity creation time. When nocriterionmatches, the engine uses the default built-in workflow.cyoda help errors ENTITY_NOT_FOUND— No entity with the given ID exists in the tenant’s data store, or the entity existed at a point-in-time that precedes the requested snapshot. Also returned for audit log lookups when the specified event or message cannot be found.cyoda help errors ENTITY_MODIFIED— When an entity update request carries anIf-Matchheader, the server requires the supplied transaction ID to equal the entity’s currentmeta.transactionId. A mismatch means another writer has updated the entity since the caller’s last read. The optimistic-concurrency guard rejects the update rather than silently overwrite.cyoda help errors MODEL_NOT_FOUND— The entity type or model name specified in the request does not exist in the tenant’s model registry. Occurs when creating entities with an unknown type, importing data that references a missing model, or performing model lifecycle transitions on a model ID that does not exist.cyoda help errors MODEL_NOT_LOCKED— Entity creation and bulk write operations require the model to be in theLOCKEDlifecycle state. Models inDRAFTor unlocked-for-editing state reject writes to prevent schema changes from affecting in-flight data.cyoda help errors VALIDATION_FAILED— UnlikeBAD_REQUEST(which covers parse failures), this error is returned when the payload is parseable but violates the registered model schema — for example, a required field is missing, a value is out of the allowed range, or a workflow guard condition is not satisfied. The error detail includes the specific validation failure.cyoda help errors INCOMPATIBLE_TYPE— Returned byPOST /entity/{format}/{name}/{version}and the entity-update surfaces when a leaf field’s value cannot be coerced into the model’s declared DataType (e.g. submitting"abc"against anINTEGERfield, or13.111against anINTEGERfield on a model whosechangeLevelis empty so type widening is not in scope).cyoda help errors CONFLICT— The server detected that the entity was modified by another writer between the time it was read and the time the current write was committed. Normal outcome under concurrent load.cyoda help errors IDEMPOTENCY_CONFLICT— The idempotency key is supplied via theIdempotency-KeyHTTP header on collection create and update requests. Seecrudfor the request shape.cyoda help errors TRANSITION_NOT_FOUND— Entity workflow state machines define explicit transitions between states. This error fires when a transition is triggered that does not exist in the model’s workflow definition for the entity’s current state. Also occurs when the transition name is misspelled or when the entity is in a terminal state that allows no further transitions.cyoda help openapi— cyoda-go generates its OpenAPI 3.1 specification from the embeddedapi/openapi.yamlfile compiled into the binary at build time. The spec is served at/openapi.jsonwith runtime-patched server URLs. The Scalar API Reference UI is served at/docsand loads the spec from/openapi.json.
Raw formats
Section titled “Raw formats”/help/crud.json— full descriptor (matchesGET /help/{topic}envelope)/help/crud.md— body only