Skip to main content
Each project defines its own data model. It decides which fields a call carries, what each is called and what type it holds, whether it can be filtered, sorted, grouped or searched, and how the fields are laid out on screen. Defining a field takes one request: nothing is deployed and no database schema changes. A call has no fixed data columns. Its name, number, status, duration, cost and every business outcome you track are all custom fields. The platform’s own fields, such as status or duration, are system fields of the same kind (see the fields the platform writes). A field key is unique within its project, so two projects can each have a status field with entirely different options.
Reading definitions needs calls.read or any field or field-group permission. Creating, updating and deleting fields need fields.create, fields.update and fields.delete; changing groups needs field_groups.*. See Authentication.

How fields, calls and values relate

A definition says what a field is. A value row ties one call to one definition and stores the value in the column for the field’s type, so numbers compare as numbers and dates as dates. The API flattens a call’s values into the call record, keyed by field key.

Field types

Choose the type for what the value is. The type decides how the value is stored and validated, and whether comparisons are numeric, chronological or textual. A select or multiselect field declares its options as value and label pairs. The value is what is stored, filtered and compared; the label is only what people see. Write and filter with the value.

The definition

POST /custom-fields creates a definition from these properties.
string
required
What the field belongs to: call for call fields.
string
required
The key the field is read, written and filtered by: lower-case letters, digits and underscores, starting with a letter or underscore, up to 100 characters. The call’s own column names (id, created_at, updated_at and the like) are reserved.
string
required
The name people see. Change the label freely; changing the key breaks every filter, integration and automation that names it.
string
required
One of the types above.
object[]
For select and multiselect: the choices, each {"value": "...", "label": "..."}.
boolean
default:"false"
The field must be present and non-empty when a call is created, and must not be emptied when it is sent on update.
boolean
default:"false"
The list, aggregate and trends endpoints accept filters on this field. Filtering on a field without it answers 422.
boolean
default:"false"
The field can be used in sort.
boolean
default:"false"
The field can be used in group on the calls list and offered for grouping in the dashboard.
boolean
default:"false"
The field is included in the search parameter’s text search. Keep this narrow; every searchable field widens every search.
boolean
default:"true"
Whether the dashboard shows the field. A hidden field is still read and written through the API.
integer
Position of the field in lists of fields and in the extraction schema.
string[]
Extra Laravel validation rules appended to the ones the type supplies, for example ["max:50"].
string
A description shown with the field.
string
Stored with the definition. The API does not fill it into calls created without the field.
boolean
default:"false"
The field takes part in post-call extraction and appears in the extraction schema. Not allowed for transcript and json fields.
string
What to extract, in words an extractor reads. Required while extraction_enabled is true.

Add a field and use it

1

Create the field

A boolean that records whether the person confirmed their appointment, filterable and sortable, and used in extraction.
Response
A select field declares its options the same way:
The new field is live at once: the next request that writes or filters calls already knows it.
2

Set it on a call

Write values by field key with PUT /calls/{call}, or include them when you create the call.
Response
3

Filter calls by it

Every filterable field is a query parameter of GET /calls.
It answers the calls whose value is true. A select field takes a list: callback_window_in=morning,afternoon. The full operator list is in the calls guide.
4

Check what deleting it would cost

GET /custom-fields/{custom_field}/delete-impact counts the records that hold a value for the field, without changing anything.
Response
5

Delete it

DELETE /custom-fields/{custom_field} deletes the definition and every value stored under it.
Response
Deleting a field cannot be undone: every call loses its value for it. Check the delete impact first, and export the values you want to keep.

Validation of call values

Call values are validated against the definitions as they are at the moment of the request. The type supplies the base rule, is_required decides between required and optional, a select or multiselect field accepts only its option values, and any validation_rules are added. An update validates only the fields it carries. A value that fails answers 422 with each field named:
Response
"Morning" is refused because it is the option’s label; the value is "morning".
A key the project does not define is ignored by POST /calls and PUT /calls/{call}: the call is saved without it. Only PATCH /calls/batch refuses it with 422. Check your keys against GET /custom-fields.
Because rules come from the current definitions, adding a required field tightens validation for every caller at once. An integration that creates calls without it starts receiving 422.

Read the data model

GET /custom-fields lists the project’s definitions, ordered by label. Pass entity_type=call (the default).
Response
Read this before writing an integration or an agent that works with calls: it is the authoritative list of keys, types, options and flags for the project.

The extraction schema

A field with extraction_enabled takes part in post-call extraction: reading a finished call’s transcript and filling the field from it. GET /custom-fields/extraction-schema returns those fields as one JSON Schema, ready to use as a strict structured output for a language model.
Response
Every enabled field is a required property keyed by its field key, in sort_order, described by its extraction_prompt, and nullable because a call may not mention it. A select field is an enum of its option values; a multiselect field is an array of them; dates and datetimes carry format. A project with no enabled fields answers an object with no properties. The platform publishes the schema; it does not run the extraction itself. The extractor is yours: an automation or your own service reads the call’s transcript, asks a model for output matching the schema, and writes the result back with PUT /calls/{call}. Because the schema’s keys are field keys and its enums are option values, the model’s output is a valid update body as it stands. Turning extraction on for a transcript or json field, or without a prompt, answers 422.

Groups and layout

Groups arrange fields for display in the dashboard; they change nothing about how a field is stored, validated or filtered. A field belongs to at most one group, and a field in no group works fully. Reordering has its own endpoints so that two people arranging different parts of the layout do not overwrite each other.
Response

Changing a field

PUT /custom-fields/{custom_field} changes any property you send and leaves the rest.
Some changes cost more than they look:
  • Type. Values are stored in a column per type. Changing the type of a field that already holds values leaves those values where the new type does not read them. Treat it as a data migration: create a new field, copy the values, then delete the old one.
  • Key. Renaming field_key breaks every filter, integration and automation that names it. Change field_label instead.
  • Options. Removing an option from a select field leaves calls that already hold that value with a value no longer in the list.
System fields (is_system: true) are the ones the platform depends on. Their field_key, field_type and is_required cannot be changed, their built-in options cannot be removed, and they cannot be deleted; each attempt answers 422, for example "Cannot modify 'field_type' on system field." You can still change their label, flags, help text and add options of your own.

Errors

The same operations are available as MCP tools (fields_list, fields_create, fields_update, fields_impact, fields_delete, fields_extraction_schema, and field_groups_*) and as CLI commands (callva fields list, callva fields impact <id>, callva fields extraction-schema). See MCP and CLI.