Skip to main content
POST

Authorizations

Authorization
string
header
required

Your secret API key as a Bearer token: Authorization: Bearer vxn_sk_.... Keys are created and scoped in the dashboard - see Authentication.

Headers

Idempotency-Key
string
required

UUIDv4 recommended. Replays cached 24h.

Body

application/json

Define a reusable custom field. Non-applicable config is normalized automatically (options with text → empty array; date_granularity with number → reset to date).

label
required

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.

Uniqueness is among active definitions. A label must be unique among the organization's active definitions (409 on conflict). Deleting a definition frees its label for reuse.

Required string length: 1 - 50
field_type
enum<string>
required

Field type - see the type table on the Custom Field object. Immutable while in use.

Available options:
text,
textarea,
number,
currency,
date,
boolean,
select,
multiselect
Example:

"select"

key
string

Org-unique machine identifier (optional - derived from the label when omitted). Immutable once the field is in use.

Pattern: ^[a-z][a-z0-9_]{1,49}$
Example:

"department"

description
string

Optional dashboard helper text.

Maximum string length: 500
position
integer

Dashboard ordering hint.

options
object[]

Required non-empty for select/multiselect. Ignored (forced empty) otherwise.

date_granularity
enum<string>

Date type only. Default date.

Available options:
year,
monthYear,
date
number_format
enum<string>

number fields only. Default decimal.

Available options:
integer,
decimal

Response

Created

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.

id
string
required

Opaque, stable, immutable. cf_ prefix.

Pattern: ^cf_[A-Za-z0-9]+$
Example:

"cf_01HW9R9Z4EF7N8MTX1RVCFLD01"

object
string
required

Always "custom_field".

Allowed value: "custom_field"
key
string
required

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.

Pattern: ^[a-z][a-z0-9_]{1,49}$
Example:

"department"

label
required

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.

Required string length: 1 - 200
field_type
enum<string>
required

What 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).

Available options:
text,
textarea,
number,
currency,
date,
boolean,
select,
multiselect
Example:

"select"

created_at
integer
required

Unix seconds.

Example:

1750000000

description
string | null

Internal helper text for the dashboard.

Maximum string length: 500
Example:

"Clinic department the patient is assigned to."

position
integer

DEFAULT form position when added to a card; each card's form_builder ordering overrides.

Example:

2

options
object[]

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.

Example:
date_granularity
enum<string>

DATE type only - controls the stored format: date → YYYY-MM-DD, monthYear → YYYY-MM, year → YYYY. Forced to date for non-date types.

Available options:
year,
monthYear,
date
Example:

"date"

usage_count
integer

Read-only. Number of cards referencing this field. Renames + type changes + deletes are blocked while > 0.

Example:

3

cards_using
string[]

Read-only. The referencing card ids.

Example:
updated_at
integer

Unix seconds.

Example:

1750000000

number_format
enum<string> | null

number fields only: integer rejects fractional input; decimal (default) allows it. Null on other types.

Available options:
integer,
decimal,
null