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

# Custom Fields API

> Define typed metadata fields on contacts and set values per contact. Use them in segments, flows, and personalization.

# Custom Fields API

Extend the contact schema with typed fields specific to your business — `lifetime_value`, `plan_tier`, `last_login_at`, `account_manager`, etc. Custom fields are referenced from segment rules, flow conditions, message personalization, and the inbox UI.

**Base path:** `/api/v1/custom-fields`

**Authentication:** API key (`X-API-Key`) or session JWT.

## Definitions

| Method   | Path                                      | Purpose                                                                               |
| -------- | ----------------------------------------- | ------------------------------------------------------------------------------------- |
| `GET`    | `/api/v1/custom-fields/`                  | List field definitions                                                                |
| `POST`   | `/api/v1/custom-fields/`                  | Create a definition                                                                   |
| `GET`    | `/api/v1/custom-fields/{id}`              | Get a definition                                                                      |
| `GET`    | `/api/v1/custom-fields/{id}/dependencies` | Scan which segments, campaigns, flows, and contacts reference the field               |
| `GET`    | `/api/v1/custom-fields/{id}/explorer`     | Inspect a field: definition, usage counts, and its last 10 PII-redacted sample values |
| `PATCH`  | `/api/v1/custom-fields/{id}`              | Update name / description / options / validators                                      |
| `DELETE` | `/api/v1/custom-fields/{id}`              | Delete a definition and strip its values from every contact                           |
| `POST`   | `/api/v1/custom-fields/reorder`           | Reorder definitions for the dashboard UI                                              |

A field's `key` and `type` are immutable: they are fixed at creation and cannot be changed by `PATCH` (changing either would orphan the values already stored on contacts). To switch a field's type, delete it and create a new one.

### Deleting a field that is in use

`DELETE` is guarded so you don't silently break the segments, campaigns, and flows that reference a field.

If the field is still referenced by any segment, campaign, or flow — or has values stored on any contact — the request returns `409 Conflict` with code `CUSTOM_FIELD_IN_USE`. The response `details` list every dependent so you can review or clean up first:

```json theme={null}
{
  "error": {
    "code": "CUSTOM_FIELD_IN_USE",
    "message": "Field \"ltv_usd\" is referenced by 2 segment(s), 1 campaign(s), 0 flow(s) and stored on 431 contact(s). Pass force=true to delete and break dependents.",
    "details": {
      "field_key": "ltv_usd",
      "dependencies": {
        "segments": [ /* ... */ ],
        "campaigns": [ /* ... */ ],
        "flows": [ /* ... */ ],
        "contacts_with_data": 431
      }
    }
  }
}
```

To delete anyway, pass `?force=true`:

```bash theme={null}
curl -X DELETE "https://api.orbit.devotel.io/api/v1/custom-fields/cf_abc123?force=true" \
  -H "X-API-Key: dv_live_sk_your_key_here"
```

With `force=true` the delete proceeds: the field's values are stripped from every contact, and each dependent is flagged so you can find it afterward. Dependent segments are set to `status: "broken"`. Dependent campaigns keep running — an in-flight send is never interrupted — but are flagged with a `broken_custom_fields` marker in their metadata. Dependent flows are set to `status: "broken"` so the automation runner skips them. The reference to the deleted field is **not** stripped from the campaign or flow filter: the filter JSON is left intact and only flagged, so the stale field-leaf remains until you edit or rebuild the filter. A field that is not referenced anywhere deletes without needing `force`.

## Values

Per-contact values are written via a single endpoint and read inline as part of [the contact resource](/api-reference/endpoints/contacts).

| Method | Path                           | Purpose                               |
| ------ | ------------------------------ | ------------------------------------- |
| `PUT`  | `/api/v1/custom-fields/values` | Set a custom-field value on a contact |

## Example — define a lifetime-value field, then set it

```bash theme={null}
# 1. Define
curl -X POST https://api.orbit.devotel.io/api/v1/custom-fields/ \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "key": "ltv_usd", "type": "number", "name": "Lifetime value (USD)" }'

# 2. Set on a contact
curl -X PUT https://api.orbit.devotel.io/api/v1/custom-fields/values \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "contact_id": "cnt_abc123", "key": "ltv_usd", "value": 482.50 }'
```

## See also

* [Contacts API](/api-reference/endpoints/contacts) — read custom-field values inline
