Skip to content

APIv4 and Custom Data

CiviCRM has a flexible custom data system which allows nearly any entity to be extended by one or more custom groups. Custom groups come in two distinct flavors: Single-record and Multi-record. For more background see the user guide chapter: Creating Custom Fields.

Single-Record Custom Data

Because single-record groups extend an entity 1-to-1, the API treats these custom fields as an extension of an entity's regular fields. For example, normally an Event has fields like id, title, start_date, end_date, etc. Adding a custom group named "Event_Extra" and a field named "Room_number" would be accessible from the API as Event_Extra.Room_number. You would retrieve it and set it as if it were any other field.

Implied Join

Notice that the field name includes a dot, which is similar to the implicit join syntax. Internally, the API adds joins to the query to fetch custom data from the appropriate tables.

Field Names

The name of a field is not to be confused with the label. The API refers to custom groups/fields by name and not user-facing labels which are subject to translation and alteration.

Filtering Custom Fields with options

Custom fields with options (select list, checkbox or radio) serialize the selected options in the database. When adding a where clause with the API, use CONTAINS rather than IN or =; in fact, the latter two will not work. This is unintuitive but filtering this way is much faster. The API is aware of the field serialization method so will avoid overlapping keys. And it automatically adds the value delimiters so there aren't false positives. For example, searching for an option named color will not return another option named coloringbook.

Multi-Record Custom Data

Multiple record custom data sets are treated by the API as entities, which work similarly to other entities attached to contacts (Phone, Email, Address, etc.). For example, creating a multi-record set named "Work_History" could then be accessed via the API as an entity named "Custom_Work_History" (traditional style) or via the CustomValue php class (OO style). Creating a record would be done like so:

PHP (traditional):

civicrm_api4('Custom_Work_History', 'create', [
  'values' => ['entity_id' => 202, 'Test_Field' => 555],
CRM.api4('Custom_Work_History', 'create', {
  values: {entity_id: 202, Test_Field: 555}

PHP (OO): Note that the object-oriented style uses the CustomValue class and passes in the name of the custom group (without a Custom_ prefix):

  ->addValue('entity_id', 202)
  ->addValue('Test_Field', 555)


Get actions support wildcards in the SELECT clause, allowing you to select all fields from a custom group, or even all custom data for a given entity type.

Get all fields from single-record group

civicrm_api4('Contact', 'get', [
  'select' => ['my_custom_group.*']

Get all core and custom fields

civicrm_api4('Contact', 'get', [
  'select' => ['*', 'custom.*']

Warning: Join Limit

Every custom group adds a join to the query. If a site contains a large number of custom groups, this could potentially reach MySql's 61 join limit, causing a fatal error. Therefore, selecting custom.* should only be done if the number of custom groups is known.

Get all fields from multi-record group

This example uses an explicit join:

civicrm_api4('Contact', 'get', [
  'join' => [
    ['Custom_my_multi_group AS my_multi', 'LEFT'],
  'select' => ['my_multi.*'],

Field Types and I/O Formats

New custom fields can be configured to store different types of data (Text, Date, Number, URL, etc.). In most cases the I/O format via the api will be a string, however there are a few exceptions:

  • Date fields: Input format is anything understood by strtotime, e.g. "now" or "-1 week" or "2020-12-25". Output format is the ISO string "YYYY-MM-DD HH:MM:SS".
  • Checkbox/multi-select fields: I/O format is an array of option values.

Try It Out

Once you have created some custom data in your system, look for it in the API Explorer. Single-record data will appear as fields on the entities they extend, and multi-record data will appear in the list of entities.

Finding Custom Entities

In the Api Explorer look for your multi-record custom entities under "C" alphabetically as they all start with the prefix "Custom_".