English فارسی Suomi
Français Nederlands Translate

civicrm developer guide

CiviCRM: DevelopAPI

The API

CiviCRM has a stable comprehensive API (Application Programming Interface) that can be used to access much of the functionality of CiviCRM. The API is the recommended way for any external programme to interact with CiviCRM.

Why use the API?

If you're not familiar with APIs, you might ask why you would use the API when you could access the core functions (e.g. the BAO files) directly?

The answer is that the community will ensure that the API will function as expected with every new release. Great effort is made to preserve backwards compatibility of the API for several versions of CiviCRM. If you decide to use other ways to collect data (like your own MySQL statements), you are left to your own devices. Changes in the schema and BAO arguments, etc. will cause you grief.

Exploring the API

The best place to learn about the API is your own test install of CiviCRM.  Be wary about using the API on your live site because the the API does not ask for confirmation, and therefore you can easily make significant changes to your data. 

Each install comes with two tools that are useful for this. 

  • The API parameter list, which shows all available entities which can be manipulated by the API and is available at http://[CIVICRM_URL]/civicrm/api/doc (or http://[CIVICRM_URL]/?q=civicrm/api/doc if you do not use clean url's in Drupal). You will first get a list of all the API entities. If you click on an entity you will get a list of parameters that are available for that specific entity, with the type of the parameter.

  • The API explorer, which is available at http://[CIVICRM_URL]/civicrm/api/explorer (or http://[CIVICRM_URL]/?q=civicrm/api/explorer if you do not use clean url's in Drupal). This gives you the possibility to actually try out the API in action. You can select the entity you want to use, for example ' Contact' and the action you want to perform, for example ' Get' . Again, be careful as the API explorer will actually perform your actions! So if you delete a contact to check what API call to use, it will really delete the contact. The API explorer will show you the code you need to have to execute the API call you have been testing. To see an example of the API explorer in action check http://civicrm.org/API_version_3. It may be that it uses an older version of the API explorer, but you will get the idea!

How to use the API

There are at least 5 different ways of using an API function. In each environment, the API uses the same names for entities, actions, and parameters, but the syntax is slightly different. Entities are the data collections you want to operate on, for example Contact, Event or Group. The actions are the thing you want to do to the entity, for example get, create, delete or update.

You can use the API: 

  1. as a PHP function, to run your own code on the same server as CiviCRM 
  2. via the AJAX interface, to be called from JavaScript code
  3. via the REST* interface, can be called from another server via http calls
  4. as a Smarty function to add data to templates 
  5. from drush on the command line for Drupal installations.  

Calling the API in PHP 

If you write custom code that is going to run within the same environment as CiviCRM, calling the API as a PHP function is the recommended way of modifying or fetching data. You will see examples of API calls throughout the developer documentation. For example, you could create several tags from a script rather than doing it manually from the CiviCRM admin page. In general you can use the API in a procedural way, or in a OOP way. 

The recommended procedural way to call the API in PHP is

 civicrm_initialize( );
 $result = civicrm_api( $entity, $actions, $params);

The recommended OOP way to call the API is

require_once 'api/class.api.php';
$api = new civicrm_api3();
$result = $api->Entity->Action ( $params );

or even

require_once '/your/civi/folder/api/class.api.php' ;
$api = new civicrm_api3( array( ' conf_path' => '/your/path/to/your/civicrm/site' ) );
$result = $api->Entity->Action ( $params ); 

where $entity/Entity is the object you want to manipulate and $action/Action is what you want to do with the entity. 

The advantage of using the OOP way rather than the procedural way is that you can use the same syntax on the same server or on a remote server. For more details, check the comments in the top section of <your civicrm>/api/class.api.php.

Note: if you do not have a copy of CiviCRM on your source server, you can copy the file class.api.php  that resides in the folder /<your path>/civicrm/api/ to the new server and you can then use the OOP way. This will work for Drupal as documented here and in the source documentation of class.api.php. If you are running CiviCRM with Joomla you need to add the right path to the parameters when you instantiate the class, so $api = new civicrm_api3 (array ('path'=>'administrator/components/com_civicrm/civicrm/extern/rest.php', 'server' =>$server, 'api_key'=>$api_key, 'key'=>$key));  

In this book we will mainly use the procedural way for our examples.

So with real data:

civicrm_initialize( );
$contact = civicrm_api('Contact','Get',array('first_name' => 'Michael', 'last_name' => 'McAndrew', 'version' =>3)); 

The version parameter is used to enable us to have and use different versions of the API. So we could for example improve a specific API with some new functionality that is only used for a set of parameters that has 'version' => 4. At the same time all existing users can continue to use the version 3 functionality. Actually, in the api folder in your install you might still have a folder with version 2 api scripts, even if they are deprecated. 

