> For the complete documentation index, see [llms.txt](https://teamleader-sdk.mcore-services.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://teamleader-sdk.mcore-services.dev/api-reference/general/custom-fields.md).

# Custom Fields

Manage custom field definitions in Teamleader Focus.

```php
Teamleader::customFields()
```

|                          |                                                                       |
| ------------------------ | --------------------------------------------------------------------- |
| Class                    | `McoreServices\TeamleaderSDK\Resources\General\CustomFields`          |
| Create / update / delete | ✓ / — / —                                                             |
| Pagination               | `page_size` / `page_number`; no totals — a short page is the last one |

## Endpoints

* `customFieldDefinitions.create`
* `customFieldDefinitions.info`
* `customFieldDefinitions.list`

## Filters

Passed as the first argument to `list()`. Any other key throws.

| Filter    | Description                                                                                            |
| --------- | ------------------------------------------------------------------------------------------------------ |
| `context` | Filter by context (contact, company, deal, project, milestone, product, invoice, subscription, ticket) |
| `ids`     | Array of custom field UUIDs to filter by                                                               |

## Sorting

Pass `sort` (and optionally `sort_order`) in the options. Any other field throws.

| Field     | Description         |
| --------- | ------------------- |
| `context` | Sort by context     |
| `label`   | Sort by field label |

## Accepted values

Public constants on the class. Body fields and enum values outside these lists throw before the request is sent.

| Constant        | Values                                                  |
| --------------- | ------------------------------------------------------- |
| `CREATE_FIELDS` | `label`, `type`, `context`, `required`, `configuration` |

## Methods

### `list()`

```php
list(array $filters = [], array $options = []): array
```

List custom fields with optional filtering, sorting and pagination.

The Teamleader API defaults to a page size of 20. Pass page\_size and page\_number via $options, or use all() to page automatically.

Deal definitions come back from the API with `context: sale`; this method normalises that to `deal` — see $contextResponseAliases.

* `$filters` — Filters to apply (ids, context)
* `$options` — page\_size, page\_number, sort, sort\_order

**Throws** `InvalidArgumentException` When a filter key or sort field is not supported

### `all()`

```php
all(array $filters = [], int $pageSize = 100): array
```

Get every custom field definition, paging until the list is exhausted.

The API returns no total count, so the end of the list is inferred from a page shorter than the requested page size. A full final page therefore costs one extra empty request.

Makes multiple API calls. The returned array carries `data` and `total_count` but no `headers`, since there is no single response to take them from.

* `$filters` — Filters to apply to every page
* `$pageSize` — Records per request

### `info()`

```php
info($id, $includes = null): array
```

Get custom field information

Deal definitions come back from the API with `context: sale`; this method normalises that to `deal` — see $contextResponseAliases.

* `$id` — Custom field UUID
* `$includes` — Not supported by this endpoint

**Throws** `InvalidArgumentException` When includes are requested

### `create()`

```php
create(array $data): array
```

Create a new custom field definition. Requires the 'settings' OAuth scope.

* `$data` — Custom field data

### `forContext()`

```php
forContext(string $context, array $options = []): array
```

Get custom fields for a specific context

* `$context` — The context to filter by
* `$options` — Pagination and sorting options

**Throws** `InvalidArgumentException` When the context is not one the API accepts

### `forContacts()`

```php
forContacts(array $options = []): array
```

Get contact custom fields

### `forCompanies()`

```php
forCompanies(array $options = []): array
```

Get company custom fields

### `forDeals()`

```php
forDeals(array $options = []): array
```

Get deal custom fields

The API returns these with `context: sale`; the SDK normalises that to `deal` so the value you filter by and the value you read back match.

### `forSales()`

```php
forSales(array $options = []): array
```

Get sale custom fields — alias for forDeals()

Kept for callers who think in the API's response vocabulary. `sale` is what the API returns; `deal` is what it accepts, and what the SDK returns after normalisation.

### `forSubscriptions()`

```php
forSubscriptions(array $options = []): array
```

Get subscription custom fields

### `forProjects()`

```php
forProjects(array $options = []): array
```

Get project custom fields

### `forInvoices()`

```php
forInvoices(array $options = []): array
```

Get invoice custom fields

### `forProducts()`

```php
forProducts(array $options = []): array
```

Get product custom fields

### `forMilestones()`

```php
forMilestones(array $options = []): array
```

Get milestone custom fields

### `forTickets()`

```php
forTickets(array $options = []): array
```

Get ticket custom fields

### `byType()`

```php
byType(string $type): array
```

Get custom fields of a specific type

The API has no `type` filter, so this pages through every definition and filters client-side. It therefore makes multiple API calls and returns `data` and `total_count` without `headers`.

* `$type` — The field type

**Throws** `InvalidArgumentException` When the type is not one the API defines

### `byIds()`

```php
byIds(array $ids): array
```

Get custom fields by specific IDs

* `$ids` — Array of custom field UUIDs

### `getAvailableContexts()`

```php
getAvailableContexts(): array
```

Get available contexts for custom fields

### `getAvailableTypes()`

```php
getAvailableTypes(): array
```

Get available field types

### `typeHasOptions()`

```php
typeHasOptions(string $type): bool
```

Check if a field type supports the 'options' configuration key

* `$type` — Field type

### `typeIsSearchable()`

```php
typeIsSearchable(string $type): bool
```

Check if a field type supports the 'searchable' configuration key

* `$type` — Field type

### `typeIsReference()`

```php
typeIsReference(string $type): bool
```

Check if a field type is a reference type (links to another entity)

* `$type` — Field type

### `getAllSupportedContexts()`

```php
getAllSupportedContexts(): array
```

Get all supported contexts

### `getAllSupportedTypes()`

```php
getAllSupportedTypes(): array
```

Get all supported field types

## Examples

Get the first page of custom fields:

```php
$customFields = Teamleader::customFields()->list();
```

Get every custom field definition, paging automatically:

```php
$customFields = Teamleader::customFields()->all();
```

Get custom fields for specific context:

```php
$contactFields = Teamleader::customFields()->list(['context' => 'contact']);
```

Get specific custom fields by ID:

```php
$fields = Teamleader::customFields()->list(['ids' => ['uuid1', 'uuid2']]);
```

Get a single custom field:

```php
$field = Teamleader::customFields()->info('field-uuid-here');
```

Create a single-line text custom field for contacts:

```php
$field = Teamleader::customFields()->create(['label' => 'VAT Number', 'type' => 'single_line', 'context' => 'contact']);
```

Create a single-select dropdown for deals with options:

```php
$field = Teamleader::customFields()->create(['label' => 'Lead Source', 'type' => 'single_select', 'context' => 'deal', 'configuration' => ['options' => ['Referral', 'Website', 'Cold Call']]]);
```
