
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.
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.
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.
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:
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.
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}
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 });
}
});
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.
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
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>
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 );
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 |
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
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!
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.
The API can deal with a check_permissions parameter that determines if the CiviCRM permissions need to be checked. There are two possibilities:
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:
3) Contact Reference fields are usable if
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
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.