Further examples are in the api/v3/examples folder in your install or in the svn repo. Note that the examples are all generated by the test suite. If there is something missing from the examples post on the API forum board and help us add it to the test suite. This may be a function or a field within that function. 

Calling the API from smarty

CiviCRM defines a smarty function {crmAPI} which can be used to call the API from the template layer.

{crmAPI var="ContactS" entity="Contact" action="get" version="3" first_name="Michael" last_name="McAndrew" }
{foreach from=$ContactS.values item=Contact}
  <li>{$Contact.example}</li>
{/foreach} 

Calling the API via javascript

It also defines a javascript function crmAPI() which can be used to call the API from javascript. 

 $().crmAPI ('Contact','get',{'version' :'3', 'first_name' :'Michael', 'first_name' :'McAndrew'}}
  ,{ success:function (data){    
       $.each(data, function(key, value) {// do something  });
     }
 });

Calling the API via Ajax or REST

You can also call the API via Ajax or REST.  Have a look at the api explorer for examples of how you call the API with these methods.There is a section further on about using the REST from an external server.

Calling the API via drush

Obviously you can only call the API using drush on a Drupal site (as drush is a Drupal module). For a single site use:

drush civicrm-api contact.get first_name=Michael last_name=McAndrew 

If you are using drush on a Drupal multi-site you have to specify the site name:

drush -l www.example.org  civicrm-api contact.get first_name=Michael last_name=McAndrew

Calling the API from an external server via the REST API

The syntax and basics are identical to the other methods. To be able to use the API with REST from an external server you need a site key and at least one api_key.

You can define a site key for your site in the civicrm.settings.php  file:

define( 'CIVICRM_SITE_KEY', 'yoursitekey' );

The site_key is unique for a site and is required with every REST call.

You also need at least one api_key. The can be set for a specific contact in the table civicrm_contact. You need to set the field api_key and you do that directly in the civicrm_contact table, for example using phpmyadmin. You can choose if you want to set an api_key for every contact that can access your CiviCRM server with the REST, or you can just set one (for contact ID 1 for example) that can be used generically by all external parties accessing your server.

It can also be part of your security policy to change an pai_key regularly. If that is the case, it is best if the calling session uses the civicrm/login function with the specific CMS user and password, and the site_key. As a result the calling server will receive the api_key as one of the params so it can be used in all further calls.

Any REST API call needs to hold a parameter called key with the site_key and api_key with the api key. 

Please note that if you are using curl you will have to have a complete install of curl. If you run into any issues with curl using the API and REST, please check the forum and/or IRC.

This security leaves room for improvement, and anyone able and willing to add authorization with oAuth will be applauded! Check the forum or IRC if you want to....

To call the API with a browser, use:

http://www.example.org/path/to/civi/codebase/civicrm/extern/rest.php?q=civicrm/<function>
For example:
http://www.example.org/civicrm/ajax/rest?fnName=civicrm/contact/get&json=1&key=
yoursitekey&PHPSESSID=4984783cb5ca0d51a622ff35fb32b590&version=3

Note: An action that modifies the database (such as creating a contact or group) should have the parameters passed as POST, not GET. The REST interface will not accepts both a GET for things that alter the database. So no create, delete or update with GET!

Note: if you use the OOP way to call the API you can actually use the same kind of syntax if you have initialized the object on the remote server:

require_once ' /your/civi/folder/api/class.api.php';
$api = new civicrm_api3( array( ' server'=>' http://example.org' , ' api_key' =>'theusersecretkey' , ' key' =>' thesitesecretkey' ) );
$result = $api->Entity->Action ( $params );

API actions

Most entities will support the following actions:

 Action  Description
 CREATE  Insert one new record (Note: if you pass an 'id' as a parameter, one record will be modified)
 DELETE  Delete one record (Note: requires an explicit 'id'  as a parameter. Note: If you want to skip the "recycle bin" for entities that support undelete (like Contacts) you should set $param[' skip_undelete' ] = 1)
 GET  Search for records
 GETCOUNT  Return the number of records found that match the criteria you passed as parameter(s). (Note: some queries are limited to 25 so you might always get that number as a maximum result.In that case you should really fix the API if you can.)
 GETFIELDS Fetch entity metadata, i.e. the list of fields supported by the entity 
 GETSINGLE  Search for records and return the only match. This returns the record in a simplified format that is easier to use and minimizes the IO required. If there are more records than 1 that match your criteria, an error is returned.
 GETVALUE  Does a get and returns the single value that you need to specify: $param[' return' ]=> ' field name' 
 REPLACE Replace an old set of records with a new or modified set of records. For example, replace the set of phone numbers with another set of phone numbers. WARNING: replace uses an implicit delete - use with care and test well before you use it in production!
 UPDATE  Update one or more fields for an existing record
 

Data returned

The returned data from the API will be an array (formatted in json/XML if you are using the REST).

The API does perform some internal validation and returns data based on (lack of) success:

$result[' is_error' ] = 0 (or 1 if there is an error)

$result[' error_message' ] = the error message if there is an error (as a string)

$result[' version' ] = 3 (or any other appropriate version)

$result[' count' ] = the number of records in the $values part of the $result array

$result[' values' ] = an array of records

$result[' id'] = the id of the record if there is only one result in $values 

Note: wheb you use the getsingle action you will not get an array 'values' returned within your result array, but a flat array with results

Chaining of API calls

You can do more API calls in one go with the first call feeding into the second one etc. For example, you can create a contact and then nest the website create in the first call. Once the contact has been created it will use the created contact_id to then create the website. If the API can not complete the total of chained calls, the whole process is rolled back. An example:

civicrm('Contact', 'Create', array('version' => 3, 'contact_type' => 'Individual', 'display_name' => 'BA Baracus', 'api.website.create' => array('url' => 'Ateam.com'));

or if you have more websites:

civicrm('Contact', 'Create', array('version' => 3, 'contact_type' => 'Individual', 'display_name' => 'BA Baracus', 'api.website.create' => array(array('url' => 'Ateam.com', ), array('url' => 'warmbeer.com', ))); 

A last example where two get-actions are chained:

$apiParams = array(
    'version'               =>  3,
    'last_name'             =>  "Jones",
    'api.GroupContact.Get'  => array(
        'contact_id'        => '$value.id'
    )
);

$result = civicrm_api("Contact", "Get", $apiParams );

 So in this case all the contacts whose last name is Jones will be listed, and for each one the groups of the contact are listed too. If you know in advance you want to retrieve both, a call like this will save you time, certainly when using the REST!

Options in the API

There are some special parameters you can pass into the API to perform additional sensible stuff, for example how many records you want returned. The following options should work on all API's:

 Option  Description
 sort Determines the way in which your returned records are ordered. Has to be a sort string that can be understood by MySQL (without the ORDER BY). So if I want to sort on last_name and  then on first_name starting with the last I should pass ' last_name, first_name DESC' 
 rowCount Determines the number of results that are returned. In almost all API's there will be a default limit of 25 records returned. You can use this option to change that if you want more or less records returned. 
 offset Works in combination with limit as per standard MySQl. Check the MySQL documentation for details.
 return  Determines what fields are returned in your result array. You should really only get the data that you actually need, for example only the display name, the gender and the birth date for a Contact.

 Note: the API development is an ongoing community effort. This means you might come across some unexpected behaviour with these options. We all hope you understand and fix them when required. 

The format of the options in a PHP call should be like this:

$params = array( ' option_group_id' => 1, ' version'  => 3, ' options'  => array( ' sort'  => ' label DESC' , 'rowCount'  => 1 ) ); 
$result = civicrm_api( ' option_value' , ' getsingle' , $params );

Note: the getsingle action in combination with rowCount=1 is sure to return you only one result. Getsingle all by itself returns an error if there are more than 1 records that match your set of criteria. 

API and permissions

The API can deal with a check_permissions parameter that determines if the CiviCRM permissions need to be checked. There are two possibilities:

  • ignore permission (check_permissions=0): this is the default when using the API with smarty or php (on the same server as CiviCRM is on). This is to allow you do display information the user wouldn't see by default (eg. the list of staff to anonymous users).
  • use permission (check_permissions=1): this is the default for REST or Ajax and it can't be overridden. This is also the mode for smarty or php if you add check_permission=1.

When check_permissions is set to 1 then the contact calling the API will be checked to see if they have appropriate credentials.

Permissions used by each API action as set in the file CRM/Core/DAO/.permissions. As of 4.3 any api action not specifically defined there required 'Administer CiviCRM' access.

These permissions can be altered using the AlterAPIPermissions hook.

As of 4.3 the Contact-Get API also applies ACL permissions. So, a person will only have the records of the contacts they are permitted to see returned. Only fields explicitly declared in getfields may be returned (the return param can not be manipulated to get extra fields).

On ajax, it uses the session (cookie) to find the user. For REST, you need for each call to add two extra param api_key (user key) & key (site key). if you use the API key, you need to go to sites/all/modules/extern/rest.php (as you can read in the section about calling the API with REST). The api_key will determine which contact will be checked.

No matter how the user is identified, it checks if:

1) The user has ‘access AJAX API’ (that could be granted to anonymous) OR 'access CiviCRM'

2) The user has the right permission. So for instance, you won't be able to access contribution information if you don't have the permissions that allow you to access it via the user interface. There isn't a perfect match between the permissions that are created with the UI in mind and the API. When in doubt, we tend to "oversecure" and on some edge case, you might not be able to access via the api some data you can on the UI.

You can alter the permission or create new ones (e.g. if you create a custom API) via the alterAPIPermissions hook. 

The permissions 'access AJAX API' is meant to work in conjunction with the hook to alter the permissions on the API (so you can let anonymous/non civi users access to a specific API without having to grant access civicrm)

For ajax they are some extra protections against CSRF or XSS:

  • you can't call directly the URL, only via ajax call
  • although every action can be called using POST, only read (get, getfields, getsingle) are accepted via http GET

3)      Contact Reference fields are usable if

  • they have ‘Access AJAX API’ OR
  • they have ‘access contact reference fields’.

