Schemas and Relationships
Behaviors and gotchas when managing fields, relationships, and custom objects
This guide covers the non-obvious behaviors of the schema, relationship, and custom-object endpoints. For the endpoint mechanics themselves, see the Schemas and Records Relationships reference.
Schema fields
Schemas describe the fields on each object. GET /schemas returns a JSON:API
response whose data array is a flat list of every schema in the workspace, each
identified by a schema URL. Built-in objects
and custom objects alike appear under .../entities/*, for example
.../entities/person and .../entities/c_sales_order. The .../core/* entries
are the shared base definitions those schemas build on.
Use "type": "date" for date fields users need to edit: custom "date-time"
fields render read-only in the UI. Enum values are case-sensitive: "Active"
and "active" are treated as different values.
Editing enum values is partly destructive
Adding values to an existing enum is safe. Removing values is destructive:
any record set to a removed value loses it (a single-select field is cleared to
null; a multi-select field drops that option), and those records fall out of any
lists that filter on the value. Always check which records use a value before
removing it.
Relationships
Relationships connect records across object types: people to companies, deals to
companies, people to deals. You can also set a relationship through a foreign-key
field (e.g. company_id) at creation time.
PATCH .../relationships/{relationship} behaves differently by relationship
kind. For many-to-many relationships (such as the people on a deal, or a
person's meetings) it replaces the entire set: any related records not in
the request body are unlinked. For one-to-many relationships (such as a
company's people) it is additive: it links the records you send and leaves
the rest attached, though linking a record that already belongs to another
parent reassigns it. To remove specific records in either case, use DELETE
on the same path.
Custom objects
Custom object names are normalized to a c_ prefix: "Sales Order" becomes
c_sales_order. If a new object's name normalizes to one that already exists,
creation is rejected with a 422. Once created, custom objects use the same
record endpoints as standard objects (single and bulk) with the c_-prefixed
name as the {object} path parameter.
User identifiers
Every record carries _created_by and _updated_by: opaque actor identifiers,
not UUIDs. The value depends on who made the change:
- A workspace user: that user's ID, whose exact format depends on the
workspace's auth provider (for example, a Google OAuth subject like
google-oauth2|106236165388989412707). - An automated actor: a system actor (
system,agent, orrep).
Treat these values as opaque. Resolve a user identifier to a name and email through the Users endpoint; the system-actor values are not workspace users and won't resolve there.