Guide 06 · Developer docs

The APIs: REST, GraphQL and custom endpoints

Every Core dna site answers three kinds of API request under /cdna-api: REST for everything, GraphQL for reads that span several entity types, and web events for endpoints you define yourself as jobs. Which fits which task, one worked request for each, and what is true of all three. Jobs were called hooks until the module was renamed Orchestration; the API's routes still use the old name.

L1–L3
Unit 02 · Writing content

Writing areas

A layout area takes a value in the shape its input type expects, and that shape is often not the one a read gives back. The write shape for each input type, the ones that fail loudly and the ones that do not, and why a record read with areasContent cannot be sent back as it is.

Who this is for. The integrations engineer writing page, post or record content. To change one layout area, send areaContent(name) inside a patch; to write them all, send areas inside revisions. Either way, the value is the same. areaComponent(name) is another name for areaContent(name).

The write shape for each input type

Input typeSendWatch for
Text, Textarea, Richtext, CodeA string; Richtext as HTMLA regular expression or maximum length set on the input type is checked
NumberA number
Switchtrue or falseOn reads back as "active": true, and through areaText as "1"; off reads as empty. true, "true", 1 and "1" are on; anything else, "yes" included, is saved as off with a 200
SelectThe option's key: the part before :: in the input type's value, full-bleed in full-bleed::Full width (edge to edge)A label, or a key the input type does not have, is a 422 "This value is not valid."
MultiselectA JSON-encoded string of keys: "[\"red\",\"green\"]"A JSON array is a 422 (below)
Date, DatetimeA stringStored exactly as sent, in any format, with no error: next Tuesday is saved as written
Image, FileThe image's or file's idUpload first; the upload's answer has the id
RecordA record idnull clears it. An id that does not exist, or one that is not a number, is an error
RecordsA list of record idsReplaces the whole list; every id is checked
Component{"name": …, "layout": <id>, "areas": {…}}The component's own areas follow this table
Component CollectionA list of componentsReplaces the whole collection; to change one element, use the collection keys

An empty value, null, "" or [], removes the layout area from the revision. The input type of each layout area, and a select's option keys, are on the layout. Read them before writing to a layout you have not met:

A layout's areas, with their input types and option keys
GET /cdna-api/common/layout/30?properties={id,name,areas{name,type{name,category,editor,possibleValues{value}}}} HTTP/1.1
Host: hub.coredna.com
Authorization: Bearer YOUR_ACCESS_TOKEN
Accept: application/json
Response 200 OK
{
  "result": "success",
  "data": {
    "id": 30,
    "name": "Hub Page Sections",
    "areas": [
      {
        "name": "navSection",
        "type": {"name": "Text", "category": "text", "editor": "text", "possibleValues": []}
      },
      {
        "name": "announcement",
        "type": {"name": "Component", "category": "component", "editor": null, "possibleValues": []}
      },
      {
        "name": "width",
        "type": {
          "name": "Content Width",
          "category": "text",
          "editor": "select",
          "possibleValues": [
            {"value": "full-bleed::Full width (edge to edge)"},
            {"value": "layout single::Standard width"}
          ]
        }
      },
      {
        "name": "pageSections",
        "type": {"name": "Component Collection", "category": "collection", "editor": null, "possibleValues": []}
      }
    ]
  }
}
Real response from this documentation site

The multiselect

The one shape nobody guesses. A JSON array is refused:

A multiselect area, written as a JSON-encoded string
PUT /cdna-api/custom-entities/apiSandbox/2?properties={id,activeRevision{id},colours:activeRevision.areaText(colours),colourList:activeRevision.areaValues(colours),featured:activeRevision.areaText(featured)} HTTP/1.1
Host: hub.coredna.com
Authorization: Bearer YOUR_ACCESS_TOKEN
Accept: application/json
Content-Type: application/json

{
  "patchRevision": {
    "originRevision": 8,
    "activeRevision": true,
    "areaContent(colours)": "[\"red\",\"green\"]"
  }
}
Response
{
  "result": "success",
  "data": {
    "id": 2,
    "activeRevision": {
      "id": 9
    },
    "colours": "[\"red\",\"green\"]",
    "colourList": [
      "red",
      "green"
    ],
    "featured": "1"
  },
  "message": "The API sandbox has been saved successfully."
}
{
  "result": "error",
  "validationErrors": {
    "patchRevision.areaContent(colours)": [
      {
        "message": "Unexpected associative array encountered",
        "code": "7d94a027-0001-da4a-4325-6a832f940d4f",
        "propertyPath": "patchRevision.areaContent(colours)"
      }
    ]
  },
  "message": "Unexpected associative array encountered"
}
Real responses from this documentation site, on its API sandbox record

Read it back with areaValues(name) to get the list, as colourList above; areaText(name) returns the string as stored. The switch in the same record reads "1" through areaText. (A list of numbers is not refused the same way, which is why a Records area takes a plain JSON list of ids.)

What is validated, and what to check yourself

With a 422 that names the layout area in validationErrors:

  • A layout area the layout does not have. The message is the raw key layout.area.not_found. Check the layout rather than the spelling of the key.
  • A multiselect sent as an array, as above.
  • A select value that is not one of its keys, on a page: "This value is not valid."
  • A required area left empty, a text that fails the input type's regular expression or maximum length, and a collection with fewer or more elements than the layout's minimum or maximum.

Not validated, so check these yourself before writing:

  • Dates. Format them in the client, in the format the templates that read them expect, such as 2026-10-17.
  • Switches. Send true, "true", 1 or "1" for on.
  • Multiselect keys. Check each key against the input type's possible values before writing to a custom entity record.
  • Empty values. An empty value removes the layout area rather than storing an empty one, so send a real value to keep it.

Why a read cannot be sent back

activeRevision{areasContent} describes each layout area: its id, its input type, and its value under text, content or, for a switch, active. A component collection comes back as collection, each element with componentId, componentName, componentLayout, componentGlobal and its layout areas described the same way. None of that is the write shape. To copy content from one record to another, map each layout area to the value in the table: componentName becomes name, componentLayout becomes layout, each layout area's description becomes its bare value, and a global component becomes a reference. Leave componentId behind: it changes with every revision.

For reading values in a client, the getters are simpler than areasContent: areaText(name) for any single value, areaValues(name) for a multiselect. Reading layout areas has the selectors.

Go deeper

Was this page helpful?

Your answer goes to the docs team.