Floating Octothorpe

Cloudflare API: getting started

Cloudflare have been around for a few years now. If you managed a domain, they provide a number of useful services such as DDoS protection and DNS management. Most of the services offered by Cloudflare can be accessed via a RESTful API.

Getting your API key

Once you've created an account, you can access your API key from the Cloudflare website. Go to the "My Settings" page, find the API key section and view your "Global API Key":

Cloudflare Global API Key webpage screenshot

Key security

Anyone who has your API key can authenticate with Cloudflare. As a result you should treat it like a password and keep it private! The examples in this post assume the API key is being stored in a file called cloudflare-key, note the file is not world readable:

[alice@example ~]$ ls -l cloudflare-key
-rw-------. 1 alice alice 38 Nov  8 23:01 cloudflare-key

Making requests

All of the examples in this post use curl to make HTTP requests. This matches the Cloudflare documentation, however you could obviously use any HTTP tool or library when making API calls.

Zones

Most of the available API calls require a valid zone ID. You can get a zone ID using the list zones API call:

curl -s -X GET \
     -H "X-Auth-Email: [email protected]" \
     -H "X-Auth-Key: $(cat cloudflare-key)" \
     -H "Content-Type: application/json" \
     https://api.cloudflare.com/client/v4/zones?name=example.com

The API should return a JSON document with the zone details, including the zone ID:

{
    "errors": [],
    "messages": [],
    "result": [
        {
            "created_on": "2016-11-03T20:54:45.153731Z",
            "development_mode": 0,
            "id": "2aae6c35c94fcfb415dbe95f408b9ce9",
            "meta": {
...

Note: passing the document through python -m json.tool, should make the response a little easier to read:

List records in a zone

Once you've got a zone ID, you can list all DNS records in the zone using the List DNS Records API call:

curl -s -X GET \
     -H "X-Auth-Email: [email protected]" \
     -H "X-Auth-Key: $(cat cloudflare-key)" \
     -H "Content-Type: application/json" \
     https://api.cloudflare.com/client/v4/zones/2aae6c35c94fcfb415dbe95f408b9ce9/dns_records/

This should give output similar to the following:

{
    "errors": [],
    "messages": [],
    "result": [
        {
            "content": "203.0.113.119",
            "created_on": "2016-11-03T20:56:45.263431Z",
            "id": "000bf354c14977ce5d30fbe238359b96",
            "locked": false,
            "meta": {
                "auto_added": false
            },
            "modified_on": "2016-11-03T20:56:45.263431Z",
            "name": "f-o.example.com",
            "proxiable": true,
            "proxied": false,
            "ttl": 1,
            "type": "A",
            "zone_id": "2aae6c35c94fcfb415dbe95f408b9ce9",
            "zone_name": "example.com"
        },
        ...

You can also limit results to specific names or record types using a query string. For example:

curl -s -X GET \
     -H "X-Auth-Email: [email protected]" \
     -H "X-Auth-Key: $(cat cloudflare-key)" \
     -H "Content-Type: application/json" \
     https://api.cloudflare.com/client/v4/zones/2aae6c35c94fcfb415dbe95f408b9ce9/dns_records/?type=A

Updating records

There is also an API call for updating DNS records. Unlike the previous calls, this API uses the http PUT method, and requires a request body. This can be provided with the --date option:

curl -s -X PUT \
     -H "X-Auth-Email: [email protected]" \
     -H "X-Auth-Key: $(cat cloudflare-key)" \
     -H "Content-Type: application/json" \
     https://api.cloudflare.com/client/v4/zones/2aae6c35c94fcfb415dbe95f408b9ce9/dns_records/000bf354c14977ce5d30fbe238359b96 \
     --data '{ "content": "203.0.113.120", "id": "000bf354c14977ce5d30fbe238359b96", "locked": false, "meta": {"auto_added": false }, "name": "f-o.example.com", "proxiable":true, "proxied": false, "ttl": 1, "type": "A"}'

If everything is successful the response should look something like the following:

{
    "errors": [],
    "messages": [],
    "result": {
        "content": "203.0.113.119",
        "created_on": "2016-11-03T20:56:45.263431Z",
        "id": "000bf354c14977ce5d30fbe238359b96",
        "locked": false,
        "meta": {
            "auto_added": false
        },
        "created_on": "2016-11-04T19:58:43.323478Z",
        "name": "f-o.example.com",
        "proxiable": true,
        "proxied": false,
        "ttl": 1,
        "type": "A",
        "zone_id": "2aae6c35c94fcfb415dbe95f408b9ce9",
        "zone_name": "example.com"
    },
    "success": true
}

Note: the example given in the Cloudflare documentation uses all available record attributes in the JSON request body. However you can currently get away with only specifying the content, name and type attributes.