Custom objects
Ship whole data models: objects, fields, formulas, validation and field-level security — provisioned per tenant on install, with an auto-generated CRUD API.
Field types
| type | notes |
|---|---|
text / textarea | strings (single / long) |
number / currency / percent | numerics; currency/percent affect display |
date / datetime | ISO YYYY-MM-DD / RFC3339 |
email / phone / url | format-validated on write (https for urls) |
picklist / multi_select | require options[]; values validated against them |
checkbox | boolean |
reference | lookup; referenceTarget = lead | contact | company | opportunity | custom:<apiName>. This is how your objects RELATE to CRM records. |
formula | computed by the platform on read — never writable |
Formula language
Spreadsheet-style expressions over the record's own fields:
win_rate = closed_won / (closed_won + closed_lost) * 100
label = IF(score >= 80, "hot", "cold")
age_days = DAYS_BETWEEN(created_date, TODAY())
| category | available |
|---|---|
| Operators | + - * / % · == != > >= < <= · && || ! (or AND OR NOT) |
| Functions | IF, CONCAT, ROUND, ABS, MIN, MAX, LEN, UPPER, LOWER, CONTAINS, TODAY, DAYS_BETWEEN, NUMBER, TEXT, BLANKVALUE |
| Null semantics | missing fields and division-by-zero evaluate to null, never errors — half-filled records render fine |
Validation rules
"validationRules": [
{ "type": "min", "value": 0 },
{ "type": "regex", "value": "^\\d{5}$", "message": "zip must be 5 digits" }
]
Types: min, max, minLength, maxLength, regex — each with an optional custom message. Add required and is_unique at the field level.
Field-level security
readRoles / writeRoles (role lists; empty = everyone). Reads strip protected fields from responses; writes are rejected with 403 FIELD_ACCESS_DENIED.
The auto-generated API
After install, the tenant's records live at:
GET /api/crm/custom/{apiName}/records?q=&filterField=&filterValue=&page=&size=
POST /api/crm/custom/{apiName}/records
GET /api/crm/custom/{apiName}/records/{id} # formulas computed, ACLs applied
PATCH /api/crm/custom/{apiName}/records/{id}
DELETE /api/crm/custom/{apiName}/records/{id}
Sandbox installs prefix your object api-names with
sbx_ so a later prod install never collides — write your connector against the apiName the install actually returns.Plan limits
Custom-object count is plan-gated per tenant (Business 3 / Enterprise 10). An install that would exceed the tenant's limit fails atomically and rolls back — nothing half-provisioned is left behind.
