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

# API Configuration

> Define Custom Fields and mappings programmatically for onboarding automation, environment replication, or syncing with internal admin tooling.

The Custom Fields API exposes the same capabilities as the dashboard.
For the concepts see the [Custom Fields overview](/guides/extending/custom-fields).
For the visual route see [Dashboard Configuration](/guides/extending/custom-fields/dashboard).

The page walks the flow end to end with example requests and responses, using a running example: extending the `employee` model with a `guardian_mobile` field, populated from a Workday connector.

## Authentication

All Custom Fields endpoints are scoped to your organization and require a Bearer token:

```http theme={null}
Authorization: Bearer <BINDBEE_API_KEY>
Content-Type: application/json
```

## Step 1: Discover models and integrations

Use the lookup endpoints, [List Models](/api-reference/custom-fields/list-models) and [List Integrations](/api-reference/custom-fields/list-integrations), to fetch the slugs you'll need. These are filtered to what your organization actually has access to.

```bash theme={null}
# Models you can extend
GET /api/v1/lookup/models?category=HRIS

# Integrations enabled for your org
GET /api/v1/lookup/integrations?category=HRIS
```

```json Example responses theme={null}
// /api/v1/lookup/models
{
  "models": [
    { "slug": "employee", "display_name": "Employee", "category": "HRIS" }
  ]
}

// /api/v1/lookup/integrations
{
  "integrations": [
    { "slug": "workday", "display_name": "Workday", "categories": ["HRIS"] }
  ]
}
```

<Note>
  Connector tokens (used for connector level mappings) are **not** returned by
  any lookup endpoint. They are issued when a connector is created and surfaced
  through the connector flow.
</Note>

## Step 2: Inspect the raw upstream payload

Before you write a JMESPath, look at the shape of the upstream JSON. The [Get Raw Data](/api-reference/custom-fields/get-raw-data) endpoint returns either the connector's latest synced row or a canned sample for the integration if no connector is provided (or if it has not synced yet).

```bash theme={null}
# Using a real connector
GET /api/v1/custom-fields/raw-data?category=HRIS&model=employee&connector_token=<CONNECTOR_TOKEN>

# Or just the integration sample
GET /api/v1/custom-fields/raw-data?category=HRIS&model=employee&integration_slug=workday
```

```json Example response theme={null}
{
  "data": {
    "employee": {
      "id": "emp_123",
      "first_name": "Ada",
      "guardian_mobile": "+1-555-123-4567"
    }
  }
}
```

In this example, `data.employee.guardian_mobile` is the JMESPath you'll want to use.

## Step 3: Validate the JMESPath (optional but recommended)

The [Preview](/api-reference/custom-fields/preview) endpoint evaluates a JMESPath against real connector data **without** persisting anything. Use this to catch typos and confirm the resolved value type before you save the mapping.

```bash theme={null}
POST /api/v1/custom-fields/preview
```

```json Request body theme={null}
{
  "connector_token": "<CONNECTOR_TOKEN>",
  "category": "HRIS",
  "model": "employee",
  "json_path": "data.employee.guardian_mobile"
}
```

```json Response theme={null}
{
  "connector_token": "<CONNECTOR_TOKEN>",
  "json_path": "data.employee.guardian_mobile",
  "resolved_value": "+1-555-123-4567",
  "resolved_value_type": "string",
  "raw_data_source": "connector_sync"
}
```

`raw_data_source` will be one of:

* `"connector_sync"` — evaluated against the connector's latest synced row.
* `"integration_sample"` — connector hasn't synced yet, fell back to the canned sample.
* `"inline"` — the request supplied an inline `raw_data` payload to evaluate against.

`resolved_value_type` will be one of: `string`, `number`, `boolean`, `object`, `array`, `null`.

## Step 4: Create the custom field

Once you're confident in your JMESPath, register the field itself with [Create Custom Field](/api-reference/custom-fields/create-custom-field). The field is just a typed slot on the `(category, model)` — it carries no mapping yet.

```bash theme={null}
POST /api/v1/custom-fields
```

```json Request body theme={null}
{
  "name": "guardian_mobile",
  "description": "Employee's guardian mobile number",
  "category": "HRIS",
  "model": "employee"
}
```

```json Response theme={null}
{
  "id": "018e586b-7d0b-7bc9-be65-a8fdbc82d734",
  "status": "SUCCESS"
}
```

`name` must be **snake\_case**, between 2 and 128 characters, and unique within the `(category, model)`. Fields created here appear with `source: "API"` when listed.

## Step 5: Create a mapping

