Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • documentation/docs/dev
  • totten/dev
  • bgm/dev
  • ivan_compucorp/dev
  • seamuslee/dev
  • artfulrobot/dev
  • ufundo/dev
  • wmortada/dev
  • lucky091588/dev
  • DaveD/dev
  • jtwyman/dev
  • rukkykofi/dev
  • JonGold/dev
  • jaapjansma/developer-docs
  • alainb/dev
  • noah/dev
  • justinfreeman/dev
  • pradeep/dev
  • larssg/dev
  • eileen/dev
  • darrick/dev
  • mattwire/dev
  • colemanw/dev
  • homotechsual/dev
  • JoeMurray/dev
  • maynardsmith/dev
  • kurund/dev
  • rocxa/dev
  • AllenShaw/dev
  • bradleyt/dev
  • chrisgaraffa/dev
  • martin.w/dev
  • herbdool/dev
  • MattTrim1/dev
  • Detlev/dev
  • ErikHommel/dev
  • brienne/devdocs
  • pminf/dev
  • SarahFG/dev
  • ayduns/dev
  • JKingsnorth/dev
  • ginkgomzd/dev
  • nicol/dev
  • almeidam/dev
  • arthurm/dev
  • damilare/dev
  • semseysandor/dev
  • major/devdocs
  • usha.makoa/dev
  • yurg/dev
  • shaneonabike/dev
  • andie/dev
  • mmyriam/dev
  • gngn/dev
  • florian-dieckmann/dev
  • jade/dev
  • luke.stewart/dev
  • vinaygawade/dev
