create_field
Add a new field to an entity schema. CHOOSING A TYPE — to LINK records (entity-to-entity relationship), use type 'reference' with targets; for an ARRAY of linked records (e.g. participants, tags) use 'reference' with multiple: true — do NOT store related record IDs as 'text' or as a 'list'. Use 'list' only for arrays of primitives (strings/numbers/booleans), with valueType. For enum fields provide values. Decide type, cardinality (multiple), and targets carefully: they're permanent once set (see update_field's description for what's changeable later and what isn't). Also works against the built-in users entity — its base fields (name/email/password/...) are fixed, but you can add your own business fields (e.g. 'role', 'gender', 'department') exactly like on any other entity; get its entity id from list_entities or describe_project. COMPUTED/STORED — for a field whose value is set by server-side logic rather than the client (computed=true, excluded from the create/update request schema) and/or never persisted (stored=false, e.g. a value presigned/derived fresh on every read): both default to the ordinary case (computed=false, stored=true) and are permanent once set. stored=false cannot be combined with search or unique. A stored=false field only gets a real value if something (today: a platform hook) populates it — declaring one on your own entity is schema support for a capability that isn't available to customer-defined logic yet.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| max | No | For text: max char length. For number: max value. For list/multiple: max items. | |
| min | No | For text: min char length. For number: min value. For list/multiple: min items. | |
| name | Yes | Field name in camelCase used in API payloads. Example: 'orderNumber', 'dueDate' | |
| type | Yes | Data type. text=string, number=float/int, boolean, date=YYYY-MM-DD, datetime=ISO8601, enum=fixed values (set `values`), reference=link to another record by ID (set `targets`; use multiple=true for an array of links), list=array of primitives (set `valueType`), object=free-form JSON. For relationships/arrays-of-IDs always use reference, never text or list. | |
| label | No | Human-readable display name | |
| hidden | No | Excludes the field from GET responses (write-only), e.g. for password-like fields (default false) | |
| search | No | Enables collection-GET filtering on this field via query operators (eq/ne/in/nin for enum/boolean/list/reference; eq/gt/gte/lt/lte for number/date/datetime; eq/starts for text). Results come from an async search index (small post-write lag) — see describe_project's `filtering` section or generate_openapi_spec for the exact operators/syntax this field supports once created. reference fields are always filterable regardless of this flag (except the system audit references _createdBy/_updatedBy/_deletedBy, which are never indexed) — enum and every other type require search:true. On an eligible type (enum/boolean/list/reference/date/datetime — not text/number), search:true ALSO automatically maintains a distinct-value counter for this field (no separate flag needed) — counts are returned under a `facets` key — {field: {value: count}} — only when the caller passes `?facets=true` (or `?facets=<thisFieldName>` to select just this field) on an UNFILTERED GET /{entity} (no query param other than limit/offset/facets); combining `facets=` with any real filter returns a clean 400 (FACETS_REQUIRES_NO_FILTERS), since the counts are a GLOBAL per-entity distribution that wouldn't describe a filtered result set. (default false) | |
| stored | No | If false, the value is never persisted — populated fresh at read time instead (default true, i.e. persisted normally). Cannot combine with search or unique. Permanent once set. | |
| unique | No | Value must be unique within the tenant (default false) | |
| values | No | For enum fields: list of allowed string values | |
| formula | No | Requires computed=true. Derives this field's value server-side from a sandboxed expression over OTHER fields on the same record — no hook/Function needed. Shape: {"type": "expression", "source": "<expression string>"}. `source` names other fields on this entity as bare identifiers (a reference field resolves to its id); supports arithmetic (+ - * / % **), comparisons, boolean/ternary logic, string literals, and a small whitelisted function set: concat(*args) (joins args, no implicit separator — write separators as literals, e.g. concat(category, '-', size)), upper(s), lower(s), trim(s), round(x, ndigits=0), abs(x), min(*args), max(*args). Examples: a `sku` field with formula {"type": "expression", "source": "concat(category, '-', size)"} becomes category+"-"+size on every create; a `total` field with {"type": "expression", "source": "round(quantity * unitPrice, 2)"} computes a real number, not a string. All-or-nothing: if any referenced field is missing on a given write, this field is simply left unset — most useful combined with unique=true and required source fields (e.g. an order number unique per customer built from two other fields). The expression cannot reference its own field's name. Permanent once set. | |
| pattern | No | For text fields: regex the value must match. Violations return 400 PATTERN_MISMATCH. | |
| targets | No | For reference fields: which entities this links to and which of their fields to inline on read. Example: [{"entity": "products", "projection": ["name", "price"]}]. On WRITE, supply the reference value as {"id": "<recordId>"} (or an array of those when multiple=true); on READ, the projected fields are returned inline. | |
| computed | No | If true, the field's value is set by server-side logic, not the client — excluded from the create/update request schema (default false). Permanent once set. | |
| location | No | REQUIRED when entity_id is a custom endpoint's id (EPT...), not applicable otherwise: whether this field validates that route's request body or a query parameter. stored/unique/search are forced/rejected server-side for an endpoint-owned field — nothing is ever persisted at the endpoint layer. | |
| multiple | No | For enum/reference: allow an array of values instead of a single value (default false). Use this for reference fields to model a one-to-many / array-of-IDs relationship. | |
| required | No | Must be present on POST (default false) | |
| entity_id | Yes | Entity record ID (e.g. 'ENT3') — or a custom endpoint's id (e.g. 'EPT3', from create_endpoint) to validate that route's request body or query parameters instead. In the endpoint case, also set `location` ('body' or 'query'). | |
| valueType | No | REQUIRED for type 'list': the element type. string/number/boolean = array of primitives. Do NOT use 'object' to model relationships — for an array of linked records use type 'reference' with multiple:true instead. | |
| description | No | ||
| default_value | No | Default value assigned on POST if field is omitted. Match the field's own type — a JSON boolean (true/false) for type 'boolean', a JSON number for type 'number', a string otherwise. Do NOT quote booleans/numbers as strings. |