A mapping pairs the custom field with a JMESPath. Send it to [Create Mapping](/api-reference/custom-fields/create-mapping). What you send decides its type: `integration_slug` for an integration level mapping, `connector_token` for a connector level one. See [Type of mapping](/guides/extending/custom-fields#type-of-mapping).

<Tabs>
  <Tab title="Integration level">
    Applies to every Workday connector in your organization.

    ```bash theme={null}
    POST /api/v1/custom-fields/mapping
    ```

    ```json Request body theme={null}
    {
      "custom_field_id": "018e586b-7d0b-7bc9-be65-a8fdbc82d734",
      "integration_slug": "workday",
      "json_path": "data.employee.guardian_mobile"
    }
    ```
  </Tab>

  <Tab title="Connector level">
    Applies to one specific connector and overrides any integration level
    mapping for the same field on that connector.

    ```bash theme={null}
    POST /api/v1/custom-fields/mapping
    ```

    ```json Request body theme={null}
    {
      "custom_field_id": "018e586b-7d0b-7bc9-be65-a8fdbc82d734",
      "connector_token": "<CONNECTOR_TOKEN>",
      "json_path": "data.employee.guardian_mobile"
    }
    ```
  </Tab>
</Tabs>

```json Response theme={null}
{
  "id": "018e586b-7d0b-7bc9-be65-a8fdbc82d734",
  "status": "SUCCESS"
}
```

<Warning>
  Provide **exactly one** of `integration_slug` or `connector_token`. To change
  the type of an existing mapping, delete it and create a new one — only
  `json_path` is mutable via update.
</Warning>

## Step 6: Verify the effective configuration

The [Get Configuration](/api-reference/custom-fields/get-configuration) endpoint returns every custom field for a given `(connector, category, model)` together with the **effective** mapping in use. Connector level mappings override integration level ones, and unmapped fields are included with `json_path: null` so you can see what's still left to configure.

```bash theme={null}
GET /api/v1/custom-fields/configuration?connector_token=<CONNECTOR_TOKEN>&category=HRIS&model=employee
```

```json Response theme={null}
{
  "connector_token": "<CONNECTOR_TOKEN>",
  "integration_slug": "workday",
  "category": "HRIS",
  "model": "employee",
  "fields": [
    {
      "custom_field_id": "018e586b-7d0b-7bc9-be65-a8fdbc82d734",
      "name": "guardian_mobile",
      "description": "Employee's guardian mobile number",
      "category": "HRIS",
      "model": "employee",
      "json_path": "data.employee.guardian_mobile",
      "source": "organization",
      "mapping_id": "018e586b-7d0b-7bc9-be65-a8fdbc82d734"
    },
    {
      "custom_field_id": "...",
      "name": "favorite_color",
      "description": null,
      "category": "HRIS",
      "model": "employee",
      "json_path": null,
      "source": null,
      "mapping_id": null
    }
  ]
}
```

Each entry's `source` indicates which mapping is winning:

* `"connector"` — a connector level mapping is in effect.
* `"organization"` — no connector override; the integration level mapping is being inherited. The response still uses the older `organization` wording for this mapping type.
* `null` — no mapping is configured for this field on this connector.

## Updating and deleting

| Action                                                                 | Endpoint                                                         | Notes                                                     |
| ---------------------------------------------------------------------- | ---------------------------------------------------------------- | --------------------------------------------------------- |
| [List custom fields](/api-reference/custom-fields/list-custom-fields)  | `GET /api/v1/custom-fields`                                      | Supports `category`, `model`, and `source` filters.       |
| [Get one with mappings](/api-reference/custom-fields/get-custom-field) | `GET /api/v1/custom-fields/{custom_field_id}`                    | Returns the field plus all its mappings.                  |
| [Delete a field](/api-reference/custom-fields/delete-custom-field)     | `DELETE /api/v1/custom-fields/{custom_field_id}`                 | Cascades — all mappings for the field are removed.        |
| [Update a mapping](/api-reference/custom-fields/update-mapping)        | `PATCH /api/v1/custom-fields/mapping/{custom_field_mapping_id}`  | Only `json_path` is mutable. Re-create to change type.    |
| [Delete a mapping](/api-reference/custom-fields/delete-mapping)        | `DELETE /api/v1/custom-fields/mapping/{custom_field_mapping_id}` | Removes a single mapping; the field itself is unaffected. |

## Next steps

<CardGroup cols={2}>
  <Card title="Retrieve custom fields" icon="download" href="/guides/extending/custom-fields#retrieve-custom-fields">
    Add `include_custom_fields=true` to your unified requests.
  </Card>

  <Card title="Best practices" icon="lightbulb" href="/guides/extending/custom-fields#best-practices">
    Naming, scoping, and automation guidance.
  </Card>
</CardGroup>
