Structured Content Field Types
Field types
Every field in a schema definition has a type property that determines what values are valid, how data is stored, and which indexing options are available.
A field can be indexed for editorial search, for retrieval, or both, and the index kinds available to it depend on its type. Editorial indexes back the editorial search API used by Data Center and WebSked; retrieval indexes back Content API queries. The two columns below list the index kinds each type accepts; a dash means the type cannot be indexed at all, and any search_settings entry on it is rejected. A field indexed for editorial only cannot be used as a Content API filter — long-text is the notable case.
| Type | Description | Max length / constraint | Editorial index | Retrieval index |
|---|---|---|---|---|
short-text | Single-line plain text string | 100 characters | keyword, semantic | keyword |
long-text | Multi-line plain text | 50,000 characters | semantic | — |
rich-text | Formatted text stored as HTML. Sanitized on write against a fixed allowlist of tags and attributes (see Rich-text fields). | 0.5 MB | — | — |
date | ISO 8601 date string (YYYY-MM-DD) | N/A | range | range |
date-time | ISO 8601 date-time string (YYYY-MM-DDTHH:MM:SSZ) | N/A | range | range |
integer | Whole number | N/A | range | range |
decimal | Decimal (floating-point) number | N/A | range | range |
boolean | true or false | N/A | keyword | keyword |
geo-point | Geographic coordinate object: { lat, lon } | Lat: –90 to 90, Lon: –180 to 180 | geo | geo |
enum | One value from a predefined list | 50 values max, each 1–100 chars | keyword | keyword |
array | JSON array of values. Free-form unless items is set (see Reference fields and Multi-select fields) or a validation rule is declared. | Max 256 items | keyword (multi-select only) | keyword (multi-select only) |
object | Nested JSON object. Free-form unless a validation rule is declared. | Max 2 levels of nesting | — | — |
reference | A pointer to another Arc XP document, resolved into the record when it is indexed (see Reference fields). | 300 per record | — | — |
Field definition properties
| Property | Type | Required | Description |
|---|---|---|---|
key | string | Yes | Field identifier. Lowercase, hyphens/underscores allowed. 3–30 chars. Immutable after creation. |
display_name | string | Yes | Label shown in the UI. 1–50 chars. Can be changed at any time. |
type | string | Yes | One of the field types above. Immutable after creation. |
is_required | boolean | No | Whether the field is required on record creation. Defaults to false. Can be relaxed (true → false) but not tightened (false → true) after creation. |
description | string | No | Help text for editors. 0–500 chars. Can be changed at any time. |
enum_values | array | Conditional | Required when type is enum, or when items is enum. Array of string values. Max 50 values; each 1–100 chars; no duplicates. |
search_settings | object | No | Enables API-level indexing for this field. |
reference_type | string | Conditional | Required when type is reference, or when items is reference. Names the kind of document the field targets. Changing it is a breaking change. |
reference_schema | string | Conditional | Required when reference_type is schema; rejected for every other target type. Names the schema the reference must point at. Changing it is a breaking change. |
items | string | No | Only valid when type is array. Declares a typed array: reference or enum. Changing it is a breaking change. |
validation | object | No | Rules the field’s values must satisfy — see Validation rules. Can be added, changed or removed at any time; applies to records saved afterwards. |
Validation rules
A field can carry a validation object that its values must satisfy. It is a small subset of JSON Schema, with the standard keyword names; any keyword outside the set below is rejected when the schema is saved. Rules are enforced when a record is created or updated. Existing records are not re-checked, but they must satisfy the current rules the next time they are saved. Changing a rule is not a breaking change. boolean, enum, date, date-time, rich-text, reference and geo-point fields cannot carry validation.
| Field type | Keywords |
|---|---|
integer, decimal | minimum, maximum — inclusive bounds; whole numbers on an integer field |
short-text, long-text | minLength, maxLength — in characters, up to 100 on short-text and 50,000 on long-text; pattern — a regular expression (RE2 syntax, up to 256 bytes) matched anywhere in the value, so anchor it with ^…$ for a full match |
short-text | format — url (an absolute http/https URL with a host), slug (lowercase letters, numbers and single hyphens), email (one address, no display name), phone (international E.164 form such as +14155552671) or iso-country (an uppercase two-letter ISO 3166-1 code such as US) |
array | minItems, maxItems (up to 256); items — a definition every element must match (not available when the field’s items is set) |
object | properties — a definition per property (up to 50); required — property names from properties that must be present |
A nested definition (items, or an entry in properties) declares a type — string, number, integer, boolean, object or array — and takes the keywords valid for that type, plus enum on strings (up to 50 values). A field can hold one level of nested object or array definition, such as the array of objects below. Once properties is declared, keys not listed there are rejected.
{ "key": "ingredients", "display_name": "Ingredients", "type": "array", "validation": { "minItems": 1, "maxItems": 50, "items": { "type": "object", "required": ["amount", "unit", "ingredient"], "properties": { "amount": { "type": "number", "minimum": 0 }, "unit": { "type": "string", "enum": ["g", "ml", "cup", "tbsp", "tsp"] }, "ingredient": { "type": "string", "maxLength": 100 } } } }}A handle such as @newsroom is a pattern (^@[A-Za-z0-9_]{1,30}$), not a built-in format.
Errors
When a record fails validation, the response lists every failing field, not just the first:
{ "error_code": "ErrInvalidParam", "error_message": "field 'ingredients[2].amount' must be greater than or equal to 0", "error_details": [ { "path": "ingredients[2].amount", "code": "minimum", "message": "field 'ingredients[2].amount' must be greater than or equal to 0" }, { "path": "website", "code": "format", "message": "field 'website' must be a valid URL" } ]}error_message is the first failure. Each entry’s path names the value (dots for object properties, [i] for array items) and code is required, type, enum, additionalProperties, uniqueItems, or the rule keyword that failed. A missing required field is reported as required field 'x' is missing.
Rich-text fields
A rich-text field holds formatted text as an HTML string. The value is sanitized when the record is written against the allowlist below; the sanitized value is what is stored and returned, so it may differ from what was submitted. Elements and attributes not listed are removed, keeping their text content.
Allowed tags
| Group | Tags |
|---|---|
| Inline formatting | b, strong, i, em, u, s |
| Structure | p, br, span, h1–h6 |
| Lists | ol, ul, li |
| Links | a |
Allowed attributes
| Attribute | On | Notes |
|---|---|---|
href, target | a | href must be an http, https, mailto or tel URL; any other value drops the attribute. When target is kept, rel="noopener noreferrer" is set. |
style | p, li, h1–h6 | Only text-align (left, center, right, justify, start, end) is kept. |
Everything else is removed, including script, style, iframe, img, video, audio, object, embed, forms, and all on* event handlers. The content of script-like elements such as script, style and iframe is removed along with them.
Limits
- 0.5 MB (524,288 bytes) per value, checked before and after sanitization.
- Markup nested more than 256 levels deep is rejected.
Data Manager’s editor produces markup inside this allowlist, so content written there is stored unchanged.
Rich-text fields cannot be indexed for editorial or retrieval search. Pair one with a short-text or long-text field when the content needs to be searchable.
Multi-select fields
A multi-select is an array field with items set to enum. Its values must come from enum_values, each listed at most once. An empty list on a required field counts as missing.
{ "key": "cuisines", "display_name": "Cuisines", "type": "array", "items": "enum", "enum_values": ["italian", "french", "japanese"]}Reference fields
A reference field points at another Arc XP document. When the record is indexed, the reference is replaced by the target’s full Arc XP Native Specification (ANS) document, so a record fetched from the Content API carries the referenced content inline.
Declaring the field
reference_type names the kind of content the field targets, and is required on every reference field:
reference_type | Target |
|---|---|
schema | Another Structured Content record |
image | A Photo Center image |
video | A Video Center video |
gallery | A Photo Center gallery |
story | A story |
author | An author |
One target type per field; a field cannot accept “image or video”. For schema targets, reference_schema names the schema being pointed at, and that schema cannot be deleted while the reference exists — DELETE /draft/v1/schema-type/{name} is refused and names the referencing schemas, so the reference field has to be removed or repointed first:
{ "key": "main_ingredient", "display_name": "Main ingredient", "type": "reference", "reference_type": "schema", "reference_schema": "ingredient"}A list of references is an array field with items set to reference:
{ "key": "ingredients", "display_name": "Ingredients", "type": "array", "items": "reference", "reference_type": "schema", "reference_schema": "ingredient"}Stored value
The value of a reference field is an ANS reference node:
{ "type": "reference", "subtype": "ingredient", "referent": { "type": "schema", "id": "PLVVMP6DQZDQ3EU3LZ7HKQZCJE" }}referent.idmust be the target document’s ANS_id.referent.typemust match the field’sreference_type.subtypeis required forschematargets and must equalreference_schema—referent.typeis always"schema"there, sosubtypeis the only thing naming which schema is meant. For the other target types it is accepted but not required.
Validation on write
For schema targets, the referenced record must already exist and its schema must match reference_schema; it does not need to be published. For the other target types there is no existence check on write — an id that resolves to nothing surfaces as an unresolved reference at retrieval time, the same way a story referencing a deleted image behaves.
What retrieval returns
- References are resolved one level deep. References inside a resolved target are left as unresolved nodes, which is also how reference cycles are handled.
- A record may carry at most 300 references, counting every reference field and target type together. This ceiling is applied when the record is indexed, not when it is saved: a record that exceeds it is saved successfully but fails to index, so it will not appear in the Content API. An array of references is separately limited to 256 items, like any other array.
- A target that cannot be resolved (wrong id, deleted, or not yet published where the published copy is requested) leaves the reference node in place, unresolved. The rest of the record is unaffected.
- The draft/published distinction is honoured for
schema,storyandvideotargets. Images, galleries and authors have a single current version.
Limitations
- Reference fields cannot be indexed. No index kind is valid for a reference field, so a
search_settingsentry on one is rejected. They consume none of the organization’s searchable-field capacity and cannot be used as a query field. To find which records point at a given document, use the Usage tab in Data Center rather than a search query; those counts come from the reference graph, not from a search index. - Resolved content can go stale. If a target changes after a referencing record was indexed, the copy embedded in that record is not refreshed until the referencing record is republished.