Custom objects
Adding an object and its fields at runtime: what the module gates, which keys are refused, the limits, and how a relation makes a related list appear.
The custom_objects module lets a workspace add its own objects and fields alongside the fourteen standard ones. Everything else about them is the same: the same field kinds, the same record endpoints, the same permission checks.
The module gates the schema, not the data. Creating an object or a field needs it. Reading and writing records never does, in a custom object as much as a standard one, so a client that only moves data works whether the module is on or off.
Creating an object
POST /objects takes three things:
| Field | Shape |
|---|---|
key |
^[a-z][a-z0-9_]{0,62}$ — lower case, starts with a letter, up to 63 characters. This is what paths and filters use |
label |
1 to 120 characters. The plural name a list shows |
singularLabel |
1 to 120 characters. The name one record shows |
Two kinds of key are refused with object_key_reserved: the key of a standard object, and any key that collides with a name the platform uses internally. Pick something the product owns rather than something generic.
Changing an object
PATCH /objects/{objectId} accepts key, label, singularLabel and the revision it was read at.
An object’s key can change. A field’s cannot. Renaming an object’s key works, and every path and saved filter that named the old one stops matching, so it is not a free change. A field is the opposite: its update endpoint accepts key, type and targetObjectId but refuses to change any of them — field_key_immutable, field_type_immutable, field_target_immutable. Only label and required actually move.
Turning required on is refused while any record is missing that value, and a standard field’s required cannot be changed at all (field_system_locked). A virtual kind cannot be required, because nothing writes it.
Fields
Fields are added with POST /objects/{objectId}/fields, in the same nineteen kinds the standard objects use.
An object holds at most 256 fields. The 257th is refused with object_field_limit.
Ten keys are taken by the columns every object table carries, and a field may not use any of them:
id · name · organization_id · object_id · revision · created_at · updated_at · archived_at · created_by · updated_by
Using one answers field_key_reserved; reusing a key the object already has answers field_key_taken.
Relations make related lists
A relation field names the object it points at. The reverse direction is read from the other side: GET /objects/{objectId}/related answers the objects whose relation fields point at this one, which is what a related list is built from.
So a custom object becomes visible in a standard object’s context by pointing at it, not by being registered anywhere. Add a relation from your object to account, and accounts gain a related list of your records.
What does not change
A custom object’s records use the same endpoints as a standard object’s — /objects/{objectId}/records and the rest — and pass the same four permission checks. There is no separate scope for custom data: records.read and records.write cover every object the workspace has.