> ## Documentation Index
> Fetch the complete documentation index at: https://docs.voxworks.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom Variables Overview

> What custom variables are, how they differ from contact fields, and a tour of the Custom Variables workspace — type tabs, saved views, add forms, the detail pane, field propagation, hierarchy and deletion.

## What are Custom Variables?

Custom variables are structured data records that you define for your team. Where a contact record carries a fixed set of fields — name, phone, email, company, timezone, address — a custom variable carries whatever structure your business needs: a property listing, a policy, a booking, a survey question. You decide the shape by creating a **custom variable type**, then create as many records of that type as you need.

|                              | Contact fields                                 | Custom variables                              |
| ---------------------------- | ---------------------------------------------- | --------------------------------------------- |
| **Shape**                    | Fixed set of fields on every contact           | Any structure you define, per type            |
| **Where they live**          | The Contacts page                              | The Custom Variables page                     |
| **Relationship to contacts** | One set of fields per contact                  | Records can be linked to one or many contacts |
| **In scripts**               | `{{contact.first_name}}` (string, e.g. `Jane`) | `{{custom.<type name>.<field>}}`              |

Every field of a custom variable is available to your call scripts through the `custom` namespace. If you create a type called Property Listing with an `address` field, your script can speak or reference `{{custom.property_listing.address}}` (string, e.g. `12 Wattle St, Brisbane QLD 4000`). In any script field that supports variables, type `/` to open the variable picker — your installed custom variable types appear under the **custom** branch with each field's data type shown.

When a custom variable is linked to a contact, calls with that contact read the linked record's values; how linking works — and what the agent reads when nothing is linked — is covered on [Linking Custom Variables to Contacts](/custom-variables/linking-contacts).

You'll find the workspace in the sidebar under **Voice Agent Settings** > **Custom Variables**.

***

## The Custom Variables workspace

The page follows the same table layout as Calls, Contacts and Scripts: a tab row, search, filter and sort controls, CSV download, refresh, and action buttons on the right.

* **Type tabs** — the first tab is **All**, showing every custom variable regardless of type. Each installed custom variable type gets its own tab, named after the type. Switching to a type tab scopes the table to that type and unlocks its data columns.
* **Table columns** — every view shows a selection checkbox, **Name**, **Type** and **Created**, plus a row menu with a **Delete** action. On a type tab you can add a column for any field of that type.
* **Filters and sorting** — on the **All** tab you can filter by Name, Type, Created and Modified. On a type tab, the Type filter is replaced by filters for each visible data column, matched to the field's type: text, number, date range, Yes/No, or a dropdown of the field's allowed values.
* **Search** — searches custom variables by name.
* **Action buttons** — **Custom Variable Types** opens the type manager (see [Custom Variable Types & Schema Validation](/custom-variables/types)); **Add Custom Variable** opens the new-record form.

### Columns and saved views

On a type tab, the **Columns** button opens a picker listing every field of the type. Until a view has been saved, every field of the type shows as a column. Nested fields appear as an expandable tree, and **All** / **None** buttons toggle everything at once. Choose the columns you want, then select **Save View** — the selection is saved on the type itself, so the same columns load for your whole team whenever that tab is opened. The button reads **View Saved** when the current selection matches what's stored. The saved selection also drives which fields the detail pane's Data section shows for records of that type.

The **All** tab has no schema to draw on, so its column picker only offers the raw field names found in your data, and views can't be saved there.

***

## Adding a custom variable

Select **Add Custom Variable** to open the **New Custom Variable** form in the detail pane on the right.

| Field | Required | Description                                                                                                                                                                         |
| ----- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Name  | Yes      | The record's display name, shown in the table's Name column.                                                                                                                        |
| Type  | No       | Pick a custom variable type from a searchable list. Each entry shows its field count, and selecting one switches the Data section to a typed form with a **Schema enforced** badge. |

The **Data** card adapts to your Type selection:

* **With a type selected** — one input per field of the type, rendered to match the field's data type: text (with email and URL variants), a dropdown when the field has a fixed list of allowed values, a number input, a Yes/No checkbox, or a JSON box for list and object fields. Required fields are marked with `*` and an alert reminds you that "Fields marked with \* are required".
* **Without a type** — free-form name/value rows. Use **Add Field** to add more rows; values that parse as JSON are stored as numbers, lists or objects, anything else as text.
* **Advanced** — a switch in the card header swaps either form for a raw JSON editor, keeping whatever you'd already entered. Invalid JSON is flagged and can't be saved.