Autocomplete with the API

If you create a profile for individual contacts that contains the current employer, you might want to add an autocomplete on that field, such as you have on the normal contact edit form. When a user starts to type the name of the current employer, the system will attempt to autocomplete the name from your database of organisation contacts. 

For security reasons, the Ajax interface is restricted to users who have access to CiviCRM - otherwise, it would be fairly easy for anyone to download all the contacts you have in your database. So that's the first thing we check for here: 

{if $session->get('userID') > 0}

<script type="text/javascript" src="/civicrm/{$config->resourceBase}js/rest.js"></script>{literal}
<script>
jQuery(document).ready(function($){
  $('#current_employer').crmAutocomplete({params:{contact_type:'Organization'}});
});
</script>
{/literal}

{/if}

You might want to add additional filters. For instance in a profile "new volunteer from a member", you want to populate the list only with the organisations that belong to the group "members" (group id 42). 

The autocomplete uses the quicksearch function which is available in the Contact API (and roughly does the same as the search in the top left corner of standard CiviCRM).

$('#current_employer').crmAutocomplete({params:{contact_type:'Organization',group:42}});

Extending the API

It should be noted that it's extremely easy to extend the api if you want to add some funky features: add a Magic.php file under api/v3, create a function civicrm_magic_getpony and voila, you have civicrm_api ("magic","getpony"), the smarty, the ajax, the REST, and it's also directly usable from the api explorer at /civicrm/ajax/doc 

