Update a custom field
Lifecycle-gated edit. Scope: custom_fields:write. What’s allowed depends on whether the field is in use (usage_count > 0):
| Change | Field unused | Field in use |
|---|---|---|
| label, description, position | ✅ | ✅ |
| ADD options | ✅ | ✅ |
| REMOVE option values | ✅ | ❌ 409 custom_field_in_use |
Rename key | ✅ | ❌ (would diverge from form_builder.fields[].id on referencing cards) |
Change field_type | ✅ | ❌ (stored values would violate the new type) |
To make a blocked change: remove the field from all referencing cards first, or create a new field and migrate.
Authorizations
Your secret API key as a Bearer token: Authorization: Bearer vxn_sk_.... Keys are created and scoped in the dashboard - see Authentication.
Headers
Recommended on PATCH and DELETE for safe retries.
Path Parameters
Custom field identifier (cf_ prefix).
^cf_[A-Za-z0-9]+$Body
Lifecycle-gated PATCH. While the field is IN USE (usage_count > 0): key renames, field_type changes, and option-value removals are BLOCKED (409 custom_field_in_use). Always editable: label, description, position, required, and ADDING options.
Customer-facing label - shown on the signup form, referenced on wallet passes, and used in the dashboard. Plain string or per-language object (the platform localization pattern, same as Card.name). This is the DEFAULT - each card's form_builder can override the label per card.
1 - 50Always editable.
500Always editable.
Adding options is always allowed; removing a value that customers already stored is blocked while in use.
Rename - BLOCKED while usage_count > 0.
^[a-z][a-z0-9_]{1,49}$Field type - see the type table on the Custom Field object. Immutable while in use.
text, textarea, number, currency, date, boolean, select, multiselect "select"
Response
Updated custom field (full object).
A reusable custom field DEFINITION - the single vocabulary used across the whole platform: the signup form (via each card's form_builder), the customer record (Customer.custom.<key>), wallet pass slots ({{custom.<key>}} in Card.pass_fields), and notification templates. Define once, reference everywhere.
The definition owns IDENTITY (key, type, options, granularity) and DEFAULTS (label translations, required, position); each card's form owns USAGE (which fields, per-card required/order/label overrides). Limits: 50 definitions per organization (409 custom_field_limit_reached), 20 fields per card form.
Opaque, stable, immutable. cf_ prefix.
^cf_[A-Za-z0-9]+$"cf_01HW9R9Z4EF7N8MTX1RVCFLD01"
Always "custom_field".
"custom_field"Stable machine identifier, unique within the organization (2-50 chars, lowercase snake). Used in {{custom.<key>}} templates and Customer custom.<key> payloads. Renames are blocked while the field is in use (usage_count > 0) to prevent keys diverging across cards.
^[a-z][a-z0-9_]{1,49}$"department"
Customer-facing label - shown on the signup form, referenced on wallet passes, and used in the dashboard. Plain string or per-language object (the platform localization pattern, same as Card.name). This is the DEFAULT - each card's form_builder can override the label per card.
1 - 200What kind of data the field holds - drives form input, validation, and typed pass/notification rendering:
Immutable while the field is used by any card (409 custom_field_in_use).
text, textarea, number, currency, date, boolean, select, multiselect "select"
Unix seconds.
1750000000
Internal helper text for the dashboard.
500"Clinic department the patient is assigned to."
DEFAULT form position when added to a card; each card's form_builder ordering overrides.
2
Choices for select / multiselect (required for those types). Each option is {value, label} - labels are always editable (display only); values are immutable once any customer has stored them and removing a used value is blocked (409 custom_field_in_use). Adding options is always allowed.
DATE type only - controls the stored format: date → YYYY-MM-DD, monthYear → YYYY-MM, year → YYYY. Forced to date for non-date types.
year, monthYear, date "date"
Read-only. Number of cards referencing this field. Renames + type changes + deletes are blocked while > 0.
3
Read-only. The referencing card ids.
Unix seconds.
1750000000
number fields only: integer rejects fractional input; decimal (default) allows it. Null on other types.
integer, decimal, null