58 results
Show changes
Showing
with 2586 additions and 86 deletions
# The CiviCRM API
CiviCRM has a stable, comprehensive **API** (Application Programming Interface) for accessing and managing data.
The API is the recommended way for any extension or external program to interact with CiviCRM.
CiviCRM also uses its own API to power all new UIs and bundled extensions.
Extensions can provide additional API entities or functionality. For help creating your own additions to the API, see [API Architecture](v4/architecture.md).
!!! tip "Why Use the API"
The API is superior to executing raw SQL or calling internal CiviCRM functions, because it offers consistency and stability.
It is designed to function predictably with every new release so as to preserve backwards compatibility when changes to the schema and BAO functions inevitably occur.
Using the API also ensures all hooks and events are dispatched, allowing CiviCRM business logic and 3rd party integrations to function properly.
The best place to begin working with the API is your own *test* install of CiviCRM, using the API Explorer.
## API Explorer
This is the go-to tool for both new and experienced developers. It gives detailed, interactive documentation on each entity, including the
available actions and their parameters, and will write API code for you. To access it:
1. Log in to a CiviCRM site as an administrator.
* This can even be the [demo site](http://dmaster.demo.civicrm.org/).
2. Within the CivCRM menu, go to **Support > Developer** and either **API Explorer v4** (URL `/civicrm/api4`) or the legacy **API Explorer v3** (URL `/civicrm/api3`).
!!! warning
The API Explorer executes real API calls. It can modify data! So if you execute a `Contact` `delete` call, it will really delete the contact.
As such, any experimenting is best done within a test site.
To get started, select an entity, for example `Contact` and an action to perform, for example `Get`.
Use the GUI to select additional parameters to configure your API call; as you do, the API Explorer will generate code
which you can copy & paste into your PHP, Javascript, REST or CLI application.
## API Versions
CiviCRM's API has major versions which are independent of the CiviCRM version. The API version increments more slowly in order to maintain stability within the extension ecosystem.
Typically, two versions of the API are maintained concurrently to allow gradual transitions. New releases of CiviCRM may add features to the API but will not break backward-compatibility within an API version.
- [**APIv4**](v4/usage.md) is the current stable version, with new features being actively developed.
- [**APIv3**](v3/usage.md) is minimally maintained with no new features and regression bug-fixes only.
Your code can use a combination of v3 and v4 API calls, but v4 is recommended for all new projects.
Although there are no plans at the time of this writing to remove APIv3, [upgrading existing code](v4/differences-with-v3.md) to use APIv4 is a good way to future-proof extensions.
## Changelog
All important changes made to the API are recorded in [APIv3 changes](v3/changes.md) and [APIv4 changes](v4/changes.md).
## Entity Relationship Diagrams
To make better use of the API, it can be helpful to have a visual understanding of the relationship between entities available in the API. [Entity Relationship Diagrams](ERDs/index.md) illustrating many of these are available as supplementary documentation to the API Explorer.
\ No newline at end of file
# API Actions
# APIv3 Actions
!!! warning "APIv3 Deprecation"
API version 3 is now deprecated. [Version 4](../v4/actions.md) is recommended.
Most entities support the following actions:
......@@ -42,7 +45,7 @@ Fetch entity metadata, i.e. the list of fields supported by the entity
## getlist
Used for autocomplete lookups by the
[entityRef](https://wiki.civicrm.org/confluence/display/CRMDOC/EntityRef+Fields) widget
[entityRef](./../../framework/quickform/entityref.md) widget
## getoptions
......@@ -61,7 +64,7 @@ returns
array(
1 => 'Female',
2 => 'Male',
3 => 'Transgender'
3 => 'Other'
)
```
......@@ -74,6 +77,31 @@ Replace an old set of records with a new or modified set of records.
Warning - REPLACE includes an implicit delete - use with care & test well
before using in productions
## getunique
Returns all unique fields (other than 'id' field) for a given entity.
```php
civicrm_api3('Contribution', 'getunique');
```
return
```php
{
"is_error": 0,
"version": 3,
"count": 2,
"values": {
"UI_contrib_trxn_id": [
"trxn_id"
],
"UI_contrib_invoice_id": [
"invoice_id"
]
}
}
```
## <del>setvalue</del>
**Deprecated.** Use the create action with the param 'id' instead.
......
# API Chaining
# APIv3 Chaining
It is now possible to do two API calls at once with the first call feeding into
the second. E.g. to create a contact with a contribution you can nest the
contribution create into the contact create. Once the contact has been created
it will action the contribution create using the id from the contact create as
`contact_id`. Likewise you can ask for all activities or all contributions to
be returned when you do a get.
!!! warning "APIv3 Deprecation"
API version 3 is now deprecated. [Version 4](../v4/chaining.md) is recommended.
See [api/v3/examples] within the core source code for a plethora of examples
(from unit tests) that use API chaining. To start, look at these examples:
It is possible to do two API calls at once with the first call feeding into the second. E.g. to create a contact with a contribution you can nest the contribution create into the contact create. Once the contact has been created it will action the contribution create using the id from the contact create as `contact_id`. Likewise you can ask for all activities or all contributions to be returned when you do a `get`.
- [APIChainedArray.php]
- [APIChainedArrayFormats.php]
- [APIChainedArrayValuesFromSiblingFunction.php]
[api/v3/examples]: https://github.com/civicrm/civicrm-core/tree/master/api/v3/examples
[APIChainedArray.php]: https://github.com/civicrm/civicrm-core/blob/master/api/v3/examples/Contact/APIChainedArray.php
[APIChainedArrayFormats.php]: https://github.com/civicrm/civicrm-core/blob/master/api/v3/examples/Contact/APIChainedArrayFormats.php
[APIChainedArrayValuesFromSiblingFunction.php]: https://github.com/civicrm/civicrm-core/blob/master/api/v3/examples/Contact/APIChainedArrayValuesFromSiblingFunction.php
See [api/v3/examples](https://github.com/civicrm/civicrm-core/tree/master/api/v3/examples) within the core source code for a plethora of examples (from unit tests) that use chaining. To start, look at these examples:
- [APIChainedArray.php](https://github.com/civicrm/civicrm-core/blob/master/api/v3/examples/Contact/APIChainedArray.ex.php)
- [APIChainedArrayFormats.php](https://github.com/civicrm/civicrm-core/blob/master/api/v3/examples/Contact/APIChainedArrayFormats.ex.php)
- [APIChainedArrayValuesFromSiblingFunction.php](https://github.com/civicrm/civicrm-core/blob/master/api/v3/examples/Contact/APIChainedArrayValuesFromSiblingFunction.ex.php)
Note that there are a few supported syntaxes:
......@@ -71,6 +62,4 @@ civicrm_api('Contact', 'create', array(
The format you use on the way in will dictate the format on the way out.
Currently this supports any entity and it will convert to `entity_id` -
i.e. a PledgePayment inside a contribution will receive the `contribution_id`
from the outer call.
Currently this supports any entity and it will convert to `entity_id` - i.e. a PledgePayment inside a contribution will receive the `contribution_id` from the outer call.
This diff is collapsed.
# APIv3 and Custom Data
!!! warning "APIv3 Deprecation"
API version 3 is now deprecated. [Version 4](../v4/custom-data.md) is recommended.
Custom data attached to entities is referenced by `custom_N` where `N` is the unique numerical ID for the custom data field.
To set a custom field, or find entities with custom fields of a particular value, you typically use a parameter like this:
```php
$params['custom_N'] = 'value';
```
To return custom data for an entity, especially when using the CustomValue API, you typically pass a param like the following:
```php
$params['return.custom_N'] = 1;
```
*or (depending on which API entity you are querying)*
```php
$params['return'] = 'custom_N';
```
*or*
```php
$params['return'] = 'custom_N,custom_O,custom_P';
```
For setting custom date fields, (ie CustomValue create), date format is `YmdHis`, for example: `20050425000000`.
This is just a brief introduction; each API may have different requirements and allow different formats for accessing the custom data. See the [API function documentation](../index.md) and also read the comments and documentation in each API php file (under civicrm/CRM/api/v3 in your CiviCRM installation) for exact details,
which vary for each API entity and function.
## Custom Value get
If developers want to get all custom data related to a particular entity. The best method is to do a `CustomValue.get` API Call.
```php
$result = civicrm_api3('CustomValue', 'get', array('entity_id' => 1));
```
A sample output would be like the following
```php
{
"is_error":0,
"undefined_fields":["return_child:child_name"],
"version":3,
"count":1,
"id":2,
"values":[
{
"entity_id":"1",
"latest":"Bam Bam",
"id":"2",
"308":"Pebbles Flintstone",
"309":"Bam Bam"
}
] }
```
For entities other than the Contact Entity you can use an alternate notation to the `custom_n` to specify the custom fields you wish to return. You can use `custom_group_name:custom_field_name`. Read carefully the documentation and parameters in `CustomValue.php` for more alternatives and details.
!!! note
When retrieving custom data for contact entity, it will only return one value in the case of a multiple custom group set whereas for other entities (e.g. Address, or using the `CustomValue.get` API) you will get all custom data records that relate to the relevant entity
The CustomValue Entity implicitly determines what the `entity_table` variable should be when it is not supplied. If you find that the implicitly is not working out exactly, then specify the `entity_table` key.
When setting the value of custom data that is of type checkbox or multivalue it is important to note that the options need to be passed in as an array. For example, if you want to set options `a` and `c` of the custom field with the ID `2` on Contact `123` you should do the following
```php
$result = civicrm_api3(
'CustomValue',
'create',
array('entity_id' => 123, 'custom_2' => array('a', 'c'))
);
```
# APIv3 Examples
!!! warning "APIv3 Deprecation"
API version 3 is now deprecated. [Version 4](../v4/usage.md) is recommended.
All the APIv3 Examples are generated through Tests in the CodeBase and are auto-generated from those tests so we can be certain of the code that is given.
## Location of Examples
The most current examples can be found in CiviCRM's GitHub Repo on the [Master Branch](https://github.com/civicrm/civicrm-core/tree/master/api/v3/examples). When you install CiviCRM the Examples that come with the particular version of CiviCRM you have installed can be found in `<civicrm_root>/api/v3/examples`. You will also be able to view them through the [API Explorer](../index.md#api-explorer) by clicking on the **Examples** tab in the Explorer.
## Creating a New Example
If you find that there is an API call or similar or perhaps a parameter for an API call that you feel is missing an example for that would be useful to the community, you can create a new example in the following way:
1. Find the relevant API test file e.g. `tests/phpunit/api/v3/MembershipTest.php`
2. Write your unit test with the API call that you want to create an Example of, however rather than using `$this->callAPISuccess` use `$this->callAPIAndDocument`. The Call API and Document function should be called similar to the following
```php
$description = "This demonstrates setting a custom field through the API.";
$result = $this->callAPIAndDocument($this->_entity, 'create', $params, __FUNCTION__, __FILE__, $description);
```
3. Find in `tests/phpunit/CiviTest/CiviUnitTestCase.php` Find the function `documentMe` and comment out the if (defined) statement.
4. Run the test suite locally for that test e.g. `./tools/scripts/phpunit 'api_v3_MembershipTest'`.
5. Commit results including changes in the Examples dir and open a pull request.
# APIv3 Interfaces
!!! warning "APIv3 Deprecation"
API version 3 is now deprecated. [Version 4](../v4/usage.md) is recommended.
APIv3 has three main interfaces along with the PHP Code that can be used to access the API.
## Javascript {#javascript}
CiviCRM provides a number of different methods to interact with the API when in javascript code. The most common of these is through the AJAX interface which is usually called using jQuery code. The next most common is through the angular interface with a couple of Node.js interfaces
### Javascript AJAX Interface {:#ajax}
The AJAX interface is one of the more common interfaces used within CiviCRM code. The AJAX interface is most commonly seen when used in javascript code. You can get example AJAX interface code out of the [API Explorer](../index.md#api-explorer) as needed.
#### CRM.api3
`CRM.api3` is a javascript method produced by CiviCRM as a thin wrapper around a call to `http://example.org/civicrm/ajax/rest`. The standard format of such an API call can be found under the relevant usage sub-chapter of this documentation.
#### Tests
[QUnit](../../testing/qunit.md) tests for `CRM.api3` can be found in [/tests/qunit/crm-api3](https://github.com/civicrm/civicrm-core/tree/master/tests/qunit/crm-api3).
You can run the tests within a web browser by visiting `/civicrm/dev/qunit/civicrm/crm-api3` within a CiviCRM [development installation](../../tools/civibuild.md).
#### Changes
The recommended AJAX interface has changed between CiviCRM versions as follows:
* version 4.2.x - `cj().crmAPI(...)`
* version 4.3.x - `CRM.api(...)`
* version 4.4.x onwards - `CRM.api3()`
For details see [APIv3 changes](changes.md).
### Javascript AngularJS crmAPI {:#angularjs}
With the advent of AngularJS being introduced into the CiviCRM framework, a service was created `crmApi()` which is a variant of `CRM.api3()` for AngularJS. It should be noted that the results are packaged as "promises" by AngularJS. The crmAPI property can be manipulate to mock responses and also the JSON encoder uses `angular.toJson()` to correctly handle hidden properties. Examples of use are
```javascript
angular.module('myModule').controller('myController', function(crmApi) {
crmApi('entity_tag', 'create', {contact_id:123, tag_id:42})
.then(function(result){
console.log(result);
});
});
```
### CiviCRM-CV Node.js binding {#cv-node.js}
This is a tool that aims to work locally with Node.js and integrates into Node.js cv commands which allow for the interaction with a local CiviCRM install. For example you could use it to get the first 25 contacts from the database as follows
```javascript
var cv = require('civicrm-cv')({mode: 'promise'});
cv('api contact.get').then(function(result){
console.log("Found records: " + result.count);
});
```
You can also use all of CV commands such as getting the vars used to make connection to the CiviCRM instance and other site metadata as follows
```javascript
// Lookup the general site metadata. Return the data synchronously (blocking I/O).
var cv = require('civicrm-cv')({mode: 'sync'});
var result = cv('vars:show');
console.log("The Civi database is " + result.CIVI_DB_DSN);
console.log("The CMS database is " + result.CMS_DB_DSN);
```
More information can be found on the [project page](https://github.com/civicrm/cv-nodejs)
### Javascript Node-CiviCRM package {#node-civicrm}
Node CiviCRM is a Node.js package which allows for the interaction with a CiviCRM instance from a remote server. This uses the Rest API to communicate to CiviCRM. For example to get the first 25 individuals from the database can be done as follows
```javascript
var config = {
server:'http://example.org',
path:'/sites/all/modules/civicrm/extern/rest.php',
key:'your key from settings.civicrm.php',
api_key:'the user key'
};
var crmAPI = require('civicrm')(config);
crmAPI.get ('contact',{contact_type:'Individual',return:'display_name,email,phone'},
function (result) {
for (var i in result.values) {
val = result.values[i];
console.log(val.id +": "+val.display_name+ " "+val.email+ " "+ val.phone);
}
}
);
```
More information can be found on the [project page](https://github.com/TechToThePeople/node-civicrm)
<a id="civicrm-extern-rest-api"></a>
<a id="wp-rest-api"></a>
<a id="keys"></a>
<a id="options-parameters-and-chaining-in-the-rest-interface"></a>
## REST Interface {:#rest}
The CiviCRM API provides REST bindings, enabling remote applications to read and write data.
The REST interface for remote applications is very similar to the AJAX interface for browser-based applications. Both submit API calls to an HTTP end-point.
However, for remote applications, you must explicitly deal with formatting and authenticating the HTTP requests.
For more detailed information about how to work with REST API, see:
* [Sysadmin Guide: Setup: API Keys](https://docs.civicrm.org/sysadmin/en/latest/setup/api-keys/)
* [Developer Guide: APIv3 REST](rest.md)
* [Developer Guide: Framework: Authentication](../../framework/authx.md)
## Smarty API Interface
When building smarty templates you might find you may want to do lookups from the database for some reason. This maybe to get most recent contribution or other information from a contact's record if you adding templates on. The format of the Smarty API call is very similar to that of the APIv3 calls.
```smarty
{crmAPI entity="nameobject" method="namemethod" var="namevariable" extraparam1="aa" extraparam2="bb" sequential="1"}
```
The format is as follows:
- `entity` - the content you want to fetch, eg. "contact", "activity", "contribution"...
- `method` - `get`, `getcount`, `search`, `search_count` (it shouldn't be a method that seeks to modify the entity, only to fetch data) - note that `search` and `search_count` are deprecated in APIv3
- `var` - the name of the smarty variable you want to assign the result to (eg the list of contacts)
- `extraparams` (optional) - all the other parameters (as many as you want) are simply used directly as the "params" to the api. cf. the example below
- `sequential` (optional) - indicates whether the result array should be indexed sequentially (1,2,3...) or by returned IDs. Although it is optional, the default was '0' in CiviCRM up to version 4.3 and '1' in 4.4 so it is advisable to fix it as desired.
- `return` (optional) - The convention to define the return attributes (`return.sort_name return.country...`) doesn't work with smarty and is replaced by return="attribute1,attribute2,attribute3.."
For example if you wanted to display a list of contacts
```smarty
{crmAPI entity='contact' action="get" var="contacts" sequential="0"}
<ul>
{foreach from=$contacts.values item=contact}
<li id="contact_{$contact.contact_id}">{$contact.sort_name}</li>
{/foreach}</ul>
```
Or if you wanted to display a contacts Activities
```smarty
{crmAPI entity="activity" action="get" var="activities" contact_id=$contactId sequential="0"}
{foreach from=$activities.values item=activity}
<p>Activity { $activity.subject } is { $activity.status_id } </p>
{/foreach}
```
You can also use the Smarty `print_r` to help debug e.g. in the case above you could call `{$activities|@print_r}`
### Using it for a javascript variable
Instead of displaying the data directly, you might want to use it to initialise a javascript variable. You can now add it directly to the template wihout needing to use the AJAX interface. Which will produce same result but will take less time and server resources
```smarty
<script>
var data={crmAPI entity="contact" action="get" contact_type="Individual" ...};
</script>
```
# APIv3 Joins
!!! warning "APIv3 Deprecation"
API version 3 is now deprecated. [Version 4](../v4/implicit-joins.md) is recommended.
An API "get" action will typically return only the values of the entity
requested. However, there are times when it is advantageous to returned
data from a related entity. For instance, when querying the API for email
addresses, you may want to return the name of the associated contact from the
Contact entity.
The CiviCRM API supports two methods of returning data from associated entities;
API Joins and [APIv3 Chaining](../v3/chaining.md). API joins provide higher
performance by making a single SQL query with a
[SQL join](https://dev.mysql.com/doc/refman/5.7/en/join.html), and are
generally preferable to API chaining where available.
## Using an API Join
To use a join in an API call, specify the name of the field on which the
join happens, a period, and the name of the field to reference.
For instance, to search for all primary emails, returning the email and joining
to also return the contact's display name:
```php
$result = civicrm_api3('Email', 'get', array(
'return' => array("email", "contact_id.display_name"),
'is_primary' => 1,
));
```
Alternatively, to return email addresses of everyone whose last name is Smith
by joining to the Contact entity:
```php
$result = civicrm_api3('Email', 'get', array(
'contact_id.last_name' => "Smith",
));
```
You can join multiple times in one query. For instance, to return a list of
events, displaying their name, the name of the related campaign, and that
campaign's type:
```php
$result = civicrm_api3('Event', 'get', array(
'return' => array("title", "campaign_id.name", "campaign_id.campaign_type_id"),
));
```
!!! tip "Supported actions"
Joins are available only with the [get](../v3/actions.md#get),
[getsingle](../v3/actions.md#getsingle), and [getcount](../v3/actions.md#getcount)
actions.
## Identifying fields eligible for a join
It is possible to join an entity to any other entity if the
[schema](../../framework/entities/index.md)
identifies a [foreign key](../../framework/entities/schema-definition.md#table-foreignKey) or
a [pseudoconstant](../../framework/pseudoconstant.md). The [getfields](../v3/actions.md#getfields) action identifies
fields that are eligible for an API join.
!!! warning "Not supported for every entity"
For historical reasons, some entities have a non-standard API in APIv3
in order to handle more complicated operations. Those entities - 'Contact',
'Contribution', 'Pledge', and 'Participant' - can be joined to from another
table, but you can not join to other tables from them.
[APIv4](../v4/implicit-joins.md) does not have this limitation.
# API Parameters
# API Options
There are many parameters accepted by the CiviCRM API. Most parameters
depend on the entity – for current details in your see the [API Explorer]
and the [API examples]. However, some parameters are particularly dynamic or
generic; these may not be explained well by the auto-generated
documentation. The format for passing options as parameters using the
REST interface is explained at [REST
interface\#optionsparameters](https://wiki.civicrm.org/confluence/display/CRMDOC/REST+interface#RESTinterface-optionsparameters).
!!! warning "APIv3 Deprecation"
API version 3 is now deprecated. [Version 4](../v4/usage.md) is recommended.
There are many API Options accepted by the CiviCRM API. These options allow the developer to add in more parameters to the resulting Query that is run against the database. E.g. Limit, Sort. You can explore these options using the the [API Explorer](../index.md#api-explorer) and the [APIv3 Examples](../v3/examples.md) However, some parameters are particularly dynamic or generic; these may not be explained well by the auto-generated documentation. The format for passing options as parameters using the REST interface is explained at [REST interface](interfaces.md#rest).
[API Explorer]: /api/general/#api-explorer
[API examples]: /api/general/#api-examples
## sequential
......@@ -201,46 +196,3 @@ civicrm_api('Contact', 'create', array(
),
));
```
## Custom Data
Custom data attached to entities is referenced by `custom_N` where `N` is
the unique numerical ID for the custom data field.
To set a custom field, or find entities with custom fields of a
particular value, you typically use a parameter like this:
```php
$params['custom_N'] = 'value';
```
To return custom data for an entity, you typically pass a param like the
following:
```php
$params['return.custom_N'] = 1;
```
*or (depending on which API entity you are querying)*
```php
$params['return'] = 'custom_N';
```
*or*
```php
$params['return'] = 'custom_N,custom_O,custom_P';
```
For setting custom date fields, (ie CustomValue create), date format is
`YmdHis`, for example: `20050425000000`.
This is just a brief introduction; each API may have different requirements
and allow different formats for accessing the custom data. See the
[API function documentation](https://wiki.civicrm.org/confluence/display/CRMDOC/Using+the+API)
and also read the comments and documentation in each API php file
(under civicrm/CRM/api/v3 in your CiviCRM installation) for exact details,
which vary for each API entity and function.
For more details and examples,
[see the tutorial on using custom data with the API here](https://wiki.civicrm.org/confluence/display/CRMDOC/Using+Custom+Data+with+the+API).
# APIv3 REST
!!! warning "APIv3 Deprecation"
API version 3 is now deprecated. [Version 4](../v4/rest.md) is recommended.
## Overview
!!! tip "Get started with APIv3 Explorer"
CiviCRM has a built-in tool for working with APIv3 (`Support => Developer => APIv3 Explorer`). You may use
this to generate complete HTTP/REST examples that are tuned to your instance of CiviCRM.
This documentation provides a deeper explanation of the HTTP/REST interface.
CiviCRM APIv3 provides HTTP/REST bindings, enabling remote applications to read and write data. To use it, we must understand the end-point URLs, the
authentication protocols, and the API data.
??? question "Is APIv3 a REST-ful interface?"
HTTP-based APIs are sometimes described as "REST-ful" if they closely follow certain HTTP conventions. CiviCRM APIv3 is not REST-ful.
Never-the-less, it is generally used for reading and writing resource records, and (by tradition) the subsystem is referred to as "REST".
## Examples
As we review the structure of an APIv3 REST call, it may help to have a few examples. Here is a representative example:
```
1: GET https://www.example.org/sites/all/modules/civicrm/extern/rest.php
2: ?key=ABCD1234&api_key=ZYXW9876
3: &entity=Contact&action=get&json=%7B%22id%22%3A10%7D
```
In line 1, we see an *end-point URL*. Line 2 provides the *authentication* parameters. Line 3 conveys the specific API call ([entity, action, parameters](usage.md)).
Similar elements should appear in any API call, but the content of each can differ. Here is another example:
```
1: POST https://crm.example.org/civicrm/ajax/rest
2: Authorization: Basic dXNlcjpwYXNz
3: X-Requested-With: XMLHttpRequest
4:
5: entity=Activity&action=create&json=%7B%22subject%22%3A%22hello%22%7D
```
Here, we have a different *end-point URL* (line 1) along with a different *authentication* style (line 2). The specific API also differs (line 5).
## Compatibility
As we proceed through this chapter, we will consider different API features. When choosing which features to use, you may wish to consult back to this compatibility matrix.
| End-Point URL | `civicrm/ajax/*` | `extern/rest.php`(deprecated) | `WP REST` |
|--|--|--|--|
| APIv3 | **Yes** | **Yes** | **Yes** |
| APIv4 | **Yes** | No | No |
| Authentication: AuthX | **Yes** (v5.36+) | No | No |
| Authentication: Session-Cookie | **Yes** | No | No |
| Authentication: Traditional Keys | **Yes** (v5.47+) | **Yes** | **Yes** |
| CMS: Backdrop | **Yes** | **Yes** | No |
| CMS: Drupal 7 | **Yes** | **Yes** | No |
| CMS: Drupal 8+ | **Yes** | Unofficial, Deprecated | No |
| CMS: Joomla | Partial | **Yes** | No |
| CMS: WordPress | **Yes** | Deprecated | **Yes** (v5.25+) |
## End-Point URL
!!! tip "For help choosing an end-point, see also: [Compatibility](#compatibility)"
All requests should be submitted to an APIv3 end-point URL.
Requests are typically submitted with HTTP POST, but read-only operations may use HTTP GET.
You may choose among a handful of end-point URLs. Expand the sections below for more detailed information.
??? example "APIv3 REST via normal HTTP route: `civicrm/ajax/rest`"
The `civicrm/ajax/rest` end-point works like any regular page in CiviCRM. On Drupal, Backdrop, and some WordPress deployments, you may access it with a clean URL.
```
https://example.org/civicrm/ajax/rest
```
In other deployments, you may need a verbose URL - such as these WordPress and Joomla URLs:
```
https://wordpress.example.org/wp-admin/admin.php?page=CiviCRM&q=civicrm/ajax/rest
https://joomla.example.org/administrator/index.php?option=com_civicrm&task=civicrm/ajax/rest
```
The `civicrm/ajax/rest` end-point is frequently used for browser-based API calls ("AJAX"). In newer versions (CiviCRM v5.36+), it can also be used for remote applications.
Stylisitcally, this is similar to [APIv4 REST](../v4/rest.md) end-point.
??? example "APIv3 REST via standalone script: `extern/rest.php`"
!!! warning "As of v5.47+, there should be no reason to use `extern/rest.php` - other end-points should be more compatible and more featureful. See [APIv3 Changelog](changes.md#restendpoint) for migration notes."
The `extern/rest.php` end-point is a standalone PHP script. It generally lives in the CiviCRM source tree, although the location will depend on the specific deployment.
```
## Typical Backdrop URL
https://example.org/modules/civicrm/extern/rest.php
## Typical Drupal 7 URL
https://example.org/sites/all/modules/civicrm/extern/rest.php
## Typical Joomla URL
https://example.org/administrator/components/com_civicrm/civicrm/extern/rest.php`
## Typical WordPress URL
https://example.org/wp-content/plugins/civicrm/civicrm/extern/rest.php
```
This end-point is broadly compatibile with many *versions* (CiviCRM v3+). However, it is incompatible with APIv4 and with some *environments*.
Specifically, Drupal 8+ and some configurations of WordPress have difficulty with it.
??? example "APIv3 REST via WordPress service"
[WP REST](wp-rest.md) (CiviCRM v5.25+) replaces all `extern/*.php` scripts with WordPress-optimized equivalents. These end-points support
clean URLs, and they provide wider compatibility with more WordPress environments.
```
## Typical WP REST URL
https://example.com/wp-json/civicrm/v3/rest
```
## Authentication
!!! tip "For help choosing an authentication protocol, see also: [Compatibility](#compatibility)"
Every request for APIv3 should include authentication details. These may be submitted in a few forms.
??? example "Authenticate via AuthX (API Key, JWT, Username/Password)"
The core extension "AuthX" (v5.36+) provides extended authentication support. If configured, [it can accept credentials in several different formats](../../framework/authx.md), such as:
```
/* Conventional HTTP header */
Authorization: Bearer MY_API_KEY
Authorization: Bearer MY_JSON_WEB_TOKEN
Authorization: Basic B64(USER:PASS)
/* Civi HTTP header */
X-Civi-Auth: Bearer MY_API_KEY
X-Civi-Auth: Bearer MY_JSON_WEB_TOKEN
X-Civi-Auth: Basic B64(USER:PASS)
/* HTTP parameter */
?_authx=Bearer+MY_API_KEY
?_authx=Bearer+MY_JSON_WEB_TOKEN
?_authx=Basic+B64(USER:PASS)
```
AuthX is compatible with normal CiviCRM routes like `civicrm/ajax/rest`.
??? example "Authenticate via CMS session/cookie"
Browser-based users typically access CiviCRM by logging in to a colocated CMS (Drupal, WordPress, etc). This process creates a session-cookie which
authenticates the user.
This style of authentication is important for AJAX. However, for remote applications, this style can be problematic because (a) each CMS has a different
login process and (b) site-builders often customize the login experience.
??? example "Authenticate via traditional REST keys"
CiviCRM v4+ supports authentication using a combination of *two* keys. A valid request must present both keys as URL parameters. For example:
```
?key=THE_SITE_KEY
&api_key=MY_API_KEY
```
The [site key](https://docs.civicrm.org/sysadmin/en/latest/setup/secret-keys/#civicrm_site_key) is a general pre-requisite, and it will be the
same for all traditional REST users. The [API key](https://docs.civicrm.org/sysadmin/en/latest/setup/api-keys/) uniquely identifies the
user or agent making the request.
Support for traditional REST keys is limited to specific end-points and versions:
| End-Point URL | Support Traditional REST Keys? |
| -- | -- |
| `civicrm/ajax/rest` | Yes (v5.47+) |
| `extern/rest.php` | Yes (All versions) |
| WP REST | Yes (v5.25+) |
## X-Requested-With
To ensure broad compatibility, APIv3 REST clients should set this HTTP header:
```http
X-Requested-With: XMLHttpRequest
```
The header is not required for all requests, but sometimes it is required, and there is generally no harm to
setting it.
For more complete details, see [Cross-Site Request Forgery (CSRF)](../../security/csrf.md) and specifically
[CSRF: APIv3/APIv4 REST](../../security/csrf.md#rest).
## API Data
As you may recall, APIv3 is built around the triplet [(`$entity`, `$action`, `$params`)](usage.md), e.g.
```php
$result = civicrm_api3($entity, $action, $params);
$result = civicrm_api3('Contact', 'get', ['id' => 10]);
```
The triplet corresponds to three HTTP parameters (`&entity=`, `&action=`, and `&json=`). If we adapt the
above example and apply appropriate escaping rules, the corresponding HTTP parameters will be:
```
&entity=Contact
&action=get
&json=%7B%22id%22%3A10%7D
```
!!! tip "Even if there are no `$params`, one should pass a placeholder value for `&json=1`."
??? warning "Deprecated: Extra Key-Value Parameters"
Any unrecognized parameters in the URL are passed through to the `$params`. The previous example could be written as:
```
&entity=Contact
&action=get
&id=10
```
This format looks easy, and it is retained for backward compatibility. Never-the-less, JSON is recommended because:
* Extra params cannot accurately indicate special values (`true`, `false`, `null`, `[]`, `{}`).
* Extra params are prone to naming conflicts (e.g. if an API requires an input `$params['action']`).
* Extra params require special encoding for nested fields (e.g. `&options[limit]=25&options[offset]=50`).
JSON addresses all these issues, and it has very broad support across many tools/environments/clients.
## Response
The response will be a JSON document, e.g.
```javascript
{
"is_error": 0,
"version": 3,
"count": 1,
"values": [
{
"contact_id": "10",
"contact_type": "Individual",
"contact_sub_type": "",
"display_name": "Example Person",
...
```
??? warning "Deprecated: XML Responses"
If you omit the `&json=...` parameter, then the APIv3 REST will send responses in XML format. This is retained for
backward compatibility, but JSON format is generally recommended.
!!! example "Example: XML response after searching for contact"
```xml
<?xml version="1.0"?>
<ResultSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Result>
<contact_id>1</contact_id>
<contact_type>Individual</contact_type>
<sort_name>Doe, John</sort_name>
<display_name>John G Doe</display_name>
<do_not_email>0</do_not_email>
<do_not_phone>0</do_not_phone>
<do_not_mail>0</do_not_mail>
<do_not_trade>0</do_not_trade>
<is_opt_out>0</is_opt_out>
<home_URL>[http://www.example.com]</home_URL>
<preferred_mail_format>Both</preferred_mail_format>
<first_name>John</first_name>
<middle_name>G</middle_name>
<last_name>Doe</last_name>
<is_deceased>0</is_deceased>
<email_id>2</email_id>
<email>jdoe@example.com</email>
<on_hold>0</on_hold>
</Result>
...
<Result>
<contact_id>N</contact_id>
<contact_type>Individual</contact_type>
<sort_name>test@example.org</sort_name>
<display_name>test@example.org</display_name>
<do_not_email>0</do_not_email>
<do_not_phone>0</do_not_phone>
<do_not_mail>0</do_not_mail>
<do_not_trade>0</do_not_trade>
<is_opt_out>0</is_opt_out>
<preferred_mail_format>Both</preferred_mail_format>
<is_deceased>0</is_deceased>
<email_id>4</email_id>
<email>test@example.org</email>
<on_hold>0</on_hold>
</Result>
</ResultSet>
```
!!! example "Example: XML response to creating a new contact"
```xml
<?xml version="1.0"?>
<ResultSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Result>
<contact_id>4</contact_id>
<is_error>0</is_error>
</Result>
</ResultSet>
```
# API Usage
!!! warning "APIv3 Deprecation"
API version 3 is now deprecated. [Version 4](../v4/usage.md) is recommended.
Every API call consists of three elements: the *entity*, *action*, and
*parameters*. For example, consider a few commonly-used entities along
with the supported actions and parameters:
......@@ -7,14 +10,12 @@ with the supported actions and parameters:
| Entity | Description | Actions | Parameters |
|--------------------------|--------------------------|---------|-------------------|
| <code>Contact</code> | An individual, <br /> organization, or <br />house-hold. |<code>create</code><br/><code>get</code><br/><code>delete</code><br/>| <code>contact\_type</code><br /> <code>nick\_name</code> <br /><code>preferred\_language</code> |
| <code>Activity</code> | An phone call, meeting,<br /> or email message. that <br /> has occurred (or will <br /> occur) at a specific <br /> date and time|<code>create</code><br/><code>get</code><br/><code>delete</code><br/>| <code>activity\_type\_id</code> <br /> <code>source\_contact\_id</code> <br /> <code>assignee\_contact\_id</code> |
| <code>Contact</code> | An individual, <br /> organization, or <br />household. |<code>create</code><br/><code>get</code><br/><code>delete</code><br/>| <code>contact\_type</code><br /> <code>nick\_name</code> <br /><code>preferred\_language</code> |
| <code>Activity</code> | A phone call, meeting,<br /> or email message. that <br /> has occurred (or will <br /> occur) at a specific <br /> date and time|<code>create</code><br/><code>get</code><br/><code>delete</code><br/>| <code>activity\_type\_id</code> <br /> <code>source\_contact\_id</code> <br /> <code>assignee\_contact\_id</code> |
| <code>Address</code> | A street-address related <br /> to a contact. |<code>create</code><br/><code>get</code><br/><code>delete</code><br/>| <code>contact\_id</code>, <br /> <code>street\_address</code> <br /> <code>city</code> <br /> <code>state\_province\_id</code> <br /> <code>country\_id</code> |
(*For full, up-to-date details about specific entities and parameters, use the
[API Explorer].*)
[API Explorer]: /api/general/#api-explorer
[API Explorer](../index.md#api-explorer).*)
The API is available in many different environments (such as PHP, REST, and
Javascript), and the notation differs slightly in each environment.
......@@ -53,8 +54,8 @@ array(
)
```
(**Note**: A few specialized actions like `getsingle` or `getvalue` may
return success in a different format.)
!!! note
A few specialized actions like `getsingle` or `getvalue` may return success in a different format.
## PHP (civicrm_api3)
......@@ -82,11 +83,9 @@ for usability:
- Errors are reported as PHP exceptions. You may catch the exceptions or
(by default) allow them to bubble up.
*Note*: If you're writing a Drupal module, a Joomla extension, a WordPress
plugin, or a standalone script, then you may need to **bootstrap** CiviCRM
before using the API. See the examples in [Bootstrap Reference].
[Bootstrap Reference]: https://wiki.civicrm.org/confluence/display/CRMDOC/Bootstrap+Reference
!!! note "Use Outside of CiviCRM"
If you're writing a Drupal module, a Joomla extension, a WordPress plugin, or a standalone script, then you may need to [bootstrap](../../framework/bootstrap.md) CiviCRM before using the API.
## PHP (class.api.php)
......@@ -150,13 +149,11 @@ http://www.example.com/civicrm/ajax/rest
```
Obviously you should substitute your site in! You can explore the syntax
and options available using the [API Explorer].
and options available using the [API Explorer](../index.md#api-explorer).
Please note that the REST interface is subject to
[API Security](https://wiki.civicrm.org/confluence/display/CRMDOC/API+Security).
Please note that the REST interface is subject to [API Security](../../security/permissions.md#api-permissions).
For more details, see [REST
interface](http://wiki.civicrm.org/confluence/display/CRMDOC/REST+interface).
For more details, see [REST interface](interfaces.md#rest).
## AJAX
......@@ -165,22 +162,48 @@ interface](http://wiki.civicrm.org/confluence/display/CRMDOC/REST+interface). 
CRM.api3('entity', 'action', [params], [statusMessage]);
```
For more details, see [AJAX Interface].
If you pass `true` in as the `StatusMessage` param, it will display the default status message. This is useful when doing things such as adding tags to contacts or similar. If you wish to do further work based on the result of the API call (e.g use the results from a GET call) you will need to use the [then method](http://api.jquery.com/deferred.then/) to listen for the event. For example:
```javascript
CRM.api3('entity_tag', 'create', {contact_id:123, tag_id:42})
.then(function(result) {
console.log(result);
});
```
Using the CRM.api3 method you can pass multiple requests through at once e.g.
[AJAX Interface]: https://wiki.civicrm.org/confluence/display/CRMDOC/AJAX+Interface
```javascript
var params = [
['email', 'get', {contact_id: 123}],
['phone', 'get', {phone: '555-5555'}]
];
CRM.api3(params).then(function(result) {
console.log('email result is:', result[0]);
console.log('phone result is:', result[1]);
});
```
You can also use associative objects in your API call as follows:
``` javascript
var params = {
one: ['email', 'getoptions', {field: 'location_type_id'}],
two: ['phone', 'getoptions', {field: 'phone_type_id', sequential: 1}],
three: ['phone', 'get']
};
CRM.api3(params).then(function(result) {
console.log('email result is:', result.one);
console.log('phone options are:', result.two);
console.log('phone get result is:', result.three);
});
```
The AJAX interface is automatically available for web-pages generated through
CiviCRM (such as standard CiviCRM web-pages, CiviCRM extensions,
and custom CiviCRM templates).
The AJAX interface is automatically available for web-pages generated through CiviCRM (such as standard CiviCRM web-pages, CiviCRM extensions and custom CiviCRM templates).
The AJAX interface could be made available to other parts of the same website
(e.g. a drupal module or wordpress widget) by calling
`CRM_Core_Resources::singleton()->addCoreResources()`
from php. Please note that the AJAX interface is subject to
[API Security](https://wiki.civicrm.org/confluence/display/CRMDOC/API+Security)
and
[Same Origin Policy](http://en.wikipedia.org/wiki/Same_origin_policy).
To use it from an external site or application, see REST interface documentation.
The AJAX interface could be made available to other parts of the same website (e.g. a Drupal module or WordPress widget) by calling `Civi::resources()->addCoreResources()`
from php. Please note that the AJAX interface is subject to [API Security](../../security/permissions.md#api-permissions)
and [Same Origin Policy](http://en.wikipedia.org/wiki/Same_origin_policy). To use it from an external site or application, see the REST interface documentation.
## Smarty
......@@ -193,7 +216,12 @@ The smarty call is to add extra information, therefore *create* or *delete*
actions don't make sense in this case.
For more details, see
[Smarty API interface](https://wiki.civicrm.org/confluence/display/CRMDOC/Smarty+API+interface).
[Smarty API interface](interfaces.md#smarty-api-interface).
## Scheduled jobs
Any API call can be configured to be run as a scheduled job. These can be configured in the UI under Administer->System Settings->Scheduled jobs. Usually API calls run this way are written with the intent that they be run as scheduled jobs - e.g those with the Job entity or provided by payment processors to run recurring payments.
## Command line
......@@ -222,3 +250,16 @@ wp civicrm-api contact.get first_name=Alice last_name=Roberts
```bash
cv api contact.get first_name=Alice last_name=Roberts
```
## API Security
API has security measures built in depending on the way the API is called that can also be turned off or on. API Permissions are also able to be altered via hook. More information on API Security can be found in the [Security Documentation](../../security/permissions.md).
## API Lookups by Username
You can use a CMS username in lieu of a contact ID by prefacing it with `@user:`. For instance, if the user "james" has a CiviCRM contact ID of 123, these statements are identical:
```bash
cv api contact.get id=123
cv api contact.get id=@user:james
```
# CiviCRM WP REST API Wrapper
!!! warning "APIv3 Deprecation"
API version 3 is now deprecated. [Version 4](../v4/rest.md) is recommended.
Starting in CiviCRM Version 5.25 CiviCRM's [extern](https://github.com/civicrm/civicrm-core/tree/master/extern) scripts have been exposed as WordPress REST endpoints.
Requirements:
- PHP 7.1+
- WordPress 4.7+
- CiviCRM version 5.25
## Endpoints
1. `civicrm/v3/rest` - a wrapper around `civicrm_api3()`
**Parameters**:
- `key` - **required**, the site key
- `api_key` - **required**, the contact api key
- `entity` - **required**, the API entity
- `action` - **required**, the API action
- `json` - **optional**, json formatted string with the API parameters/arguments, or `1` as in `json=1`
It mimics CiviCRM's REST [interface](interfaces.md), by default all calls to `civicrm/v3/rest` return XML formatted results. To get `json` formatted results pass `json=1` or a json formatted string with the API parameters, like in example 2 below.
**Examples**:
1. `https://example.com/wp-json/civicrm/v3/rest?entity=Contact&action=get&key=<site_key>&api_key=<api_key>&group=Administrators`
2. `https://example.com/wp-json/civicrm/v3/rest?entity=Contact&action=get&key=<site_key>&api_key=<api_key>&json={"group": "Administrators"}`
2. `civicrm/v3/url` - a substitution for `civicrm/extern/url.php` to track when links in mailings are clicked.
3. `civicrm/v3/open` - a substitution for `civicrm/extern/open.php` to track when recipients open mailings.
4. `civicrm/v3/authorizeIPN` - a substitution for `civicrm/extern/authorizeIPN.php` (for testing Authorize.net as per [docs](https://docs.civicrm.org/sysadmin/en/latest/setup/payment-processors/authorize-net/#shell-script-testing-method))
**_Note_**: this endpoint has **not been tested**
5. `civicrm/v3/ipn` - a substitution for `civicrm/extern/ipn.php` (for PayPal Standard and Pro live transactions)
**_Note_**: this endpoint has **not been tested**
6. `civicrm/v3/cxn` - a substitution for `civicrm/extern/cxn.php`
7. `civicrm/v3/pxIPN` - a substitution for `civicrm/extern/pxIPN.php`
**_Note_**: this endpoint has **not been tested**
8. `civicrm/v3/widget` - a substitution for `civicrm/extern/widget.php`
9. `civicrm/v3/soap` - a substitution for `civicrm/extern/soap.php`
**_Note_**: this endpoint has **not been tested**
## Settings
It is recommened to use the hook included in the code to replace the mailing url via the WP REST API. To do this create a plugin that includes the following:
```php
add_filter( 'civi_wp_rest/plugin/replace_mailing_tracking_urls', '__return_true' )
```
Creating a standalone functionality plugin is recommended. You can read the [WP docs on Writing a plugin](https://codex.wordpress.org/Writing_a_Plugin), there is a good tutorial on a [Functionality Plugin at ccs-tricks](https://css-tricks.com/wordpress-functionality-plugins/)
Alternatively, but not recommended. you can set the `CIVICRM_WP_REST_REPLACE_MAILING_TRACKING` constant to `true` to replace mailing url and open tracking calls with their counterpart REST endpoints, `civicrm/v3/url` and `civicrm/v3/open`.
_Note: use this setting with caution, it may affect performance on large mailings, see `CiviCRM_WP_REST\Civi\Mailing_Hooks` class._
# APIv4 Actions
With a few exceptions, most API Entities support a basic set of _CRUD_ (create, read, update, delete) actions,
along with some _metadata_ actions to retrieve information about the structure of the entity.
!!! tip "API Explorer"
The easiest way to see which actions are available for each entity is to browse the [**API Explorer**](../api/#api-explorer),
which shows all available entities, their actions, and the parameters for each action.
*Most entities support the following actions:*
## Read Actions
* **`get`**
Search for records using SQL-like parameters (`select`, `where`, `having`, `join`, `orderBy`, `limit`).
For most entities, `get` includes advanced features such as [joins](explicit-joins.md).
* **`autocomplete`**
Used to populate EntityReference autocomplete results, this action calls `SearchDisplay::run`
which in turn calls the `get` action.
* **`export`**
Available only for [Managed Entity](managed.md) types, outputs code which can be used to package and distribute a record in an extension.
## Write Actions
* **`create`**
Insert a single new record into the database.
* **`update`**
Update one or more existing records with new values. If an `id` is not supplied, then query params are required to search for records to update.
* **`save`**
Given an array of records, either `create` or `update` each one. By default the presence of an `id` determines whether an existing record will be updated.
The `match` param gives finer control over this, and lets you specify one or more fields; if a single existing record matches *all* of them, it will be updated instead of a new record created. For example you can `save` an array of contacts and specify
`['external_id']` as the `match` param, which will update contacts with matching `external_id`s.
* **`delete`**
Delete one or more records based on query parameters. Some entities, including `Contact`, implement "Soft Delete", in which case the `delete` action's default behavior is to give records an intermediate "trashed" status. For these entities, set `useTrash = FALSE` to delete records permanently.
* **`replace`**
Replace an existing set of records with a new or modified set of records. For example, replace a group of `Phone` numbers for a given `Contact`.
!!! warning
Replace includes an implicit delete action - use with care & test well before using in production.
* **`revert`**
Available only for [Managed Entity](managed.md) types, resets a record to its original packaged state.
## Metadata Actions
* **`checkAccess`**
Check if current user is authorized to perform a specified action on a given record.
* **`getActions`**
Returns a list of actions avaiable for a given entity.
* **`getFields`**
Fetch the list of fields supported by the entity, including [custom fields](custom-data.md).
Optionally load the [option-lists](pseudoconstants.md) for fields.
## Other Entity-Specific Actions
Some entities provide extra actions. For example, `Afform::submit` or `SearchDisplay::run`.
To discover all available actions for an entity, use the `getActions` API action.
\ No newline at end of file
# APIv4 Architecture
*This guide is intended for anyone wishing to extend the CiviCRM API itself, either in core or in their own extension.*
!!! tip "Example extension"
As you read this, you can also follow-along with a live demo in the API Explorer by installing the [APIv4 Example Extension](https://lab.civicrm.org/extensions/api4example/).
## API Entity Classes
Every API entity is a class which inherits from [`\Civi\Api4\Generic\AbstractEntity`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/AbstractEntity.php). Each class serves the following purposes:
1. Declare the API entity by its existence.
- You can declare a new API (e.g. FooBar) simply by placing the class `\Civi\Api4\FooBar` in the `/Civi/Api4` directory of your extension, as long as it inherits from `\Civi\Api4\Generic\AbstractEntity`.
2. Provide factory functions for that entity's **Actions**.
3. A `getInfo` function which returns an array of metadata about the entity. In most cases `getInfo` from the base class does not need to be overridden.
4. An optional function `permissions`. This function should contain any specific permissions or overrides to the `meta` or `default` permissions necessary for the entity.
The function must return an array in a [suitable format](../../security/permissions.md#apiv4). The following example would allow the `get` action to anyone with `access CiviEntity` permission, and also shows how to override `meta` and `default` permissions:
```php
return [
// for meta actions e.g. getActions, getFields etc
'meta' => [<some permission>]
// To be used for all actions where there isn't a specific permission set
'default' => [<some permission>],
'get' => ['access CiviEntity'],
];
```
Further information on permissions is defined in the [security chapter](../../security/permissions.md#apiv4).
## API Action Classes
Every API action is a class which inherits from [`\Civi\Api4\Generic\AbstractAction`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/AbstractAction.php). It has two functions:
1. Store the parameters of the API call.
- Every `protected` class var is considered a parameter (unless it starts with an underscore).
- The `$version` parameter refers to the API version (4) and cannot be changed.
- The `$_entityName` and `$_actionName` vars are set when the Action object is constructed (by the Entity class factory fn, see above). The underscore makes them hidden parameters as they cannot be changed.
- Adding a `protected` var to your Action named e.g. `$thing` will automatically:
- Provide a getter/setter (via `__call` MagicMethod) named `getThing()` and `setThing()`.
- Expose the param in the API Explorer (be sure to add a doc-block as it displays in the help panel).
- Require a value for the param if you add the `@required` annotation.
2. Define a `_run()` function to execute the call and return the results.
- The `_run()` function is invoked by `execute()`
- It gets passed a `Result` object into which it places an array of values to be returned.
## The Result Class
An API [`Result`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/Result.php) is a PHP ArrayObject. It has three functions:
1. Store the results of the API call (accessible via ArrayAccess).
2. Store metadata like the Entity & Action names.
- Some actions extend the Result object to store extra metadata. For example [`BasicReplaceAction`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/BasicReplaceAction.php) returns [`\Civi\Api4\Result\ReplaceResult`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Result/ReplaceResult.php) which includes the additional `$deleted` property to list any items deleted by the operation.
3. Provide convenience methods like `$result->first()` and `$result->indexBy($field)`.
## Class Inheritance
![Inheritance](../../img/api4/inheritance-community-chest.jpg)
To reduce code duplication and enforce consistency, APIv4 uses PHP class inheritance extensively.
Compare these (slightly simplified) examples:
<!-- Would be nice if Markdown made it easier to do side-by-side comparison... -->
<table>
<thead>
<tr>
<th>APIv3 Website.php</th>
<th>APIv4 Website.php</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<pre class="codehilite">
function civicrm_api3_website_get($params) {
return _civicrm_api3_basic_get('Website', $params);
}
function civicrm_api3_website_create($params) {
return _civicrm_api3_basic_create('Website', $params);
}
function civicrm_api3_website_delete($params) {
return _civicrm_api3_basic_delete('Website', $params);
}
</pre>
</td>
<td>
<pre class="codehilite">
namespace Civi\Api4;
class Website extends Generic\DAOEntity {
}
</pre>
</td>
</tr>
</tbody>
</table>
*Website* is a typical CRUD API using generic functions to perform actions on the `civicrm_website` table.
The v3 file needed a function for each action, resulting in a lot of duplicate code across API files.
By taking advantage of class inheritance, APIv4 reduces this boilerplate to nothing; factory functions for the standard set of actions are inherited from `Civi\Api4\Generic\DAOEntity`.
### Entity Base Classes
![Entity Inheritance Diagram](../../img/api4/APIv4-entity-inheritance.svg)
There are three ways to implement an APIv4 entity:
1. **Extend DAOEntity:** for entities with a database table and `DAO` class. E.g. the *Contact* API entity corresponds to the
`CRM_Conatact_DAO_Contact` class and the `civicrm_contact` database table.
They extend from [`Civi\Api4\Generic\DAOEntity`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/DAOEntity.php)
and thus inherit the standard set of DAO actions.
2. **Extend BasicEntity:** to start with a [basic set of CRUD actions](architecture/#basic-actions),
use [`Civi\Api4\Generic\BasicEntity`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/BasicEntity.php)
as the base class. You do not need a DAO or even a database table for this type of entity; just supply a php
function to read, write and delete records and the API will handle CRUD functionality.
3. **Extend AbstractEntity:** for the most flexible type of entity use the [`\Civi\Api4\Generic\AbstractEntity`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/AbstractEntity.php) class directly.
This gives you the flexibility to implement any actions, using any datasource.
These APIs are not required to implement any action except `GetFields`.
See the [APIv4 example extension](https://lab.civicrm.org/extensions/api4example/) for a working demonstration.
### Action Class Hierarchy
To standardize parameter names and reduce code duplication, each action class inherits from an abstract parent.
![Action Inheritance Diagram](../../img/api4/APIv4-action-inheritance.svg)
### DAO Actions
All DAO entities provide factory functions for
[`DAOGetFieldsAction`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/DAOGetFieldsAction.php),
[`DAOGetAction`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/DAOGetAction.php),
[`DAOCreateAction`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/DAOCreateAction.php),
[`DAOUpdateAction`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/DAOUpdateAction.php),
[`DAOSaveAction`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/DAOSaveAction.php),
[`DAODeleteAction`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/DAODeleteAction.php), and
[`BasicReplaceAction`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/BasicReplaceAction.php).
The Get action uses schema metadata to query the database and perform joins with other DAO entities. The Create, Delete, Save & Update actions call the core BAO methods to ensure hooks are invoked when writing to the database.
In most cases the action classes are used as-is, but it's also possible to override a DAO action to add/modify parameters or functionality.
It is also possible to add other ad-hoc actions to any entity;
e.g. [`Contact::getChecksum`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Action/Contact/GetChecksum.php) is an ad-hoc action added to the Contact entity.
### Building Your Own Actions
You can add arbitrary actions to any entity simply by defining a class which extends [`AbstractAction`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/AbstractAction.php)
or one of the Basic actions.
#### AbstractAction
[**`AbstractAction`**](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/AbstractAction.php)
is the base class for all API actions. Every action must, at minimum, extend this class.
For example, the [`Example::random()`](https://lab.civicrm.org/extensions/api4example/blob/master/Civi/Api4/Action/Example/Random.php) action extends this class directly.
Your custom action will define parameters as protected class properties, and implement a `_run` function to execute the action.
Before extending `AbstractAction` directly, consider if your action could benefit from the features provided by one of the Basic actions:
#### Basic Actions
These classes provide a framework for building custom API actions.
They are all used by the [`Civi\Api4\Generic\BasicEntity`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/BasicEntity.php) class.
See the [Example entity](https://lab.civicrm.org/extensions/api4example/) for a working demonstration.
Each basic action is implemented by supplying a callback function to perform logic and return data;
the basic action class handles details like validating param input and formatting & filtering the result.
Basic Actions are designed to be used in 1 of 2 ways:
1. Your Entity's action function can construct the basic action directly, passing the callback into the constructor.
2. You can override the basic action class (e.g. for customizing the parameters). See [`Example::create()`](https://lab.civicrm.org/extensions/api4example/blob/master/Civi/Api4/Action/Example/Create.php).
- [**`BasicGetAction`**](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/BasicGetAction.php):
Used to build actions whose purpose is fetching records. Parameters are `select`, `where`, `offset`, `limit`, and `orderBy`.
Its built-in array-query engine automatically filters/sorts the raw data returned by your callback according to the parameters.
Normally your callback can simply return an array of all existing records, but if performance is a concern, the functions `_itemsToGet()` and `_isFieldSelected()` can help you optimize your callback to only return results that are needed.
- [**`BasicCreateAction`**](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/BasicCreateAction.php):
Used to create a new record. Parameters are `values`. Values will be passed into the callback via `writeRecord`, or you can override the `writeRecord` method in your custom create class.
See [`Example::create()`](https://lab.civicrm.org/extensions/api4example/blob/master/Civi/Api4/Action/Example/Create.php).
- [**`BasicUpdateAction`**](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/BasicUpdateAction.php):
Used to update records based on a search query. Parameters are `values`, `reload`, `where`, `offset`, `limit`, and `orderBy`.
Internally calls `Get` to obtain records to update, so your entity must implement a get action.
Each will be passed into the callback via `writeRecord`, or you can override the `writeRecord` method in your custom update class.
- [**`BasicSaveAction`**](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/BasicSaveAction.php):
Used to create or update multiple records. Parameters are `records`, `defaults`, and `reload`.
Each will be passed into the callback via `writeRecord`, or you can override the `writeRecord` method in your custom save class.
- [**`BasicBatchAction`**](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/BasicBatchAction.php):
Used to perform an action on records based on a search query. Use this class, for example, to implement Delete.
Parameters are `where`, `offset`, `limit`, and `orderBy`.
Internally calls `Get` to obtain records, so your entity must implement a get action.
Each will be passed into the callback via `doTask`, or you can override the `doTask` method in your custom batch class.
`Delete` actions can implement the [`SoftDelete`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/Traits/SoftDelete.php ) trait and default to marking records as "trashed" rather than permanently deleting them.
- [**`BasicReplaceAction`**](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/BasicReplaceAction.php):
Used to replace a set of records. Parameters are `records`, `default`, `reload`, `where`, `offset`, `limit`, and `orderBy`.
Internally calls `Get` to obtain records and `Save` to write them, so your entity must implement those actions.
- [**`BasicGetFieldsAction`**](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/BasicGetFieldsAction.php):
Metadata action returns a list of fields for your entity.
# APIv4 Chaining
Chaining lets you perform multiple API calls at once with the results of the outer call triggering additional api calls.
E.g. to create a contact with a contribution you can nest the contribution create into the contact create. Likewise you can ask for all activities or all contributions to be returned from `Contact::get`.
!!! tip "Chaining or Joins"
Chained API calls execute once per result. This can be very slow if the outer API call returns hundreds of records.
In that case, consider if you can achieve your goal using [Implicit](implicit-joins.md) or [Explicit Joins](explicit-joins.md) instead.
## Supported Syntaxes:
**Object Oriented:**
```php
$results = \Civi\Api4\Contact::create()
->addValue('contact_type', 'Individual')
->addValue('display_name', 'BA Baracus')
->addChain('create_website', \Civi\Api4\Website::create()->setValues(['contact_id' => '$id', 'url' => 'example.com']))
->execute();
```
**Traditional:**
```php
civicrm_api('Contact', 'create', [
'version' => 4,
'values' => [
'contact_type' => 'Individual',
'display_name' => 'BA Baracus',
],
'chain' => [
'create_website', ['Website', 'create', ['values' => ['url' => 'example.com', 'contact_id' => '$id']]],
],
]);
```
If you have 2 websites to create you can pass them as separate key => array pairs; just specify a unique array key in the chain array.
Object Oriented way
```php
\Civi\Api4\Contact::create()
->addChain('first_website', \Civi\Api4\Website::create()->setValues(['contact_id' => '$id', 'url' => 'example1.com']))
->addChain('second_website', \Civi\Api4\Website::create()->setValues(['contact_id' => '$id', 'url' => 'example2.com']))
...
```
Traditional:
```php
civicrm_api4('Contact', 'create', [
'chain' => [
'first website', ['Website', 'create', ['values' => ['url' => 'example1.com', 'contact_id' => '$id']]],
'second_website', ['Website', 'create', ['values' => ['url' => 'example2.com', 'contact_id' => '$id']]],
],
...
```
## Back-references
Note the use of `'$id'` in the examples above. Any field returned by the outer call can be passed down to a chained call by prefixing it with a dollar sign. Even the results of other chains can be accessed in this way.
# APIv4 Changelog
*This page lists major or breaking changes to APIv4 with each new release of CiviCRM Core. Other update notes can be found elsewhere:*
- To find out the version an APIv4 entity was added, check the `@since` annotation at the top of the file, or in the help box of the Explorer.
- Detailed APIv4 changes not listed here are available in the [release notes for each version](https://lab.civicrm.org/dev/core/-/tree/master/release-notes).
- Also see: [Differences Between Api v3 and v4](../v4/differences-with-v3.md) and [Hooks Changelog](../../hooks/changes.md).
## CiviCRM 5.64
If using `Workflow.render` api (or the not-supported-for-external-use functions `CRM_Core_BAO_MessageTemplate::sendMessage`)
the ids in the `WorkflowMessage` (model) properties (variously called 'values' or 'modelProps') now use consistent non-freudian casing.
They are standardised on `contactID` rather than `contactId` etc. The `tokenProperties` still use freud-case (id rather than ID).
## CiviCRM 5.54
### 5.54 Autocomplete action added
This API action is used with Entity Autocomplete inputs, which replace the APIv3-based EntityRef widgets.
## CiviCRM 5.45
### 5.45 ManagedEntity trait added with `export` and `revert` actions
For details see [managed entity](https://github.com/civicrm/civicrm-core/pull/21955) and [export action](https://github.com/civicrm/civicrm-core/pull/22014) pull requests.
### 5.45 Contact::delete uses trash by default
For details see [pull request](https://github.com/civicrm/civicrm-core/pull/21232) and documentation on [write actions](../v4/actions.md#write-actions) and [basic actions](../v4/architecture.md#basic-actions).
### 5.45 SortableEntity trait added with auto-weight management
For details see [pull request](https://github.com/civicrm/civicrm-core/pull/22137).
### 5.45 Navigation entity treats `permission` field as array rather than string
For details see [pull request](https://github.com/civicrm/civicrm-core/pull/22160).
### 5.45 RelationshipCache entity now has `case_id` column
For details see [pull request](https://github.com/civicrm/civicrm-core/pull/21845).
## CiviCRM 5.43
### 5.43 Only fields declared in `getFields` returned by default.
Every API must declare a `getFields` action to define what fields are returned; as of 5.43 this list is used more strictly: When using SELECT(*) or ommitting SELECT, only declared fields of type "Field" will be returned. See [pull-request](https://github.com/civicrm/civicrm-core/pull/21438) for details.
### 5.43 Virtual entities supported via event in Entity::get.
It's now possible to define ad-hoc or virtual entities without their own DAO. See [pull-request](https://github.com/civicrm/civicrm-core/pull/21803) for details.
## CiviCRM 5.38
### 5.38 Implicit join syntax changed, old syntax deprecated.
As of 5.38 the API supports the syntax `contact_id.display_name` and the old `contact.display_name` is deprecated. See [pull request](https://github.com/civicrm/civicrm-core/pull/20130) for details.
## CiviCRM 5.29
### 5.29 Added `target_contact_id` and `assignee_contact_id` to `Activity.create` in the API explorer.
Each can take an array of contact IDs. This feature existed before version 5.29.0 but was previously not discoverable in the explorer.
For more information see the [commit to CiviCRM Core](https://github.com/civicrm/civicrm-core/commit/8c6a5fd64b).
### 5.29 Shortcut for setting checkPermissions e.g. `Contact::get(FALSE)`
For more information see the following [pull request](https://github.com/civicrm/civicrm-core/pull/17834).
## CiviCRM 5.23
### 5.23 `$index` param supports array input
CiviCRM 5.23 supports two new modes for the `$index` param - associative and non-associative array. See [CiviCRM Core PR #16257](https://github.com/civicrm/civicrm-core/pull/16257)
### 5.23 Converts field values to correct data type
The api historically returns everything as a raw string from the query instead of converting it to the correct variable type (bool, int, float). As of CiviCRM 5.23 this is fixed for all DAO-based entities. See [CiviCRM Core PR #16274](https://github.com/civicrm/civicrm-core/pull/16274)
### 5.23 Selects only relevant contact fields by default
The Contact entity in CiviCRM is divided into 3 major types: Individuals, Households and Organizations.
Not all contact fields apply to all contact types, e.g. the `sic_code` field is only used by Organizations,
and the `first_name` and `last_name` fields are only used by Individuals.
In CiviCRM 5.23 the schema has been augmented with metadata about which fields belong to which contact type, and Api4 now uses this
metadata to select only relevant fields. E.g. fetching a household with the api will not return the `first_name` or `organization_name` fields
as those will always be `null`.
### 5.23 Get actions support selecting fields by * wildcard
The `select` param now supports the `*` wildcard character for matching field names.
See [CiviCRM Core PR #16302](https://github.com/civicrm/civicrm-core/pull/16302).
### 5.23 Delete/Update do not throw error when 0 items found
For consistency across all "batch-style" actions that update/delete records based on a query,
the `Delete` and `Update` actions now simply return an empty result if no matches are found to act upon.
Previously they would throw an exception, which was similar to APIv3 behavior but inconsistent with other
APIv4 batch actions and SQL in general. See [CiviCRM Core PR #16374](https://github.com/civicrm/civicrm-core/pull/16374).
# 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](https://docs.civicrm.org/user/en/latest/organising-your-data/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.
!!! note "Implied Join"
Notice that the field name includes a dot, which is similar to the [implicit join syntax](implicit-joins.md).
Internally, the API adds joins to the query to fetch custom data from the appropriate tables.
!!! tip "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):**
```php
civicrm_api4('Custom_Work_History', 'create', [
'values' => ['entity_id' => 202, 'Test_Field' => 555],
]);
```
**Javascript:**
```javascript
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):
```php
\Civi\Api4\CustomValue::create('Work_History')
->addValue('entity_id', 202)
->addValue('Test_Field', 555)
->execute();
```
## Wildcards
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
```php
civicrm_api4('Contact', 'get', [
'select' => ['my_custom_group.*']
]);
```
### Get all core and custom fields
```php
civicrm_api4('Contact', 'get', [
'select' => ['*', 'custom.*']
]);
```
!!! warning "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](explicit-joins.md):
```php
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.
!!! tip "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_".
# Differences Between API v3 and v4
APIv4 is broadly similar to APIv3. Both are designed for reading and writing data.
Both use *entities*, *actions*, and *parameters*. However, APIv4 is specifically a
breaking-change which aims to reduce *ambiguity* and improve *flexibility* and *consistency*.
This document walks through a list of specific differences. As you consider
them, it may help to have a concrete example expressed in both APIv3 and APIv4:
<!-- Would be nice if Markdown made it easier to do side-by-side comparison... -->
<table>
<thead>
<tr>
<th>APIv3</th>
<th>APIv4</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<em>Procedural-array style:</em><br/>
<div class="codehilite"><pre>
1: $res = civicrm_api3('Contact', 'get', [
2: 'sequential' => 1,
3: 'check_permissions' => 0, // default
4: 'first_name' => 'Bob',
5: 'return' => 'id,display_name',
6: 'options' => [
7: 'limit' => 2,
8: 'offset' => 2,
9: ],
10: ]);
11:
12: foreach ($res['values'] as $row) {
13: echo $row['display_name'];
14: }
</pre></div>
</td>
<td>
<em>Procedural-array style:</em><br/>
<div class="codehilite"><pre>
1: $result = civicrm_api4('Contact', 'get', [
2: 'checkPermissions' => FALSE,
3: 'where' => [['first_name', '=', 'Bob']],
4: 'select' => ['id', 'display_name'],
5: 'limit' => 2,
6: 'offset' => 2,
7: ]);
8:
9: foreach ($result as $row) {
10: echo $row['display_name'];
11: }
</pre></div>
<em>Object-oriented style:</em><br/>
<div class="codehilite"><pre>
1: $result = \Civi\Api4\Contact::get()
2: ->setCheckPermissions(FALSE)
3: ->addWhere(['first_name', '=', 'Bob'])
4: ->addSelect(['id', 'display_name'])
5: ->setLimit(2)
6: ->setOffset(2)
7: ->execute();
8:
9: foreach ($result as $row) {
10: echo $row['display_name'];
11: }
</pre></div>
</td>
</tr>
</tbody>
</table>
## Input
APIv4 reflects the ongoing efforts present through the lifecycle of APIv3 toward uniform and discreet input parameters.
For a little history... If you used early versions of APIv3, you might have written some code like this:
```php
civicrm_api3('Contact', 'get', array(
'check_permissions' => 0,
'first_name' => 'Elizabeth',
'return' => 'id,display_name',
'rowCount' => 1000,
'offset' => 2,
));
```
You may notice that there are no subordinate arrays -- everything goes into one flat list of parameters.
As the system grew, this became a bit awkward:
* What happens if you want to filter on a field named `return` or `action` or `rowCount`?
* How do you ensure that the same option gets the same name across all entities (`rowCount` vs `limit`)?
* Why does `first_name` use snake_case while `rowCount` uses lowerCamelCase?
* Why is `Contact.get` the only API to support `rowCount`?
Over time, APIv3 evolved so that this example would be more typical:
```php
civicrm_api3('Contact', 'get', [
'check_permissions' => FALSE,
'first_name' => 'Elizabeth',
'return' => ['id','display_name'],
'options' => ['limit' => 1000, 'offset' => 2],
]);
```
Observe:
* The `options` adds a place where you can define parameters without concern for conflicts.
* The new generation of `options` are more standardized - they often have generic implementations that work with multiple entities/actions.
* The top-level still contains a mix of *option* fields (like `return`) and *data* or *query* fields (like `first_name`).
* The old options at the top-level are deprecated but still around.
APIv4 presented an opportunity to *break backward compatibility* and thereby *become more consistent*. In APIv4, a typical call would look like:
```php
civicrm_api4('Contact', 'get', [
'checkPermissions' => FALSE,
'where' => [['first_name', '=', 'Elizabeth']],
'select' => ['id', 'display_name'],
'limit' => 1000,
'offset' => 2,
]);
```
Key things to note:
* The `options` array is completely gone. The params array *is* the list of options.
* Most items in the params array have shared/generic implementations - ensuring consistent naming and behavior for every api entity.
* The *data* fields (e.g. `id`, `display_name`, and `first_name`) no longer appear at the top. They always appear beneath some other param, such as `where` or `select`.
* In APIv3, it was possible (but deprecated) to call the API using a lower-case entity name (eg activity.get). This behavior has been removed in APIv4 and using lower-case entity names will cause an error. Use the proper CamelCase representation of the Entity name when making API calls.
## API Wrapper
* APIv4 supports two notations in PHP:
* Procedural/array style: `civicrm_api4('Entity', 'action', $params)`
* Object-oriented style: `\Civi\Api4\Entity::action()->...->execute()`
* When using OOP style in an IDE, most actions and parameters can benefit from auto-completion and type-checking.
* `$checkPermissions` always defaults to `TRUE`. In APIv3, the default depended on the environment (`TRUE` in REST/Javascript; `FALSE` in PHP).
* Instead of APIv3's `sequential` param, a more flexible `index` controls how results are returned. In traditional style is is the 4th parameter to the api function:
* Passing a string will index all results by that key e.g. `civicrm_api4('Contact', 'get', $params, 'id')` will index by id.
* Passing a number will return the result at that index e.g. `civicrm_api4('Contact', 'get', $params, 0)` will return the first result and is the same as `\Civi\Api4\Contact::get()->execute()->first()`. `-1` is the equivalent of `$result->last()`.
* When [chaining](../v4/chaining.md) API calls together, back-references to values from the main API call must be explicitly given (discoverable in the API Explorer).
## Actions
* For `get`, the default `limit` has changed. If you send an API call without an explicit limit, then it will return *all* records. (In v3, it would silently apply a default of 25.) However, if you use the API Explorer, it will *recommend* a default limit of 25.
* The `create` action is now only used for creating *new* items (no more implicit update by passing an id to v3 `create`).
* The `save` action in v4 is most similar to v3's `create`, with the difference that it takes an array of one or more records instead of a single record. Like APIv3's `create`, it infers the action based on the presence of `id` in each record.
* `Update` and `Delete` can be performed on multiple items at once by specifying a `where` clause, vs a single item by id in v3.
Unlike v3, they will not complain if no matching items are found to update/delete and will return an empty result instead of an error.
* `getsingle` is gone, use `$result->first()` or `index` `0`.
* `getoptions` is no longer a standalone action, but part of `getFields`.
* `replace` requires at least one value; if there are no values to replace, use `delete`.
## Output
* `Result` is an [`ArrayObject`](https://www.php.net/manual/en/class.arrayobject.php) rather than a plain `array`.
* In PHP, you can iterate over the `ArrayObject` (`foreach ($myResult as $record)`), or you can call methods like `$result->first()` or `$result->indexBy('foo')`.
* By default, results are indexed sequentially (`0,1,2,3,...` like APIv3's `sequential => 1`). You may optionally index by `id`, `name`, or any other field, as in:
* (Procedural-style; use `$index` parameter): `civicrm_api4('Contact', 'get', [], 'id')`
* (OOP-style; use `indexBy()` method): `\Civi\Api4\Contact::get()->execute()->indexBy('id')`
* Custom fields are refered to by name rather than id. E.g. use `constituent_information.Most_Important_Issue` instead of `custom_4`.
# APIv4 Explicit Joins
In a relational database, you often need to work with data from multiple entities (tables) at once.
If the simpler notations for [implicit join](implicit-joins.md) or [option transformation](pseudoconstants.md)
don't meet a need, you can use the explicit syntax to indicate exactly how 2 tables should be joined.
!!! note "Get Only"
Unlike the [implicit join](implicit-joins.md) and [option transformation](pseudoconstants.md)
syntaxes which work for both read and write operations, explicit joins only work for `get` actions.
!!! tip "Joins or Chaining"
There is some overlap between joins and [Chaining](chaining.md); in some cases either technique can accomplish the same thing.
Because chaining executes a new query for every result, joins are usually more efficient when given a choice between the two.
## Specifying a Join
An explicit join is defined as an array with the following properties:
1. `EnityName AS alias` - the alias can be any string of your choosing; it will be used as an identifier in other clauses (`ON`, `SELECT`, `WHERE`, `HAVING`, `ORDER BY`)
2. Join type (`LEFT`, `INNER` or `EXCLUDE`)
- **LEFT** joins make the related entity *optional* - rows from the main entity are always returned.
- **INNER** joins make the related entity *required* - rows from the main entity are only returned if the join is found.
- **EXCLUDE** only returns rows from the main entity are only returned if the join is *not* found.
3. `EntityBridge` *(optional)* name of bridge to use (not shown, see following section on EntityBridges)
4. One or more `ON` clause arrays; each is either a single clause with `[expression, operator, expression]`, or a conjunction (`AND`, `OR`, `NOT`) followed by sub-clauses.
```php
// Traditional Syntax:
civicrm_api4('Contact', 'get', [
'join' => [
[
'Participant AS participants', // Entity & alias
'LEFT', // Type of join
NULL, // entity bridge to use
['id', '=', 'participants.contact_id'], // ON clauses...
['participants.status_id:name', '=', "'Attended'"],
],
],
...
```
!!! tip "Quoting Strings in ON Clauses"
Unlike WHERE or HAVING, the ON clause can reference field names on either side of the operator, e.g. 'participants.contact_id'.
To specify a string literal like "Attended", place it in a second set of quotation marks (single or double).
Note that arrays of strings do not need extra quotes, as in the below example:
The OOP syntax has a sugar `addJoin` method which takes the name/alias and side as the first 2 arguments,
then an optional bridge (not shown, see following section on EntityBridges), and a variable number of clauses.
```php
// OOP Syntax:
Civi\Api4\Contact::get()
->addJoin(
'Participant AS participants',
'LEFT',
NULL,
['id', '=', 'participants.contact_id'],
['participants.status_id:name', 'IN', ['Registered', 'Attended']]
)
...
```
!!! note "Specifying 0 Clauses Deprecated"
If you pass 0 clauses to the join (e.g. `'join' => [['Participant AS participants', 'LEFT']]`)
The API will attempt to find an FK between the two entities and automatically add it to the ON clause for you.
Because this can lead to ambiguity and unexpected behavior, it is recommended to always explicitly give the FK fields
in the ON clause of your join, as do the above examples.
## GROUP BY and Aggregation
The relationship between joined entities is not necessarily 1-1. By default this will cause duplicate rows to be returned
for the main entity. For example, an API call to `Contact.get` with a join on `Email` will return the same contact 3 times
if they have 3 email addresses.
This example groups the results by `Contact.id` to return just one row per contact, and aggregates
their email addresses into an array:
```php
civicrm_api4('Contact', 'get', [
'select' => ['display_name', 'GROUP_CONCAT(email.email) AS emails'],
'join' => [
['Email AS email', 'LEFT', ['id', '=', 'email.contact_id']],
],
'groupBy' => ['id'],
...
```
## Using an EntityBridge
An *EntityBridge* is a small table whose primary purpose is to link two other entities together.
They exist because MySQL cannot directly link a row in one table to multiple rows in another.
The EntityBridge solves this by storing a row for every join. For example, a single activity can
have more than one target contact, so the `ActivityContact` stores a row for every `Contact` linked to an `Activity`.
APIv4 allows you to join two entities *through* an EntityBridge with a single join clause. Just add the name of the bridge API
in front of the join clauses:
```php
civicrm_api('Activity', 'get', [
'join' => [
[
"Contact AS target_contacts", // Entity & alias
"LEFT", // Type of join
"ActivityContact", // EntityBridge name
['id', "=", 'target_contacts.activity_id'], // ON clauses...
['target_contacts.record_type_id:name', '=', '"Activity Targets"'],
],
],
...
```
Notice that the ON clause specifies joining directly to the Contact entity, even though the fields
`activity_id` or `record_type_id` actually belong to `ActivityContact`. This is because behind the scenes,
the API combines the two, allowing you to treat the `Contact` entity as if it also has fields
belonging to the `ActivityContact` entity.
# APIv4 Fields
In most cases the `values` refer to the database fields by the database field name.
- In some cases the field may be qualified with a `:` [denoting that data about the field is displayed](pseudoconstants.md)
- In some cases the field may be extended with a `.` [to join to another entity](implicit-joins.md)
- In some cases calculated fields will be exposed
## Calculated Fields
Calculated Fields are fields that are determined from other data. A few important things to remember:
- they are a feature of APIv4 and so are not present in APIv3 or via BAO's.
- they are not retrieved unless specifically requested as they can be expensive.
- they *are* available as tokens, for example when sending email, and anywhere else APIv4 is used, such as SearchKit.
Calculated fields can be based on:
- a single field: `Contact.age` is calculated from the `Contact.birth_date` field and the current date.
- multiple fields from the same record: `Contribution.tax_exclusive_amount` is the difference of `Contribution.total_amount` and `Contribution.tax_amount`.
- a sub-query or join using other tables: `Contribution.balance_amount` is calculated by a query on other financial tables.
Calculated Fields are specified in `GetSpecProvider` files. Look at the existing ones for examples in `<civi_root>/Civi/Api4/Service/Spec/Provider/*GetSpecProvider.php`
The SpecProvider has 3 main parts:
- the field definition - creating a `FieldSpec` object.
- the `applies()` function - limiting which entities and actions this applies to.
- the SQL string - defining how to calculate the new field (but see below for Entity Refs).
For a Calculated Field to be available through the API, the SpecProvider must be made discoverable. In an extension, one way to do this is to make your SpecProvider extend the `AutoService` interface, and [enable the `scan-classes` mixin](../../../framework/services/#registering-services). When developing an extension, the mixin can be enabled using `civix`:
```bash
civix mixin --enable=scan-classes@1
```
Using `scan-classes` may not be desirable for more complex/heavy extensions. Another way to make the SpecProvider discoverable is to register it individually with the CiviCRM container, with the tag `spec_provider`. For example, inside your extension's implementation of [hook_civicrm_container](../../hooks/hook_civicrm_container.md):
````php
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
function my_ext_civicrm_container(ContainerBuilder $container) {
$class = \Civi\Api4\Service\Spec\Provider\MyFieldGetSpecProvider::class;
$container->setDefinition($class, new Definition($class))
->setPublic(TRUE)
->addTag('spec_provider');
}
````
!!! tip "Hint"
When developing these Calculated Fields, use the debug feature of API4 Explorer to see the generated SQL.
### Calculated Fields in FormBuilder
To make your calculated field available as a filter on a [FormBuilder search form](../../../afform/overview/#afform-types), include an input type. For example:
````php
$field->setInputType('Select')
->setOptions([1 => 'One', 2 => 'Two']);
````
### Entity Refs
One powerful feature of Calculated Fields is the ability to use them as Entity References if the calculated value is a foreign key. All of the referenced entity's fields can be accessed without further definition of those fields.
So for example, the Calculated Field `Contact.address_primary` links to the Contact's primary address (determined by joining to the `civicrm_address` table) which then provides access to `Contact.address_primary.city`.
The SQL string defining the join for a reference like this moves to a file in `<civi_root>/Civi/Api4/Event/Subscriber/*SchemaMapSubscriber.php`
For an example, study the implementation of `Contact.address_primary` in `ContactGetSpecProvider.php` and `ContactSchemaMapSubscriber.php`
!!! tip "Reminder"
Note that a cache clear is needed after making changes to the `*SchemaMapSubscriber.php` files.
### Core Calculated Fields
This section contains a listing of Calculated Fields in core. Use them as inspiration!
- `Activity.case_id` - provides the case that an activity is linked to
- `Activity.source_contact_id`, `Activity.target_contact_id`, `Activity.assignee_contact_id` - contacts related to the activity
- `Address.proximity` - (Filter) determines whether an address is within a given distance of a location (see [example](https://github.com/civicrm/civicrm-core/pull/23597))
- `Contact.age_years`- age of a contact (based on `birth_date`) in years
- `Contact.groups` - (Filter) determines whether a contact belongs to any of the specified groups
- `Contact.address_primary, address_billing, email_primary, email_billing, phone_primary, phone_billing, im_primary, im_billing` - addresses associated with a contact
- `Contribution.balance_amount` - balance
- `Contribution.paid_amount` - amount paid
- `Contribution.tax_exclusive_amount` - total amount less the tax amount
- `Domain.is_active` - is this the current active domain
- `MessageTemplate.master_id` - the original version of a MessageTemplate if it has been modified
!!! tip "Filters vs Fields"
Most calculated fields can be used in any part of the query (SELECT, ORDER BY, HAVING, etc) but fields designaged as type '(Filter)' can only be used in the WHERE clause.