Whether a save with missing or mismatched values is accepted, warned about or blocked depends on the type's validation setting — see [Custom Variable Types & Schema Validation](/custom-variables/types).

***

## The detail pane

Click any row to open **Custom Variable Details** — the record's name, its type badge, and two tabs.

### Data tab

The **Data** section lists the record's fields with their current values — the same field selection as the type's saved view, or every field of the type when no view has been saved. Values are edited inline:

* Click a text or number value to edit it in place; click away (or press Ctrl+Enter) to save, or press Escape to cancel.
* Yes/No values toggle with a single click.
* Fields with a fixed list of allowed values open a dropdown.
* List and object fields open a JSON editor and validate as you type.

Hover over any field label and a copy button appears that copies the field's script token — for example `{{custom.property_listing.address}}` (string, e.g. `12 Wattle St, Brisbane QLD 4000`) — ready to paste into a call script. A tooltip previews the token before you copy it.

The **Metadata** section below shows the record's Name, Type, its Parent (when one is set — see Hierarchy below), Created and Modified timestamps, and the record's unique ID.

### Raw JSON tab

The **Raw JSON** tab shows the record's full data payload. Use the copy button to copy it, or the pencil to edit the whole payload as JSON and **Save** — handy for pasting in a complete record or fixing structure that the field editors can't reach.

***

## Adding fields to a type

Types aren't frozen once created. Open **Custom Variable Types**, edit a type, and use **Add Field** in its schema editor to add a new field — or **Import JSON** to generate fields from a sample record.

Because the table columns, detail pane and add form are all driven by the type's field list, a newly added field is available immediately on **every** custom variable of that type: it appears in the column picker as a table column and filter, in the detail pane, and in the new-record form. If you've already saved a view for the type, tick the new field in the **Columns** picker and save the view again to show it — the table and detail pane follow the saved selection. Existing records keep their data untouched — the new field simply reads as empty (shown as —) until a value is entered. The new field is also immediately addressable from scripts, e.g. adding `inspection_date` to a Property Listing type makes `{{custom.property_listing.inspection_date}}` (string, e.g. `2026-07-21`) available; on records where it hasn't been filled in yet the field has no value, and if your script speaks the token without a fallback the caller hears the raw `{{...}}` text rather than silence — guard it with a fallback before speaking it.

The full type builder — field types, formats, allowed values, validation modes and the installable type catalogue — is documented on [Custom Variable Types & Schema Validation](/custom-variables/types).

***

## Hierarchy

A custom variable can have a **parent** — another custom variable it belongs to, such as line items under an order, or rooms under a property. When a record has a parent, the detail pane's Metadata section shows a **Parent** row with the parent's name.

There is currently no control in the workspace for setting a parent; parents are assigned when records are created or updated through the [Voxworks API](/api-reference/overview), which accepts a parent reference on both create and upsert.

***

## Deleting custom variables

* **One record** — open the row menu (⋯) and choose **Delete**. The **Delete Custom Variable** dialog warns that the action cannot be undone.
* **Several records** — tick their checkboxes, then use the **Delete selected** bin icon that appears in the toolbar. The **Delete Selected Custom Variables** dialog confirms the count before deleting.

Deletes made in the workspace are permanent: the records and their links to contacts are removed. Deletes made through the API behave differently — the record is hidden from the workspace rather than destroyed (a soft delete).

Deleting a **type** (from the Custom Variable Types dialog) removes the type and its tab from the workspace, but does not delete the records of that type — they remain visible on the **All** tab.

***

## Next Steps

* [Custom Variable Types & Schema Validation](/custom-variables/types) — build type schemas, choose field types and formats, and set Off/Warn/Strict validation.
* [Linking Custom Variables to Contacts](/custom-variables/linking-contacts) — attach records to contacts so calls read the right data.
* [Importing Custom Variables from CSV](/custom-variables/csv-import) — create typed records in bulk from a spreadsheet.
* [Variables](/flows/variables) — the full variable reference, including the `custom` namespace and the `/` picker.
