CodamAIDocs
Topicdone

The endpoints

All HTTP routes of CRMS under /crms: render, edit and approve templates, read and verify final documents. Where they run, what they accept and who may call them.

Variants
Rendering: render, validate, capabilitiesTemplates: editions, variants, draft, approval, revisions, chainDocuments: read, list, verify, legal hold, eraseembedded with crms-rest, embedded without, remote, separate service

What this is about

CRMS offers its functions over HTTP, all under the path /crms. This is done by the CRMS HTTP interface. It is an adapter: it reads a request, calls the matching function of a CRMS module and writes the response. It has no business logic of its own.

Where the routes run

The routes exist where CRMS runs embedded, meaning in the same process as the application, and the CRMS HTTP interface is on the classpath. The separate CRMS service always brings it along.

Does this application have /crms?
Embedded with HTTP interfaceEmbedded without HTTP interfaceRemoteThe CRMS service itself
CRMS runsin the application's processin the application's processas a separate serviceas a separate service
HTTP interfacein the buildnot in the buildforbidden, the start failsalways included
Routes /crms/**yes, behind the application's security chainno, the application only calls CRMS in codeno, the application uses crms-clientyes

In the remote operating mode the application would otherwise pass the CRMS service on under its own routes, behind its own security. That is why the start refuses the HTTP interface there. More on the operating modes in Embedded or standalone.

The path of a request

A request to /crms
  1. CIAS
    Security chain
    Is the token valid? CIAS determines person, tenant and roles.
    ↳ no 401
  2. CRMS
    Reading the request
    Is someone signed in? Is the body JSON, not too large, are all fields known and of the right type?
    ↳ no 401 crms-authentication-required, 400 malformed-json, 413, 415 or 422 validation-failed
  3. CRMS
    Role and visibility
    Does the person have the required role, and can they see the object?
    ↳ no 403 or 404
  4. The module runs the function, the response goes back

The HTTP interface reads no token itself. The person comes through CIAS, see The roles.

Rendering

RouteBodyResponseWho
POST /crms/renderthe render requestthe document’s bytesevery signed-in person, for templates they can see
POST /crms/render/validatethe render request200 {"violations": [...]}, empty means validas above
GET /crms/capabilities–what this installation offersCRMS checks no person, the application’s security chain applies

Rendering needs no role of its own. It is enough to be signed in and to be allowed to see the template. Which template a request finds is described in How a template is found, the fields of the request in The render request.

Request
POST /crms/render
Content-Type: application/json

{ "template": "audit-report", "format": "PDF", "mode": "FINAL",
  "reference": "audit-4711", "locale": "de-DE",
  "data": { "customer": { "name": "ACME" } } }
Response
200
Content-Type: application/pdf
Content-Disposition: inline; filename="audit-report.pdf"
Crms-Template-Key: audit-report
Crms-Template-Scope: TENANT          ← which edition won
Crms-Template-Variant: de-DE         ← which language variant
Crms-Template-Revision: 3f1c…        ← which revision of the template
Crms-Template-Revision-Hash: sha-256:…
Crms-Document-Revision: 9a7e…        ← with FINAL only
X-Content-Type-Options: nosniff

<the bytes of the PDF>

/crms/render/validate checks the same request without rendering. GET /crms/capabilities names the formats, the default PDF profile, the admitted scopes, the languages, whether final documents are stored (documentRevisions), whether transient documents are allowed (transientDocuments), and the limits (timeout, maxOutputBytes, maxPayloadBytes, maxAttachmentCount, maxAttachmentBytes).

Templates

A template editor uses these routes. Each route calls exactly one function of the template module. See means: the template belongs to the system, to your tenant or to you. Write means: in addition, the write role of the edition’s scope. Review means: the role of the current approval stage.

RouteBodyResponseWho
GET /crms/templates–the editions you can seesee
POST /crms/templateskey, outputType, scope, defaultLocale201 the edition, with Locationwrite
GET /crms/templates/{edition}–the editionsee
GET /crms/templates/{edition}/variants–its variants, the default language firstsee
POST /crms/templates/{edition}/variantslocale201 the variantwrite
GET /crms/variants/{variant}/draft–the draft, or 204 without a draftwrite
PUT /crms/variants/{variant}/draftexpectedVersion, contentthe saved draftwrite
GET /crms/variants/{variant}/draft/assets/{name}–an asset of the draft, as a downloadwrite
POST /crms/revisions/{revision}/draftexpectedVersionthe draft with the content of this revisionwrite
POST /crms/variants/{variant}/submitreason (optional)the new revisionwrite
POST /crms/revisions/{revision}/approve–the revision afterwardsreview
POST /crms/revisions/{revision}/rejectreasonthe revision afterwardsreview
POST /crms/variants/{variant}/rollbacktarget, reason (optional)the new, published revisionwrite
POST /crms/variants/{variant}/retirereason (optional)204write
GET /crms/variants/{variant}/revisions–all revisions, oldest firstsee
GET /crms/variants/{variant}/trail–every entry of the chain, with all hashessee
POST /crms/variants/{variant}/verify–{"intact": true} or {"intact": false, "brokenAt": 7}see
GET /crms/revisions/{revision}/content–the revision’s content, assets describedsee
GET /crms/revisions/{revision}/assets/{name}–an asset of the revision, as a downloadsee

A few rules apply to all template routes:

  • A draft is always saved whole. content replaces the old content, with source, fields and all assets as Base64. Base64 is a notation that writes bytes as text.
  • expectedVersion is the version of the draft your change builds on, 0 for none. If someone else saved in the meantime, CRMS answers 409 template-draft-changed.
  • Whether a reason is required is decided by the installation. When rejecting, it is always required.
  • The body is limited, 16 MiB by default, adjustable through CODAMAI_CRMS_REST_TEMPLATE_MAX_BYTES. Above that: 413 request-too-large|<limit>.
  • Assets come as a download (Content-Disposition: attachment) with X-Content-Type-Options: nosniff and Content-Security-Policy: sandbox. This way an SVG cannot run scripts on the application’s page in the browser.

The whole flow from draft to publication is described in The life cycle of a template and Approval.

Documents

These routes work with final documents. The archive checks the role before it looks anything up, the same as for an embedded call.

RouteRoleResponse
GET /crms/documents?template=…&scope=…&reference=…readthe revisions of the chain, oldest first
GET /crms/documents/{revision}readthe document’s bytes, inline
POST /crms/documents/{revision}/verifyread{"ok": true} or {"ok": false, "problem": "<key>"}
POST /crms/documents/{revision}/legal-holdlegal hold204
POST /crms/documents/{revision}/legal-hold/releaselegal hold204
POST /crms/documents/{revision}/eraseerase204
  • When listing, all three parameters are required. If one is missing, you get 422 validation-failed with the rule required.
  • The three changing routes need a body {"reason": "litigation-hold"}. The reason is a key in kebab-case, not free text, because it ends up in a chain that is never deleted. Free text gives 422 validation-failed.
  • Reading returns the whole description of the revision in headers: Crms-Document-Revision, Crms-Document-Number, Crms-Document-Format, Crms-Document-Stored-At, Crms-Document-Retain-Until, Crms-Document-Legal-Hold, Crms-Document-Content-Hash and the Crms-Template-* headers as when rendering.
  • The archive always works in the tenant of the person asking and records them as the actor.

What verify, legal hold and erase mean in practice is described in Verify and export and Retention, legal hold and erasure.

Rules for all routes

RuleWhat it means
Known fields onlyAn unknown field in the body gives the rule not-allowed. Duplicate keys and text after the JSON object give malformed-json.
No silent conversion"5" is not a number. A value with the wrong JSON type is invalid. null counts as a missing field.
One spelling per IDIDs in the path are UUIDs in the usual long form, in lower or upper case. Short forms like 1-1-1-1-1 give invalid, with the name of the path variable as the field.
Text instead of numbers and objectsTimes are ISO-8601 text, languages are language tags like de-DE, hashes are <algorithm>:<hex>.
Compressed bodyEvery route accepts Content-Encoding: gzip. The limit applies to the unpacked bytes. Any other encoding gives 415 content-encoding-unsupported.
Documents protectedEvery document response carries X-Content-Type-Options: nosniff, HTML also Content-Security-Policy: sandbox. A script in a template therefore does not run with the reader’s session.
Whole responsesA document always comes in one piece, not streamed. This way even a late error can still come as an error answer.

Pitfalls

Next

Search