Introduction

The CareHQ API is RESTful, uses predictable resource-oriented URLs, accepts URL-encoded form data request bodies, returns JSON-encoded responses and uses standard HTTP status codes, authentication and verbs (GET, PUT, PATCH and DELETE).

We recommend creating an API key on your sandbox account for development to avoid modifying live data.

There are a number of other useful recommendations for working with the API in the Integrating your website's enquiry form with CareHQ help article.

Sandbox URL
https://api.carehq.dev/v1/
Live URL
https://api.carehq.co.uk/v1/

SDKs

Currently CareHQ provides lightweight clients for Python , PHP , Ruby and C# and we are actively working on developing client SDKs for other languages.

Installing the Python SDK
pip install carehq
Installing the PHP SDK
composer require carehq/carehq-php
Installing the Ruby SDK
gem install carehq
Installing the C# SDK
dotnet add package CareHQ.APIClient

Authentication

The CareHQ API uses API keys to authenticate requests. You can view and manage your API keys under Account > API keys. You must have the account owner role to manage API keys.

To authenticate requests you make to the API you will need your account Id, an API key and API secret. API keys grant access to your data which may include sensitive and personally identifiable information - keep your API credentials safe! Don't share API credentials in publicly accessible code such as client-side JavaScript or public GitHub repositories.

When you create an API key you will be able to grant it a set of permissions for each resource; typically create, read (list & retrieve), update and delete. By only granting an API key the permissions it needs you can limit the risks associated with another application or service accessing your data.

All API requests must be made over HTTPS and optionally may be restricted to a known list of IP addresses associated with the API key.

Authentication values are sent in request headers. These include a timestamp for the request and a signature generated by hashing the request's URL-encoded form values, timestamp and your API secret. These header values are automatically generated and attached to each request by the SDK client. Your API secret must never be sent with a request.

GET
/v1/care-enquiries
import carehq

api_client = carehq.APIClient(
    account_id=MY_ACCOUNT_ID,
    api_key=MY_API_KEY,
    api_secret=MY_API_SECRET
)

care_enquiries = api_client('GET', 'care-enquiries')
<?php

require_once('vendor/autoload.php');

$api_client = new CareHQ\APIClient(
    MY_ACCOUNT_ID,
    MY_API_KEY,
    MY_API_SECRET
);

$care_enquiries = $api_client->request('GET', 'care-enquiries');
require 'carehq'

api_client = APIClient.new(
    MY_ACCOUNT_ID,
    MY_API_KEY,
    MY_API_SECRET
)

care_enquiries = api_client.request('GET', 'care-enquiries')
using CareHQ;
using System.Net.Http;
using System.Text.Json;

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            ApiClient apiClient = new ApiClient(
                MY_ACCOUNT_ID,
                MY_API_KEY,
                MY_API_SECRET
            );

            var absences = apiClient.Request(
                HttpMethod.Get,
                "absences",
                new MultiValueDict()
                    .Add(
                        "attributes",
                        "ends",
                        "notes",
                        "reason_for_absence",
                        "starts"
                    )
            );
        }
    }
}

Rate limits

The CareHQ API enforces a rate limit of 10 requests per second per API key. We use rate limits to help ensure the API is stable and responsive at all times.

If you exceed the rate limit your SDK client will raise an RateLimitExceeded exception based on a 429 HTTP status code being returned from the server.

Working within the rate limit

Each HTTP response from the API includes additional headers that provide;

  • the rate limit (requests per second permitted for the key),
  • the time at which the rate limit will reset,
  • the number of requests remaining before the rate limit resets.

This information can be accessed via the SDK client and used to determine if you need to wait before making the next request. If multiple clients will be using the same API key concurrently then you will still need to handle RateLimitExceeded exceptions.

GET
/v1/care-enquiries
import carehq
import time

api_client = carehq.APIClient(
    account_id=MY_ACCOUNT_ID,
    api_key=MY_API_KEY,
    api_secret=MY_API_SECRET
)

def call_api(*args, **kwargs):
    """
    Call the API and handle rate limits by waiting until the limit resets.
    """
    if api_client.rate_limit_remaining is not None:
        if not api_client.rate_limit_remaining:
            time.sleep(api_client.rate_limit_reset - time.time())

    try:
        response = api_client(*args, **kwargs)
    except RateLimitExceeded as error:
        response = call_api(*args, **kwargs)

    return response

care_enquiries = call_api('GET', 'care-enquiries')
<?php

require_once('vendor/autoload.php');

$api_client = new CareHQ\APIClient(
    MY_ACCOUNT_ID,
    MY_API_KEY,
    MY_API_SECRET
);

/**
 * Call the API and handle rate limits by waiting until the
 * limit resets.
 */
function call_api(
    $api_client,
    $method,
    $path,
    $params=NULL,
    $data=NULL
) {

    if ($api_client->rate_limit_remaining === 0) {
        sleep($api_client->rate_limit_reset - time());
    }

    try {
        $response = $api_client->request(
            $method,
            $path,
            $params,
            $data
        );
    } catch (CareHQ\Exception\RateLimitExceeded $error) {
        $response = call_api(
            $api_client,
            $method,
            $path,
            $params,
            $data
        );
    }

    return $response;
}

$care_enquiries = call_api($api_client, 'GET', 'care-enquiries');
require 'carehq'
require 'carehq/exceptions'

api_client = APIClient.new(
    MY_ACCOUNT_ID,
    MY_API_KEY,
    MY_API_SECRET
)

