JSON contract
This page documents the exact output shape of the conversion per field type. The contract is frozen by characterization tests (Content — they assert the complete JSON per fixture record); changes are deliberate decisions, not accidents.
Global rules
- Keys are the Content Block field identifiers (
my_), mapped from the database columns (field tx_). Columns without a Content Block field definition pass through with their column name.myext_ my_ field - Order: keys are alphabetically sorted (
ksort) — insidedata, inside nested collections, everywhere. - System fields are stripped:
uid,pid,col,Pos CType,foreign_,table_ parent_ uid tx_.container_ parent - Never break the response: unknown value types become
nullwith a debug log entry; missing files produce__entries (see below).error Message - The
id/type/colwrapper aroundPos datais built by EXT:headless, not by this extension.
Field types
| Content Block type | JSON shape |
|---|---|
| Text | string, unchanged |
| Textarea | string, unchanged |
Richtext (Text with enable) | HTML string via lib. |
| Number | int (or float), 0/null when empty |
| DateTime | W3C string 2023- (configurable via options.), null when empty |
| Select | selected value(s): string or array of strings, "" when empty |
| Password | "" — always blanked, hashes never leave the system |
| Email / Color / Slug | string |
| Json | parsed array (null when the column is empty) |
| Link | link object, see below (null when empty) |
File (one) | file object, see below |
File (one) | array of file objects |
| Folder | array of storage-absolute folder paths, e.g. ["/ |
| Category | array of {uid, pid, title} (reduced shape — deliberate, see design record) |
| Collection | array of item objects, each fully converted (identifier keys, sorted) |
| Relation | resolved records, fully converted per target table |
| FlexForm | parsed FlexForm values as array |
| Checkbox | null + debug log — the Core Record API resolves checkboxes to booleans, and booleans are not part of the frozen contract. Register a custom normalizer if you need checkbox values. |
| unknown types | null + debug log entry |
Link object
{
"url": "https://example.com",
"target": "",
"type": "url",
"title": "https://example.com",
"config": { "parameter": "https://example.com" },
"attr": { "href": "https://example.com" }
}
titleis the typolink text, which falls back to the URL when no link text is set.- Empty links are
null. - Unresolvable targets produce the same object with empty strings plus
__.error Message
File object
{
"id": 1,
"alt": "",
"title": "",
"publicUrl": "https://example.com/fileadmin/image.jpg",
"thumbnails": {
"mobile": "https://example.com/fileadmin/_processed_/…jpg",
"desktop": "https://example.com/fileadmin/_processed_/…jpg"
}
}
idis thesys_uid.file_ reference publicis absolute and respects manual Backend crops.Url thumbnailsexists only when image variants are defined for the field — see Define image variants.- A missing/deleted file turns the whole field into
{"__.error Message": "…"}
Category shape rationale
Categories use the reduced {uid, pid, title} shape for historical contract reasons (the production consumer depends on it). If you need more fields, register a custom normalizer that claims Lazy of sys_ records with a higher priority.
Collections and relations
Each collection item is converted with the full pipeline of its own table: field identifiers as keys, system fields stripped, values normalized. Relation targets are resolved via the Core Schema API (Active), so the correct sub-schema (per record type) applies.