This guide explains how to create properties through the API and what happens when multiple objects use a property with the same name.
Properties define the schema for your objects: field types, validation rules, select options, and display metadata. In Caraer, a property is not owned by a single object. The same property definition can be attached to many objects, so you can reuse common fields like email, firstname, or status without duplicating configuration.
Each property has:
- Shared definition — applies everywhere the property is used:
name,label,type,format,rules,options,indexed, and related settings. - Per-object settings — configured separately for each object the property is attached to:
group,hidden,index, and archive state (deletedAt,deletedBy).
When you fetch properties for an object, the API returns the combined view: shared definition plus that object's settings.
All property routes are scoped to an object:
POST /api/v2/objects/{objectUuid}/properties— create (or attach) a propertyPUT /api/v2/objects/{objectUuid}/properties/{propertyUuid}— updateGET /api/v2/objects/{objectUuid}/properties/{propertyUuid}— fetch onePOST /api/v2/objects/{objectUuid}/properties/index— list with paginationPUT /api/v2/objects/{objectUuid}/properties/updateIndices— reorder fieldsDELETE /api/v2/objects/{objectUuid}/properties/{propertyUuid}— archive for this objectPOST /api/v2/objects/{objectUuid}/properties/{propertyUuid}/restore— restore an archived property on this objectDELETE /api/v2/objects/{objectUuid}/properties/{propertyUuid}/permanent— permanently remove an archived property from this object (and delete the property entirely if no other object uses it)GET /api/v2/objects/{objectUuid}/properties/formats— list available formatsGET /api/v2/objects/{objectUuid}/properties/calculation-types— calculation types per property type
Write operations require the tools.objects.schemas.write scope. Delete and restore require tools.objects.schemas.delete.
{objectUuid} accepts either the object UUID or its internal name (for example candidate).
curl -X POST "https://your-company.caraer.com/api/v2/objects/candidate/properties" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "email",
"label": "Email address",
"description": "Primary contact email",
"type": "string",
"format": "email",
"rules": ["required"],
"group": "Contact details",
"hidden": false,
"indexed": true
}'Required fields:
| Field | Notes |
|---|---|
name | Lowercase, letters/numbers/underscores only. Stable internal key. |
label | Human-readable label shown in the UI. |
type | One of string, number, date, single-select, multi-select, file, tag, structure, linked-property, checkbox, range. |
format | Must match the chosen type (for example email or single-line for string). Use GET .../properties/formats for the full list. |
rules | Array of validation rule strings (for example required, unique). |
Common optional fields:
description— max 255 charactersoptions— required for select types; each option needs a uniquenameandlabelgroup— form/view grouping for this objecthidden— hide on forms for this object (defaultfalse)indexed— enable faster filtering on this property (defaultfalse)formatSettings— format-specific configuration (for example linked-property targets)
These fields control how a property is exposed and how clients should treat it. They are part of the shared property definition, so they apply everywhere the property is attached.
| Field | Default | What it does |
|---|---|---|
nonPublic | false | Restricts access for App/API token authentication. Even when a token has record read or write scopes for the object, it cannot read or write this property. Use for internal-only fields that integrations should not touch. |
editable | true | Controls whether the property schema can be changed. When false, the property definition is locked — updates through PUT .../properties/{propertyUuid} are not allowed. This does not affect whether record values can be written. |
immutable | false | Marks the property as platform-managed. Record values for this field cannot be edited through the records API — Caraer sets and maintains them through system logic or relations. Automatically enabled for linked-property fields. |
webpagePublic | false | Allows the property value to be included when a record is returned through public webpage endpoints. Properties without this flag are omitted from public webpage responses. |
embeddable | false | Includes the property value when Caraer builds a semantic search embedding for the record after create or update. Useful on text-like fields you want discoverable through AI-powered search. |
icon | null | Optional icon name (Font Awesome style, for example envelope or user) shown in forms, views, and filters in the Caraer UI. Does not affect record API behavior. |
Note:
editableandimmutableapply at different levels.editablelocks the property schema (type, label, rules, and so on).immutablelocks record values for that field. A property can be schema-editable but still have immutable record values, or vice versa.
Example with flags set:
curl -X POST "https://your-company.caraer.com/api/v2/objects/candidate/properties" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "internal_notes",
"label": "Internal notes",
"type": "string",
"format": "multi-line",
"rules": [],
"nonPublic": true,
"editable": true,
"webpagePublic": false,
"embeddable": true,
"icon": "note-sticky"
}'What happens on create:
- Caraer looks up an existing property by name.
- If one exists, the same property UUID is reused. If not, a new property is created.
- The property is attached to the object (or restored if it was previously archived on that object).
- Per-object settings (
group,hidden,index) are saved for this object. - If
indexedistrue, the property is indexed for faster queries on this object. - The property may be added to the object's default view (when it has fewer than 10 visible columns).
Property names are globally unique within your company. There is one property definition per name, not one per object.
Create the same property name on a second object:
curl -X POST "https://your-company.caraer.com/api/v2/objects/vacancy/properties" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "email",
"label": "Email address",
"type": "string",
"format": "email",
"rules": [],
"group": "Recruiter contact"
}'Because email already exists, Caraer:
- Reuses the same property UUID
- Attaches it to
vacancy - Saves object-specific
group,hidden, andindexforvacancy
Both objects now expose an email field, backed by the same property definition.
| Concern | Shared across objects | Per object |
|---|---|---|
name | Yes — one name globally | — |
type, format | Yes | — |
rules, options | Yes | — |
label, description | Yes | — |
indexed | Yes | — |
nonPublic, editable, immutable, webpagePublic, embeddable, icon | Yes | — |
group, hidden, index | — | Yes |
| Archive (soft delete) | — | Yes (per object) |
Practical implication: updating options on a shared select property affects every object that uses it. Changing group or hidden only affects the object you update.
If a property name already exists, the new create request must use the same type and format. Otherwise validation fails with an error like:
A property with the same name already exists — change the type to … and format to …
You cannot create email as a string/email on one object and as a single-select on another.
Reserved names (name, externalUuid, createdAt, updatedAt, uuid) cannot be created manually.
Updates go through the property UUID:
curl -X PUT "https://your-company.caraer.com/api/v2/objects/candidate/properties/PROPERTY_UUID" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "email",
"label": "Work email",
"type": "string",
"format": "email",
"rules": ["required", "unique"]
}'Immutable after creation:
nametype
format is validated on create; treat it as fixed once records exist.
When you change shared fields (label, rules, options), all objects using that property see the change. Send object-specific fields like group or hidden in the same request to update only that object's settings.
Archiving removes the property from one object's schema only:
curl -X DELETE "https://your-company.caraer.com/api/v2/objects/candidate/properties/PROPERTY_UUID" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"- The property definition remains if other objects still use it.
- Existing values on
candidaterecords are not automatically cleared; the field is removed from the schema for that object. - Restore with
POST .../properties/{propertyUuid}/restore.
Permanent delete removes the archived property from this object. If no other object uses the property, it is deleted entirely and values are removed from records on all affected objects.
System properties (name, label, createdAt, updatedAt, deletedAt, uuid) cannot be deleted.
| Type | Example formats |
|---|---|
string | single-line, multi-line, email, phone, url |
number | number, currency |
date | date |
single-select | single-select |
multi-select | multi-select |
checkbox | single-checkbox |
file | file |
tag | tag |
structure | structure |
linked-property | linked-property (read-only; value comes from a related record) |
range | number-range, currency-range |
Use GET /api/v2/objects/{objectUuid}/properties/formats for the authoritative list in your environment.
- Reuse intentionally. Shared names mean shared validation, options, and labels. Use the same name when fields truly represent the same concept (
email,firstname). Use distinct names when semantics differ (status_candidatevsstatus_vacancy). - Plan names early.
nameandtypeare immutable; renaming effectively means migrating data to a new property. - Index for query paths. Set
indexed: trueonly on properties you filter or sort on frequently. - Scope deletes carefully. Archiving a shared property on one object does not affect others; permanently deleting it while other objects still use it is blocked.
- Align integrations on
name. Record APIs address values by property name, not UUID. Shared names behave the same across objects, but values live on each record independently.
- Creating the same name with a different type/format on another object.
- Expecting different select options per object while reusing one property name.
- Assuming archive on one object removes the property everywhere.
- Trying to update a property schema when
editableisfalse. - Sending values for
immutableorlinked-propertyfields on record create/update. - Setting
nonPublic: falseand expecting App/API tokens to read sensitive fields without explicit property scopes. - Removing select options that are still used in existing records.