def call_api(api_client, method, path, params: nil, data: nil)
    # Call the API and handle rate limits by waiting until the limit resets.

    if not api_client.rate_limit_remaining.nil?
        if (api_client.rate_limit_remaining or 0) <= 0
            sleep(api_client.rate_limit_reset - Time.now.to_f)
        end
    end

    begin
        response = api_client.request(method, path, params: params, data: data)
    rescue RateLimitExceeded => error
        response = call_api(method, path, params: params, data: data)
    end

    return response

end

care_enquiries = call_api(api_client, 'GET', 'care-enquiries')
using CareHQ;
using System;
using System.Net.Http;
using System.Text.Json;
using System.Threading;

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {

            ApiClient apiClient = new ApiClient(
                "MY_ACCOUNT_ID",
                "MY_API_KEY",
                "MY_API_SECRET",
            );

            JsonDocument absences = CallApi(
                apiClient,
                HttpMethod.Get,
                "care-enquiries"
            );

            if (absences != null)
                Console.WriteLine(absences.RootElement.ToString());
        }

        /// <summary>
        /// Call the API and handle rate limits by waiting until the limit resets
        /// </summary>
        /// <returns>Returns a JsonDocument</returns>
        private static JsonDocument CallApi(
            ApiClient apiClient,
            HttpMethod method,
            string path,
            MultiValueDict parameters = null,
            MultiValueDict data = null
        )
        {
            JsonDocument response = null;

            if (apiClient.RateLimitRemaining == 0)
                Thread.Sleep((int)(apiClient.RateLimitReset - DateTimeOffset.UtcNow.ToUnixTimeSeconds()) * 1000);

            try
            {
                response = apiClient.Request(
                    method,
                    path,
                    parameters,
                    data
                );
            }
            catch (CareHQ.Exception.RateLimitExceeded ex)
            {
                response = CallApi(
                        apiClient,
                        method,
                        path,
                        parameters,
                        data
                    );
            }

            return response;
        }
    }
}

Data types

The API accepts URL-encoded form data.

  • Boolean values are assumed to be true if any value is sent and false if the key is not present in the form data.
  • Structured data is sent by building a path representing the structure where each key is separated by a dash; for example postal_address-address_1.
  • Dates should use the format YYYY-MM-DD.
  • Times should use the format HH:MM.
  • Date/Times should use the format YYYY-MM-DD HH:MM:SS and should be given in UTC (not local time).

The API returns JSON data.

  • Dates are returned as strings using the format YYYY-MM-DD.
  • Times are returned as strings using the format HH:MM.
  • Date/Times are returned as strings using the format YYYY-MM-DD HH:MM:SS and are always given as UTC (not local time).

Errors

HTTP responses from the API with a status code in the 4xx range represent an error with the request (e.g. a requested resource does not exist, or a required parameter is missing). A status code in the 5xx range indicates an error with the CareHQ API.

Errors are typically handled by capturing them as exceptions raised when calling the API.

Status codes

  • 400 - Invalid request
  • 401 - Unauthorized
  • 403 - Forbidden
  • 405 - Method not allowed
  • 404 - Not found
  • 429 - Rate limit exceeded

Attributes

  • hint
    string

    A descriptive hint as to the reason for the error.

  • arg_errors
    hash

    When applicable the arg_errors attribute will be present and provide a dictionary of invalid parameters (as the keys) and validation errors (a list of strings) for each parameter (as the values).

GET
/v1/care-enquiries
import carehq

api_client = carehq.APIClient(
    account_id=MY_ACCOUNT_ID,
    api_key=MY_API_KEY,
    api_secret=MY_API_SECRET
)

try:
    api_client('GET', 'care-enquiries')

except carehq.exceptions.APIException as error:
    print(error)
<?php

require_once('vendor/autoload.php');

$api_client = new CareHQ\APIClient(
    MY_ACCOUNT_ID,
    MY_API_KEY,
    MY_API_SECRET
);

try {
    $response = $api_client->request('GET', 'care-enquiries');
} catch (CareHQ\Exception\APIException $error) {
    echo($error);
}
require 'carehq'
require 'carehq/exceptions'

api_client = APIClient.new(
    MY_ACCOUNT_ID,
    MY_API_KEY,
    MY_API_SECRET
)

begin
    client.request('GET', 'care-enquiries')
rescue APIException => error
    print(error)
end
using CareHQ;
using System;
using System.Net.Http;

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {

            ApiClient apiClient = new ApiClient(
                MY_ACCOUNT_ID,
                MY_API_KEY,
                MY_API_SECRET
            );


            try
            {
                apiClient.Request(
                   HttpMethod.Get,
                   "care-enquiries"
                );
            }
            catch (CareHQ.Exception.APIException error)
            {
                Console.WriteLine(error);
            }
        }
    }
}

All resources can be fetched in bulk using a resource's list API method. Resources fetched using the list action are paginated returning one page per request.

By default pages contain a maximum of 10 resources, but this number can be increased to 100.

API methods that return paginated results share a common interface that supports the following parameters:

Parameters

  • attributes
    optional
    default ['_id']
    A list of attributes to include for fetched objects.
  • page
    optional
    default 1
    The page number to fetch.
  • per_page
    optional
    default 10
    The number of items to return per page.

Pagination response

  • item count
    integer
    The number of items returned.
  • items
    list of hashes
    A list of resources.
  • page
    integer
    The page number returned.
  • page_count
    integer
    The total number of pages given the per_page value.
  • per_page
    integer
    The maximum number of items that can be returned in a page.