Skip to content

APIv3 REST

Overview

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.

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).

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

For help choosing an end-point, see also: 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.

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 end-point.

APIv3 REST via standalone script: extern/rest.php

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 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.

APIv3 REST via WordPress service

WP REST (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

For help choosing an authentication protocol, see also: Compatibility

Every request for APIv3 should include authentication details. These may be submitted in a few forms.

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, 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.

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.

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 is a general pre-requisite, and it will be the same for all traditional REST users. The API key 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:

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) and specifically CSRF: APIv3/APIv4 REST.

API Data

As you may recall, APIv3 is built around the triplet ($entity, $action, $params), e.g.

$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

Even if there are no $params, one should pass a placeholder value for &json=1.

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.

{
    "is_error": 0,
    "version": 3,
    "count": 1,
    "values": [
        {
            "contact_id": "10",
            "contact_type": "Individual",
            "contact_sub_type": "",
            "display_name": "Example Person",
            ...
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: XML response after searching for contact

<?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: XML response to creating a new contact

<?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>