If you want to have a go at creating, extending or fixing a core API, make sure you check the wiki instruction and stick to the API Architecture standards.

On top of this magic you can also create your own API functions in a CiviCRM extension. We recommend you use civix to create CiviCRM extension. For more information see the wiki page on the subject:  http://wiki.civicrm.org/confluence/display/CRMDOC42/Create+a+Module+Extension#CreateaModuleExtension-AddanAPIfunction

An example of  API usage

Migration can be a bit hard every now and then. Even if we have the standard CiviCRM import function, data quality at the source can be gruesome. So I personally create my own migration code using the API, and I will use some here as an example.

The first part is creating a specific migration group, after checking if it exists already and deleting it. This is done so all contacts created in the migration can be removed in one go if something goes wrong.

$groupTitle = " Migration ". date( " Ymd" , strtotime( ' now'  ) );
$groupName = " Special migration group" ;
$checkGroup = civicrm_api( ' Group' ,  ' Getcount',  array( 'version' =>'3', ' title' => $groupTitle;
if ( $checkGroup[' result' ] == 1 ) {
   civicrm_api( 'Group', 'Delete', array('version' => '3', 'id' => $checkGroup['id']));
}
civicrm_api( 'Group', 'Create', array('version' = '3', ' title' => $groupTitle, ' name' => $groupName ));

Second part of the example is creating an individual with the API, and adding a custom field which I know exists, but I do not know the id of the custom field in the specific site. Once again, I use the API to get the right custom field id. Obviously there are bits of code before this happens to manipulate the unstructured source data...

 $createInd = civicrm_api( 'Contact', ' Create'  array(
	' version'		=>	' 3',
	' contact_type'	=>	' Individual' ,
	' first_name' 	=>	$firstName,
	' middle_name'	=>	$middleName,
	' last_name' 	=>	$lastName,
	' gender_id' 	=>	$genderID,
	' birth_date' 	=>	$birthDate ));
if ( $createInd[' is_error'  != 0 ) {
	// error handling
} else {
	$contactID = $createInd[' id' ];
	$customField = civicrm_api( 'CustomField', 'Getsingle', array(
		'version' => '3',
		'label' => $customFieldName ));
	$columnName = "custom_".$customField['id'];
	civicrm_api( 'CustomValue', 'Create', array(
		'version' 		=>	'3',
		'entity_id'		=>	$contactID,
		$columnName	=>	$sourceField));

So this example should give you an idea of how to go about. There are more examples in the API folder of your specific install, in the folder <your civicrm site>/civicrm/api/v3/examples.

 



EDIT