I’m probably doing Cloudflare a disservice by categorising it as a CDN provider, but that’s certainly one of the many services they offer and perhaps how most individuals using their free offering see them. Like me, I’m certain the vast majority of that group use the Cloudflare dashboard to configure their domains, but Cloudflare provides an API that allows you to programmatically manage those DNS records through a command-line interface of a *nix shell such as Bash.
The documentation states:
Using Cloudflare’s API, you can do just about anything you can do on cloudflare.com via the customer dashboard.
Although the Cloudflare API documentation gives numerous examples, it took me a while to get to grips with them, so I thought it may be useful for others if I document my examples.
To use the Cloudflare API you’ll need the email address used to login to your Cloudflare account and your Cloudlare account’s global API key.
Table of Contents
- INTRODUCTION
- 2. ABOUT THE CODE SAMPLES
- 2.1 Code
- 2.2 Output
- 2.3 Alternative Code and Output
- 2.4 API Keys vs API Tokens
- 2.5 Automated Shell Script
- 3. CLOUDFLARE RESTRICTIONS
- 4. WORKING CODE EXAMPLES
- 4.1 ZONE RECORDS
- 4.1.1 List All Zone Records
- 4.1.2 Create a New Zone Record for a Domain
- 4.1.3 List an Existing Zone Record for a Domain
- 4.1.4 Delete an Existing Zone Record for a Domain
- 4.2 CREATE NEW DNS RECORDS
- 4.2.1 Create a New DNS [A] Record for a Domain
- 4.2.2 Create a New DNS [A] Record for a Sub-domain
- 4.2.3 Create a New DNS [CNAME] Record for an Alias
- 4.2.4 Create a New DNS [MX] Record for a Domain
- 4.2.5 Create a Second New DNS [MX] Record for a Domain
- 4.2.6 Create a New DNS [TXT] Record
- 4.3. LIST, UPDATE & DELETE EXISTING DNS RECORDS
2. ABOUT THE CODE SAMPLES
2.1 Code
Below is an example of code used throughout this article together with the output if the request is successful and the output if unsuccessful:
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ ZONE_ID="8b717207bcee4047af2e9dff95832996"; \ TYPE="A"; \ NAME="example.com"; \ CONTENT="203.0.113.50"; \ PROXIED="true"; \ TTL="1"; \ curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H "Content-Type: application/json" \ --data '{"type":"'"$TYPE"'","name":"'"$NAME"'","content":"'"$CONTENT"'","proxied":'"$PROXIED"',"ttl":'"$TTL"'}' \ | python -m json.tool;
{ "errors": [], "messages": [], "result": { "content": "203.0.113.50", "created_on": "2018-01-27T15:57:52.254408Z", "id": "02a929c163302fe6ad885e77ad7bd268", "locked": false, "meta": { "auto_added": false, "managed_by_apps": false }, "modified_on": "2018-01-27T15:57:52.254408Z", "name": "example.com", "proxiable": true, "proxied": true, "ttl": 1, "type": "A", "zone_id": "8b717207bcee4047af2e9dff95832996", "zone_name": "example.com" }, "success": true }
{ "errors": [ { "code": 81057, "message": "The record already exists." } ], "messages": [], "result": null, "success": false }
I’ve assigned certain values in the code to variables – EMAIL
, KEY
etc – to make it easier to see how this data is used throughout the code. Below is a sample DNS record on the Cloudflare customer dashboard together with a table summarising the variables used.
Variable | Value |
---|---|
EMAIL |
The email address associated with your Cloudflare account. |
KEY |
The global API key associated with your Cloudflare account. |
TOKEN |
Similar to an API key, but allows more fine-tuned access. |
DOMAIN |
The name of the domain to create a zone record for. |
JUMP_START |
If true, automatically attempts to fetch existing DNS records when creating a domain’s zone record |
ZONE_ID |
The unique ID of the domain’s zone record. Assigned by Cloudflare. Required when managing an existing zone record and its DNS records. |
DNS_ID |
The unique ID given to each of the domain’s individual DNS records. Assigned by Cloudflare. Required when updating or deleting an existing DNS record. |
TYPE |
The DNS record type including A, CNAME, MX and TXT records. This equates to the Type column on the Cloudflare dashboard. |
NAME |
The DNS record name. This equates to the Name column on the Cloudflare dashboard. |
CONTENT |
The DNS record content. This equates to the Value column on the Cloudflare dashboard. |
PROXIED |
If true, a DNS record will pass through Cloudflare’s servers. Un-proxied records will not and are for DNS resolution only. Applicable to A and CNAME records only. This equates to the Status column on the Cloudflare dashboard. |
TTL |
Valid TTL. Must be between 120 and 2,147,483,647 seconds, or 1 for automatic |
PRIORITY |
The order in which servers should be contacted. Applicable to MX records only. |
ALL |
If true, JSON output will be pretty-printed using Python’s json.tool module. Otherwise, output will be limited to specified data. |
2.2 Output
All requests to Cloudflare’s API are made using HTTPS and return unformatted JSON data. To make this output readable, I’ve piped the JSON data through Python’s json.tool
– a simple command line interface for the json module to pretty-print JSON objects. All key/value pairs are sorted alphabetically.
HTTPS requests to the API using the POST
or DELETE
methods return a JSON object containing 4 top-level key/value pairs. These keys are errors
, messages
, result
and success
. The values for these keys can be an empty array:
"errors": [],
…another object containing other key/value pairs:
"result": { "content": "203.0.113.50", "created_on": "2018-01-27T15:57:52.254408Z", ... },
…or a boolean value:
"success": true
For HTTPS requests using GET
, result
key value objects are contained within an array:
"result": [ { ... "id": "8b717207bcee4047af2e9dff95832996", ... } ],
In addition there is a fifth top-level key/value pair for the GET
method named result_info
whose value is an object containing other key/value pairs:
"result_info": { "count": 1, ... },
2.3 Alternative Code and Output
Some requests to the Cloudflare API produce a lot of JSON data. As an alternative to the main code samples, I have provided alternative code whose output focuses on a particular piece of data – the unique ID of a domain’s DNS record for example. In the example below, the variable ALL
is included and controls how JSON data is displayed. If ALL
is true
, JSON data is piped to Python’s json.tool
as before. However, if false
, only limited JSON data – as specified in the statements passed as a command to python
– is displayed.
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ ZONE_ID="8b717207bcee4047af2e9dff95832996"; \ TYPE="A"; \ NAME="example.com"; \ CONTENT="203.0.113.50"; \ PROXIED="true"; \ TTL="1"; \ ALL="false"; \ curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H "Content-Type: application/json" \ --data '{"type":"'"$TYPE"'","name":"'"$NAME"'","content":"'"$CONTENT"'","proxied":'"$PROXIED"',"ttl":'"$TTL"'}' \ | if $ALL; then python -m json.tool; else python -c "import sys,json;data=json.loads(sys.stdin.read()); print('Type: ' + data['result']['type'] + '\n' + 'DNS ID: ' + data['result']['id'] if data['success'] else 'ERROR: ' + data['errors'][0]['message'])"; fi
Type: A DNS ID: 02a929c163302fe6ad885e77ad7bd268
ERROR: The record already exists.
2.4 API Keys vs API Tokens
Cloudflare are moving away from using legacy API keys to API tokens. All of the examples in this article use an API key to access the Cloudflare API and continue to work – for now. To use an API token, you need to change this example code…
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ ZONE_ID="8b717207bcee4047af2e9dff95832996"; \ TYPE="A"; \ NAME="example.com"; \ CONTENT="203.0.113.50"; \ PROXIED="true"; \ TTL="1"; \ curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H "Content-Type: application/json" \ --data '{"type":"'"$TYPE"'","name":"'"$NAME"'","content":"'"$CONTENT"'","proxied":'"$PROXIED"',"ttl":'"$TTL"'}' \ | python -m json.tool;
…to this…
TOKEN="ZsJcjFDfHxaVnEjjfDdvgpFDHF6jsUGVvyzd6M8R"; \ ZONE_ID="8b717207bcee4047af2e9dff95832996"; \ TYPE="A"; \ NAME="example.com"; \ CONTENT="203.0.113.50"; \ PROXIED="true"; \ TTL="1"; \ curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ --data '{"type":"'"$TYPE"'","name":"'"$NAME"'","content":"'"$CONTENT"'","proxied":'"$PROXIED"',"ttl":'"$TTL"'}' \ | python -m json.tool;
2.5 Automated Shell Script
I found working with the Cloudflare API cumbersome and somewhat error prone and so put together a shell script to streamline adding new DNS records and updating and deleting existing DNS records. The script requires the domain to have an existing zone record and allows this…
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ ZONE_ID="8b717207bcee4047af2e9dff95832996"; \ TYPE="A"; \ NAME="example.com"; \ CONTENT="203.0.113.50"; \ PROXIED="true"; \ TTL="1"; \ curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H "Content-Type: application/json" \ --data '{"type":"'"$TYPE"'","name":"'"$NAME"'","content":"'"$CONTENT"'","proxied":'"$PROXIED"',"ttl":'"$TTL"'}' \ | python -m json.tool;
…to be replaced with:
./cf-dns.sh -d example.com -n example.com -c 203.0.113.50 -l 1 -x y -k
Much simpler and no need to be concerned with getting zone IDs or DNS record IDs. The GitHub repository with documentation and examples can be found at cloudflare-dns.
3. ClOUDFLARE RESTRICTIONS
Adding DNS records on Cloudflare for a given domain will have no affect on where that domain’s DNS resolves until its nameservers are changed via the domain’s registrar to point to Cloudflare’s. As such, you should be able to use any domain name when experimenting with the Cloudflare API, but Cloudflare does impose some restrictions:
You can’t create DNS records for recognised domains like google.com, microsoft.com, example.com etc. Should you try, you’ll receive the error: This zone is banned and cannot be added to Cloudflare at this time. I’ve used example.com in all of my code examples, but this is purely illustrative.
The domain must be registered. You can’t use google.test, microsoft.invalid, example.localhost even though these TLDs have been reserved for testing and documentation purposes by the IETF (RFC 2606). The error message is We were unable to identify example.localhost as a registered domain.
A valid IP address is also required. Using 12.345.678.9 returns DNS Validation Error. I used 203.0.113.50 which is in a range of IP addresses which the IETF (RFC 5737) have reserved for testing and documentation purposes.
4. WORKING CODE EXAMPLES
Below is a screenshot of the Cloudflare dashboard showing DNS records for the domain example.com. We’ll create each of these DNS records using the Cloudflare API.
Each of the following code examples when executed from the command-line should do exactly as described, providing valid data is supplied for EMAIL
, KEY
and where applicable DOMAIN
, ZONE_ID
and DNS_ID
.
All code examples were successfully tested using cURL 7.54.0 and Python 2.7.10 on macOS High Sierra 10.13.3 and cURL 7.47.0 and Python 2.7.12 on Ubuntu 16.04.3.
4.1 ZONE RECORDS
4.1.1 List All Zone Records
Many interactions with the Cloudflare API require the domain’s zone ID. To list all the domains on your Cloudflare account together with their individual zone ID, use the following code:
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ curl -X GET "https://api.cloudflare.com/client/v4/zones" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H "Content-Type: application/json" \ | python -c $'import sys,json\ndata=json.loads(sys.stdin.read())\nif data["success"]:\n\tfor dict in data["result"]:print("Zone ID: " + dict["id"] + ", Domain: " + dict["name"])\nelse:print("ERROR(" + str(data["errors"][0]["code"]) + "): " + data["errors"][0]["message"])'
Zone ID:8b717207bcee4047af2e9dff95832996, Domain:example.com Zone ID:cmgL5LrSzoguaB5b4bBQsEx0YtqEqya4, Domain:example.net Zone ID:KsuNw7WlMISEOd2tiGlzTXYmJAeZMRJA, Domain:example.org
ERROR(9103): Unknown X-Auth-Key or X-Auth-Email
4.1.2 Create a New Zone Record for a Domain
In order to create DNS records for a domain, we first need to create a unique zone record for that domain to which we’ll later add these DNS records. To create a zone record for example.com
, use the following code:
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ DOMAIN="example.com"; \ JUMP_START="false"; \ curl -X POST "https://api.cloudflare.com/client/v4/zones/" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H "Content-Type: application/json" \ --data '{"name":"'"$DOMAIN"'","jump_start":'"$JUMP_START"'}' \ | python -m json.tool;
{ "errors": [], "messages": [], "result": { "account": { "id": "2b38766c25a309dc4906a2ca27b7951e", "name": "steve@example.com" }, "created_on": "2018-01-27T17:21:09.947727Z", "development_mode": 0, "id": "8b717207bcee4047af2e9dff95832996", "meta": { "custom_certificate_quota": 0, "multiple_railguns_allowed": false, "page_rule_quota": 3, "phishing_detected": false, "step": 4, "wildcard_proxiable": false }, "modified_on": "2018-01-27T17:21:09.947727Z", "name": "example.com", "name_servers": [ "elsa.ns.cloudflare.com", "sid.ns.cloudflare.com" ], "original_dnshost": null, "original_name_servers": [ "ns1.sedoparking.com", "ns2.sedoparking.com" ], "original_registrar": null, "owner": { "email": "steve@example.com", "id": "4ca324382cc5077590a1808267ebd523", "type": "user" }, "paused": false, "permissions": [ "#access:edit", "#access:read", "#analytics:read", "#app:edit", "#billing:edit", "#billing:read", "#cache_purge:edit", "#dns_records:edit", "#dns_records:read", "#lb:edit", "#lb:read", "#logs:read", "#member:edit", "#member:read", "#organization:edit", "#organization:read", "#ssl:edit", "#ssl:read", "#subscription:edit", "#subscription:read", "#waf:edit", "#waf:read", "#worker:edit", "#worker:read", "#zone:edit", "#zone:read", "#zone_settings:edit", "#zone_settings:read" ], "plan": { "can_subscribe": false, "currency": "USD", "externally_managed": false, "frequency": "", "id": "0daaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "is_subscribed": true, "legacy_discount": false, "legacy_id": "free", "name": "Free Website", "price": 0 }, "status": "pending", "type": "full" }, "success": true }
{ "errors": [ { "code": 1061, "message": "example.com already exists" } ], "messages": [], "result": null, "success": false }
Alternatively, to limit the data that is displayed use:
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ DOMAIN="example.com"; \ JUMP_START="false"; \ ALL="false"; \ curl -X POST "https://api.cloudflare.com/client/v4/zones/" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H "Content-Type: application/json" \ --data '{"name":"'"$DOMAIN"'","jump_start":'"$JUMP_START"'}' \ | if $ALL; then python -m json.tool; else python -c "import sys,json;data=json.loads(sys.stdin.read()); print('ZONE_ID: ' + data['result']['id'] if data['success'] else 'ERROR: ' + data['errors'][0]['message'])"; fi
ZONE_ID: 8b717207bcee4047af2e9dff95832996
ERROR: example.com already exists
4.1.3 List an Existing Zone Record for a Domain
To display the existing zone record for example.com
, use the following code:
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ DOMAIN="example.com"; \ curl -X GET "https://api.cloudflare.com/client/v4/zones?name=$DOMAIN" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H "Content-Type: application/json" \ | python -m json.tool;
{ "errors": [], "messages": [], "result": [ { "account": { "id": "2b38766c25a309dc4906a2ca27b7951e", "name": "steve@example.com" }, "created_on": "2018-01-27T17:39:39.206820Z", "development_mode": 0, "id": "8b717207bcee4047af2e9dff95832996", "meta": { "custom_certificate_quota": 0, "multiple_railguns_allowed": false, "page_rule_quota": 3, "phishing_detected": false, "step": 4, "wildcard_proxiable": false }, "modified_on": "2018-01-27T17:39:39.206820Z", "name": "example.com", "name_servers": [ "elsa.ns.cloudflare.com", "sid.ns.cloudflare.com" ], "original_dnshost": null, "original_name_servers": [ "ns1.sedoparking.com", "ns2.sedoparking.com" ], "original_registrar": null, "owner": { "email": "steve@example.com", "id": "4ca324382cc5077590a1808267ebd523", "type": "user" }, "paused": false, "permissions": [ "#access:edit", "#access:read", "#analytics:read", "#app:edit", "#billing:edit", "#billing:read", "#cache_purge:edit", "#dns_records:edit", "#dns_records:read", "#lb:edit", "#lb:read", "#logs:read", "#member:edit", "#member:read", "#organization:edit", "#organization:read", "#ssl:edit", "#ssl:read", "#subscription:edit", "#subscription:read", "#waf:edit", "#waf:read", "#worker:edit", "#worker:read", "#zone:edit", "#zone:read", "#zone_settings:edit", "#zone_settings:read" ], "plan": { "can_subscribe": false, "currency": "USD", "externally_managed": false, "frequency": "", "id": "0daaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "is_subscribed": true, "legacy_discount": false, "legacy_id": "free", "name": "Free Website", "price": 0 }, "status": "pending", "type": "full" } ], "result_info": { "count": 1, "page": 1, "per_page": 20, "total_count": 1, "total_pages": 1 }, "success": true }
{ "errors": [], "messages": [], "result": [], "result_info": { "count": 0, "page": 1, "per_page": 20, "total_count": 0, "total_pages": 0 }, "success": true }
Alternatively, to limit the data that is displayed use:
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ DOMAIN="example.com"; \ ALL="false"; \ curl -X GET "https://api.cloudflare.com/client/v4/zones?name=$DOMAIN" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H "Content-Type: application/json" \ | if $ALL; then python -m json.tool; else python -c "import sys,json;data=json.loads(sys.stdin.read()); print('ZONE_ID: ' + data['result'][0]['id'] if data['result'] else 'ERROR: Does a zone record for \"$DOMAIN\" exist?')"; fi
ZONE_ID: 8b717207bcee4047af2e9dff95832996
ERROR: Does a zone record for "example.com" exist?
4.1.4 Delete an Existing Zone Record for a Domain
To delete the existing zone record for example.com
and all its related DNS records, use the following code. Note that we need to provide the unique ID of the domain’s existing zone record:
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ ZONE_ID="8b717207bcee4047af2e9dff95832996"; \ curl -X DELETE "https://api.cloudflare.com/client/v4/zones/$ZONE_ID" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H "Content-Type: application/json" \ | python -m json.tool;
{ "errors": [], "messages": [], "result": { "id": "8b717207bcee4047af2e9dff95832996" }, "success": true }
{ "errors": [ { "code": 1001, "message": "Invalid zone identifier" } ], "messages": [], "result": null, "success": false }
Alternatively, to limit the data that is displayed use:
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ ZONE_ID="8b717207bcee4047af2e9dff95832996"; \ ALL="false"; \ curl -X DELETE "https://api.cloudflare.com/client/v4/zones/$ZONE_ID" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H "Content-Type: application/json" \ | if $ALL; then python -m json.tool; else python -c "import sys,json;data=json.loads(sys.stdin.read()); print('Zone for ID \"$ZONE_ID\" deleted.' if data['success'] else 'ERROR: ' + data['errors'][0]['message'])"; fi
Zone for ID 8b717207bcee4047af2e9dff95832996 deleted.
ERROR: Invalid zone identifier
4.2 CREATE NEW DNS RECORDS
4.2.1 Create a New DNS [A] Record for a Domain
To create a DNS record that points example.com
to the IP address 203.0.113.50
, use the following code:
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ ZONE_ID="8b717207bcee4047af2e9dff95832996"; \ TYPE="A"; \ NAME="example.com"; \ CONTENT="203.0.113.50"; \ PROXIED="true"; \ TTL="1"; \ curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H "Content-Type: application/json" \ --data '{"type":"'"$TYPE"'","name":"'"$NAME"'","content":"'"$CONTENT"'","proxied":'"$PROXIED"',"ttl":'"$TTL"'}' \ | python -m json.tool;
{ "errors": [], "messages": [], "result": { "content": "203.0.113.50", "created_on": "2018-01-27T15:57:52.254408Z", "id": "02a929c163302fe6ad885e77ad7bd268", "locked": false, "meta": { "auto_added": false, "managed_by_apps": false }, "modified_on": "2018-01-27T15:57:52.254408Z", "name": "example.com", "proxiable": true, "proxied": true, "ttl": 1, "type": "A", "zone_id": "8b717207bcee4047af2e9dff95832996", "zone_name": "example.com" }, "success": true }
{ "errors": [ { "code": 81057, "message": "The record already exists." } ], "messages": [], "result": null, "success": false }
Alternatively, to limit the data that is displayed use:
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ ZONE_ID="8b717207bcee4047af2e9dff95832996"; \ TYPE="A"; \ NAME="example.com"; \ CONTENT="203.0.113.50"; \ PROXIED="true"; \ TTL="1"; \ ALL="false"; \ curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H "Content-Type: application/json" \ --data '{"type":"'"$TYPE"'","name":"'"$NAME"'","content":"'"$CONTENT"'","proxied":'"$PROXIED"',"ttl":'"$TTL"'}' \ | if $ALL; then python -m json.tool; else python -c "import sys,json;data=json.loads(sys.stdin.read()); print('Type: ' + data['result']['type'] + '\n' + 'DNS ID: ' + data['result']['id'] if data['success'] else 'ERROR: ' + data['errors'][0]['message'])"; fi
Type: A DNS ID: 02a929c163302fe6ad885e77ad7bd268
ERROR: The record already exists.
The Cloudflare dashboard now shows:
4.2.2 Create a New DNS [A] Record for a Sub-domain
To create a DNS record that points sub-domain.example.com
to the IP address 203.0.113.50
, use the following code:
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ ZONE_ID="8b717207bcee4047af2e9dff95832996"; \ TYPE="A"; \ NAME="sub-domain"; \ CONTENT="203.0.113.50"; \ PROXIED="true"; \ TTL="1"; \ curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H "Content-Type: application/json" \ --data '{"type":"'"$TYPE"'","name":"'"$NAME"'","content":"'"$CONTENT"'","proxied":'"$PROXIED"',"ttl":'"$TTL"'}' \ | python -m json.tool;
{ "errors": [], "messages": [], "result": { "content": "203.0.113.50", "created_on": "2018-01-31T10:05:17.945648Z", "id": "1edaebfd2c02a69beec51da4476e743e", "locked": false, "meta": { "auto_added": false, "managed_by_apps": false }, "modified_on": "2018-01-31T10:05:17.945648Z", "name": "sub-domain.example.com", "proxiable": true, "proxied": true, "ttl": 1, "type": "A", "zone_id": "8b717207bcee4047af2e9dff95832996", "zone_name": "example.com" }, "success": true }
{ "errors": [ { "code": 81057, "message": "The record already exists." } ], "messages": [], "result": null, "success": false }
Alternatively, to limit the data that is displayed use:
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ ZONE_ID="8b717207bcee4047af2e9dff95832996"; \ TYPE="A"; \ NAME="sub-domain"; \ CONTENT="203.0.113.50"; \ PROXIED="true"; \ TTL="1"; \ ALL="false"; \ curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H "Content-Type: application/json" \ --data '{"type":"'"$TYPE"'","name":"'"$NAME"'","content":"'"$CONTENT"'","proxied":'"$PROXIED"',"ttl":'"$TTL"'}' \ | if $ALL; then python -m json.tool; else python -c "import sys,json;data=json.loads(sys.stdin.read()); print('Type: ' + data['result']['type'] + '\n' + 'DNS ID: ' + data['result']['id'] if data['success'] else 'ERROR: ' + data['errors'][0]['message'])"; fi
Type: A DNS ID: 1edaebfd2c02a69beec51da4476e743e
ERROR: The record already exists.
The Cloudflare dashboard now shows:
4.2.3 Create a New DNS [CNAME] Record for an Alias
To create a DNS record that makes www.example.com
an alias of example.com
, use the following code:
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ ZONE_ID="8b717207bcee4047af2e9dff95832996"; \ TYPE="CNAME"; \ NAME="www"; \ CONTENT="example.com"; \ PROXIED="true"; \ TTL="1"; \ curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H "Content-Type: application/json" \ --data '{"type":"'"$TYPE"'","name":"'"$NAME"'","content":"'"$CONTENT"'","proxied":'"$PROXIED"',"ttl":'"$TTL"'}' \ | python -m json.tool;
{ "errors": [], "messages": [], "result": { "content": "example.com", "created_on": "2018-01-31T10:27:57.075092Z", "id": "7bdb2e46037df332e5abdd45f8f981f5", "locked": false, "meta": { "auto_added": false, "managed_by_apps": false }, "modified_on": "2018-01-31T10:27:57.075092Z", "name": "www.example.com", "proxiable": true, "proxied": true, "ttl": 1, "type": "CNAME", "zone_id": "8b717207bcee4047af2e9dff95832996", "zone_name": "example.com" }, "success": true }
{ "errors": [ { "code": 81053, "message": "An A, AAAA or CNAME record already exists with that host." } ], "messages": [], "result": null, "success": false }
Alternatively, to limit the data that is displayed use:
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ ZONE_ID="8b717207bcee4047af2e9dff95832996"; \ TYPE="CNAME"; \ NAME="www"; \ CONTENT="example.com"; \ PROXIED="true"; \ TTL="1"; \ ALL="false"; \ curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H "Content-Type: application/json" \ --data '{"type":"'"$TYPE"'","name":"'"$NAME"'","content":"'"$CONTENT"'","proxied":'"$PROXIED"',"ttl":'"$TTL"'}' \ | if $ALL; then python -m json.tool; else python -c "import sys,json;data=json.loads(sys.stdin.read()); print('Type: ' + data['result']['type'] + '\n' + 'DNS ID: ' + data['result']['id'] if data['success'] else 'ERROR: ' + data['errors'][0]['message'])"; fi
Type: CNAME DNS ID: 7bdb2e46037df332e5abdd45f8f981f5
ERROR: An A, AAAA or CNAME record already exists with that host.
The Cloudflare dashboard now shows:
4.2.4 Create a New DNS [MX] Record for a Domain
To create a DNS record that specifies the primary mail server to handle mail for example.com
, use the following code:
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ ZONE_ID="8b717207bcee4047af2e9dff95832996"; \ TYPE="MX"; \ NAME="@"; \ CONTENT="aspmx.l.google.com"; \ PRIORITY="1"; \ TTL="1"; \ curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H "Content-Type: application/json" \ --data '{"type":"'"$TYPE"'","name":"'"$NAME"'","content":"'"$CONTENT"'","priority":'"$PRIORITY"',"ttl":'"$TTL"'}' \ | python -m json.tool;
{ "errors": [], "messages": [], "result": { "content": "aspmx.l.google.com", "created_on": "2018-01-31T10:36:15.396025Z", "id": "4983f68556095761d8f76af09f48b093", "locked": false, "meta": { "auto_added": false, "managed_by_apps": false }, "modified_on": "2018-01-31T10:36:15.396025Z", "name": "example.com", "priority": 1, "proxiable": false, "proxied": false, "ttl": 1, "type": "MX", "zone_id": "8b717207bcee4047af2e9dff95832996", "zone_name": "example.com" }, "success": true }
{ "errors": [ { "code": 81057, "message": "The record already exists." } ], "messages": [], "result": null, "success": false }
Alternatively, to limit the data that is displayed use:
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ ZONE_ID="8b717207bcee4047af2e9dff95832996"; \ TYPE="MX"; \ NAME="@"; \ CONTENT="aspmx.l.google.com"; \ PRIORITY="1"; \ TTL="1"; \ ALL="false"; \ curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H "Content-Type: application/json" \ --data '{"type":"'"$TYPE"'","name":"'"$NAME"'","content":"'"$CONTENT"'","priority":'"$PRIORITY"',"ttl":'"$TTL"'}' \ | if $ALL; then python -m json.tool; else python -c "import sys,json;data=json.loads(sys.stdin.read()); print('Type: ' + data['result']['type'] + '\n' + 'DNS ID: ' + data['result']['id'] if data['success'] else 'ERROR: ' + data['errors'][0]['message'])"; fi
Type: MX DNS ID: 4983f68556095761d8f76af09f48b093
ERROR: The record already exists.
The Cloudflare dashboard now shows:
4.2.5 Create a Second New DNS [MX] Record for a Domain
To create a DNS record that specifies the secondary mail server to handle mail for example.com
, use the following code:
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ ZONE_ID="8b717207bcee4047af2e9dff95832996"; \ TYPE="MX"; \ NAME="@"; \ CONTENT="alt1.aspmx.l.google.com"; \ PRIORITY="5"; \ TTL="1"; \ curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H "Content-Type: application/json" \ --data '{"type":"'"$TYPE"'","name":"'"$NAME"'","content":"'"$CONTENT"'","priority":'"$PRIORITY"',"ttl":'"$TTL"'}' \ | python -m json.tool;
{ "errors": [], "messages": [], "result": { "content": "alt1.aspmx.l.google.com", "created_on": "2018-01-31T11:05:36.960561Z", "id": "6b21db8d6a20c0011971d4ec2c3b8445", "locked": false, "meta": { "auto_added": false, "managed_by_apps": false }, "modified_on": "2018-01-31T11:05:36.960561Z", "name": "example.com", "priority": 1, "proxiable": false, "proxied": false, "ttl": 1, "type": "MX", "zone_id": "8b717207bcee4047af2e9dff95832996", "zone_name": "example.com" }, "success": true }
{ "errors": [ { "code": 81057, "message": "The record already exists." } ], "messages": [], "result": null, "success": false }
Alternatively, to limit the data that is displayed use:
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ ZONE_ID="8b717207bcee4047af2e9dff95832996"; \ TYPE="MX"; \ NAME="@"; \ CONTENT="alt1.aspmx.l.google.com"; \ PRIORITY="5"; \ TTL="1"; \ ALL="false"; \ curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H "Content-Type: application/json" \ --data '{"type":"'"$TYPE"'","name":"'"$NAME"'","content":"'"$CONTENT"'","priority":'"$PRIORITY"',"ttl":'"$TTL"'}' \ | if $ALL; then python -m json.tool; else python -c "import sys,json;data=json.loads(sys.stdin.read()); print('Type: ' + data['result']['type'] + '\n' + 'DNS ID: ' + data['result']['id'] if data['success'] else 'ERROR: ' + data['errors'][0]['message'])"; fi
Type: MX DNS ID: 6b21db8d6a20c0011971d4ec2c3b8445
ERROR: The record already exists.
The Cloudflare dashboard now shows:
4.2.6 Create a New DNS [TXT] Record
To create a DNS record that specifies the sender policy framework (SPF) for example.com
, use the following code:
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ ZONE_ID="8b717207bcee4047af2e9dff95832996"; \ TYPE="TXT"; \ NAME="@"; \ CONTENT="v=spf1 include:_spf.google.com ~all"; \ TTL="1"; \ curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H "Content-Type: application/json" \ --data '{"type":"'"$TYPE"'","name":"'"$NAME"'","content":"'"$CONTENT"'","ttl":'"$TTL"'}' \ | python -m json.tool;
{ "errors": [], "messages": [], "result": { "content": "v=spf1 include:_spf.google.com ~all", "created_on": "2018-01-31T11:13:04.971069Z", "id": "3c90b59fca40473f26d8edf4c7e5fdb1", "locked": false, "meta": { "auto_added": false, "managed_by_apps": false }, "modified_on": "2018-01-31T11:13:04.971069Z", "name": "example.com", "proxiable": false, "proxied": false, "ttl": 1, "type": "TXT", "zone_id": "8b717207bcee4047af2e9dff95832996", "zone_name": "example.com" }, "success": true }
{ "errors": [ { "code": 81057, "message": "The record already exists." } ], "messages": [], "result": null, "success": false }
Alternatively, to limit the data that is displayed use:
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ ZONE_ID="8b717207bcee4047af2e9dff95832996"; \ TYPE="TXT"; \ NAME="@"; \ CONTENT="v=spf1 include:_spf.google.com ~all"; \ TTL="1"; \ ALL="false"; \ curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H "Content-Type: application/json" \ --data '{"type":"'"$TYPE"'","name":"'"$NAME"'","content":"'"$CONTENT"'","ttl":'"$TTL"'}' \ | if $ALL; then python -m json.tool; else python -c "import sys,json;data=json.loads(sys.stdin.read()); print('Type: ' + data['result']['type'] + '\n' + 'DNS ID: ' + data['result']['id'] if data['success'] else 'ERROR: ' + data['errors'][0]['message'])"; fi
Type: TXT DNS ID: 3c90b59fca40473f26d8edf4c7e5fdb1
ERROR: The record already exists.
The Cloudflare dashboard now shows:
4.3. LIST, UPDATE & DELETE EXISTING DNS RECORDS
4.3.1 List All DNS Records for a Zone
To list all the DNS records associated with the zone record for example.com
, use the following code:
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ ZONE_ID="8b717207bcee4047af2e9dff95832996"; \ curl -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H "Content-Type: application/json" \ | python -m json.tool;
{ "errors": [], "messages": [], "result": [ { "content": "203.0.113.50", "created_on": "2018-02-09T08:40:30.673141Z", "id": "02a929c163302fe6ad885e77ad7bd268", "locked": false, "meta": { "auto_added": false, "managed_by_apps": false }, "modified_on": "2018-02-09T08:40:30.673141Z", "name": "example.com", "proxiable": true, "proxied": true, "ttl": 1, "type": "A", "zone_id": "8b717207bcee4047af2e9dff95832996", "zone_name": "example.com" }, { "content": "203.0.113.50", "created_on": "2018-02-09T08:43:22.134574Z", "id": "1edaebfd2c02a69beec51da4476e743e", "locked": false, "meta": { "auto_added": false, "managed_by_apps": false }, "modified_on": "2018-02-09T08:43:22.134574Z", "name": "sub-domain.example.com", "proxiable": true, "proxied": true, "ttl": 1, "type": "A", "zone_id": "8b717207bcee4047af2e9dff95832996", "zone_name": "example.com" }, { "content": "example.com", "created_on": "2018-02-09T08:44:10.505243Z", "id": "7bdb2e46037df332e5abdd45f8f981f5", "locked": false, "meta": { "auto_added": false, "managed_by_apps": false }, "modified_on": "2018-02-09T08:44:10.505243Z", "name": "www.example.com", "proxiable": true, "proxied": true, "ttl": 1, "type": "CNAME", "zone_id": "8b717207bcee4047af2e9dff95832996", "zone_name": "example.com" }, { "content": "alt1.aspmx.l.google.com", "created_on": "2018-02-09T08:47:23.832766Z", "id": "6b21db8d6a20c0011971d4ec2c3b8445", "locked": false, "meta": { "auto_added": false, "managed_by_apps": false }, "modified_on": "2018-02-09T08:47:23.832766Z", "name": "example.com", "priority": 5, "proxiable": false, "proxied": false, "ttl": 1, "type": "MX", "zone_id": "8b717207bcee4047af2e9dff95832996", "zone_name": "example.com" }, { "content": "aspmx.l.google.com", "created_on": "2018-02-09T08:46:28.139571Z", "id": "4983f68556095761d8f76af09f48b093", "locked": false, "meta": { "auto_added": false, "managed_by_apps": false }, "modified_on": "2018-02-09T08:46:28.139571Z", "name": "example.com", "priority": 1, "proxiable": false, "proxied": false, "ttl": 1, "type": "MX", "zone_id": "8b717207bcee4047af2e9dff95832996", "zone_name": "example.com" }, { "content": "v=spf1 include:_spf.google.com ~all", "created_on": "2018-02-09T08:48:36.208222Z", "id": "3c90b59fca40473f26d8edf4c7e5fdb1", "locked": false, "meta": { "auto_added": false, "managed_by_apps": false }, "modified_on": "2018-02-09T08:48:36.208222Z", "name": "example.com", "proxiable": false, "proxied": false, "ttl": 1, "type": "TXT", "zone_id": "8b717207bcee4047af2e9dff95832996", "zone_name": "example.com" } ], "result_info": { "count": 6, "page": 1, "per_page": 20, "total_count": 6, "total_pages": 1 }, "success": true }
{ "errors": [], "messages": [], "result": [], "result_info": { "count": 0, "page": 1, "per_page": 20, "total_count": 0, "total_pages": 0 }, "success": true }
A far better alternative perhaps is to use the code below which limits the output to specific data and is useful if you need to quickly get the ID of an existing DNS record in order to update or delete it.
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ ZONE_ID="8b717207bcee4047af2e9dff95832996"; \ curl -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H 'Content-Type: application/json' \ | python -c $'import sys,json\ndata=json.loads(sys.stdin.read())\nif data["success"]:\n\tfor dict in data["result"]:print("ID: " + dict["id"] + ", Type: " + dict["type"] + ", " + "Name: " + dict["name"] + ", " + "Content: " + dict["content"])\nelse:print("ERROR(" + str(data["errors"][0]["code"]) + "): " + data["errors"][0]["message"])'
ID: 02a929c163302fe6ad885e77ad7bd268, Type: A, Name: example.com, Content: 203.0.113.50 ID: 1edaebfd2c02a69beec51da4476e743e, Type: A, Name: sub-domain.example.com, Content: 203.0.113.50 ID: 7bdb2e46037df332e5abdd45f8f981f5, Type: CNAME, Name: www.example.com, Content: example.com ID: 6b21db8d6a20c0011971d4ec2c3b8445, Type: MX, Name: example.com, Content: alt1.aspmx.l.google.com ID: 4983f68556095761d8f76af09f48b093, Type: MX, Name: example.com, Content: aspmx.l.google.com ID: 3c90b59fca40473f26d8edf4c7e5fdb1, Type: TXT, Name: example.com, Content: v=spf1 include:_spf.google.com ~all
ERROR(10000): Authentication error
4.3.2 List DNS Records for a Zone Based on DNS Record Name
To list all the DNS records associated with the zone record for example.com
whose name is example.com
, use the following code:
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ ZONE_ID="8b717207bcee4047af2e9dff95832996"; \ NAME="example.com"; \ curl -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records?name=$NAME" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H "Content-Type: application/json" \ | python -m json.tool;
{ "errors": [], "messages": [], "result": [ { "content": "203.0.113.50", "created_on": "2018-02-09T08:40:30.673141Z", "id": "02a929c163302fe6ad885e77ad7bd268", "locked": false, "meta": { "auto_added": false, "managed_by_apps": false }, "modified_on": "2018-02-09T08:40:30.673141Z", "name": "example.com", "proxiable": true, "proxied": true, "ttl": 1, "type": "A", "zone_id": "8b717207bcee4047af2e9dff95832996", "zone_name": "example.com" }, { "content": "alt1.aspmx.l.google.com", "created_on": "2018-02-09T08:47:23.832766Z", "id": "6b21db8d6a20c0011971d4ec2c3b8445", "locked": false, "meta": { "auto_added": false, "managed_by_apps": false }, "modified_on": "2018-02-09T08:47:23.832766Z", "name": "example.com", "priority": 5, "proxiable": false, "proxied": false, "ttl": 1, "type": "MX", "zone_id": "8b717207bcee4047af2e9dff95832996", "zone_name": "example.com" }, { "content": "aspmx.l.google.com", "created_on": "2018-02-09T08:46:28.139571Z", "id": "4983f68556095761d8f76af09f48b093", "locked": false, "meta": { "auto_added": false, "managed_by_apps": false }, "modified_on": "2018-02-09T08:46:28.139571Z", "name": "example.com", "priority": 1, "proxiable": false, "proxied": false, "ttl": 1, "type": "MX", "zone_id": "8b717207bcee4047af2e9dff95832996", "zone_name": "example.com" }, { "content": "v=spf1 include:_spf.google.com ~all", "created_on": "2018-02-09T08:48:36.208222Z", "id": "3c90b59fca40473f26d8edf4c7e5fdb1", "locked": false, "meta": { "auto_added": false, "managed_by_apps": false }, "modified_on": "2018-02-09T08:48:36.208222Z", "name": "example.com", "proxiable": false, "proxied": false, "ttl": 1, "type": "TXT", "zone_id": "8b717207bcee4047af2e9dff95832996", "zone_name": "example.com" } ], "result_info": { "count": 4, "page": 1, "per_page": 20, "total_count": 4, "total_pages": 1 }, "success": true }
{ "errors": [], "messages": [], "result": [], "result_info": { "count": 0, "page": 1, "per_page": 20, "total_count": 0, "total_pages": 0 }, "success": true }
4.3.3 List DNS Records for a Zone Based on DNS Record Type
To list all the DNS records associated with the zone record for example.com
whose type is MX
, use the following code:
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ ZONE_ID="8b717207bcee4047af2e9dff95832996"; \ TYPE="MX"; \ curl -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records?type=$TYPE" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H "Content-Type: application/json" \ | python -m json.tool;
{ "errors": [], "messages": [], "result": [ { "content": "alt1.aspmx.l.google.com", "created_on": "2018-02-09T10:55:50.545902Z", "id": "6b21db8d6a20c0011971d4ec2c3b8445", "locked": false, "meta": { "auto_added": false, "managed_by_apps": false }, "modified_on": "2018-02-09T10:55:50.545902Z", "name": "example.com", "priority": 5, "proxiable": false, "proxied": false, "ttl": 1, "type": "MX", "zone_id": "8b717207bcee4047af2e9dff95832996", "zone_name": "example.com" }, { "content": "aspmx.l.google.com", "created_on": "2018-02-09T10:55:01.615968Z", "id": "4983f68556095761d8f76af09f48b093", "locked": false, "meta": { "auto_added": false, "managed_by_apps": false }, "modified_on": "2018-02-09T10:55:01.615968Z", "name": "example.com", "priority": 1, "proxiable": false, "proxied": false, "ttl": 1, "type": "MX", "zone_id": "8b717207bcee4047af2e9dff95832996", "zone_name": "example.com" } ], "result_info": { "count": 2, "page": 1, "per_page": 20, "total_count": 2, "total_pages": 1 }, "success": true }
{ "errors": [], "messages": [], "result": [], "result_info": { "count": 0, "page": 1, "per_page": 20, "total_count": 0, "total_pages": 0 }, "success": true }
4.3.4 List DNS Records for a Zone Based on DNS Record Name and Type
To list all the DNS records associated with the zone record for example.com
whose name is example.com
and type is MX
, use the following code:
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ ZONE_ID="8b717207bcee4047af2e9dff95832996"; \ NAME="example.com"; \ TYPE="MX"; \ curl -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records?name=$NAME&type=$TYPE" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H "Content-Type: application/json" \ | python -m json.tool;
{ "errors": [], "messages": [], "result": [ { "content": "alt1.aspmx.l.google.com", "created_on": "2018-02-09T08:47:23.832766Z", "id": "ec3045d58f0cde044d73198af3dc77f4", "locked": false, "meta": { "auto_added": false, "managed_by_apps": false }, "modified_on": "2018-02-09T08:47:23.832766Z", "name": "dummy.com", "priority": 5, "proxiable": false, "proxied": false, "ttl": 1, "type": "MX", "zone_id": "8b717207bcee4047af2e9dff95832996", "zone_name": "dummy.com" }, { "content": "aspmx.l.google.com", "created_on": "2018-02-09T08:46:28.139571Z", "id": "cab6d9fa24a3946530f0c1868d83bf8d", "locked": false, "meta": { "auto_added": false, "managed_by_apps": false }, "modified_on": "2018-02-09T08:46:28.139571Z", "name": "dummy.com", "priority": 1, "proxiable": false, "proxied": false, "ttl": 1, "type": "MX", "zone_id": "8b717207bcee4047af2e9dff95832996", "zone_name": "dummy.com" } ], "result_info": { "count": 2, "page": 1, "per_page": 20, "total_count": 2, "total_pages": 1 }, "success": true }
{ "errors": [], "messages": [], "result": [], "result_info": { "count": 0, "page": 1, "per_page": 20, "total_count": 0, "total_pages": 0 }, "success": true }
4.3.5 Update an Individual DNS Record
To update an individual DNS record we need to pass its unique ID to the Cloudflare API. So, to update the CNAME record for www.example.com
so that PROXIED
is changed to false and TTL
is changed to 2 minutes, use the following code. Note that even though TYPE
, NAME
and CONTENT
are not changing, they still need to be included otherwise the Cloudflare API returns an error:
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ ZONE_ID="8b717207bcee4047af2e9dff95832996"; \ DNS_ID="7bdb2e46037df332e5abdd45f8f981f5"; \ TYPE="CNAME"; \ NAME="www"; \ CONTENT="example.com"; \ PROXIED="false"; \ TTL="120";\ curl -X PUT "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$DNS_ID" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H "Content-Type: application/json" \ --data '{"type":"'"$TYPE"'","name":"'"$NAME"'","content":"'"$CONTENT"'","proxied":'"$PROXIED"',"ttl":'"$TTL"'}' \ | python -m json.tool;
{ "errors": [], "messages": [], "result": { "content": "example.com", "created_on": "2018-02-09T09:58:05.239777Z", "id": "7bdb2e46037df332e5abdd45f8f981f5", "locked": false, "meta": { "auto_added": false, "managed_by_apps": false }, "modified_on": "2018-02-09T09:58:05.239777Z", "name": "www.example.com", "proxiable": true, "proxied": false, "ttl": 120, "type": "CNAME", "zone_id": "8b717207bcee4047af2e9dff95832996", "zone_name": "example.com" }, "success": true }
{ "errors": [ { "code": 1020, "message": "Invalid DNS record identifier" } ], "messages": [], "result": null, "success": false }
4.3.6 Delete an Individual DNS Record
To delete an individual DNS record associated with the zone record for example.com
, use the following code. Note thet the DNS record’s unique ID needs to be included:
EMAIL="steve@example.com"; \ KEY="08n46q4ofo0v5pc3u3g3eu517o69axu8s6ml4"; \ ZONE_ID="8b717207bcee4047af2e9dff95832996"; \ DNS_ID="7bdb2e46037df332e5abdd45f8f981f5"; \ curl -X DELETE "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$DNS_ID" \ -H "X-Auth-Email: $EMAIL" \ -H "X-Auth-Key: $KEY" \ -H "Content-Type: application/json" \ | python -m json.tool;
{ "errors": [], "messages": [], "result": { "id": "7bdb2e46037df332e5abdd45f8f981f5" }, "success": true }
{ "errors": [ { "code": 1032, "message": "Invalid DNS record identifier" } ], "messages": [], "result": null, "success": false }
Thank you much!
I want to use it with cron. How can i update record without promt where i press “1” button?
Hi Dmitrii,
See my reply to you on GitHub.
Regards, Steve.
is there a way to list dns records from cloudflare using its API not using curl, in php, jquery or javascript?
if possible with example pls. Thanks
Hi Khasan,
The get-dns.py script on the cloudflare-dns repo’s develop branch uses the Python requests library to access the Cloudflare API, but I’ve no experience using PHP, jQuery or JavaScript to do so.
Regards, Steve.
thanks for reply, take a look at this link https://developers.cloudflare.com/api/operations/dns-records-for-a-zone-list-dns-records.
Here is given examples how to use with javascript, jquery but i could not fetch the records according to example. May be anyone could help me. Thanks again.
Hi Khasan,
I tried the XMLHttpRequest and fetch examples but ran into issues with CORS. With fetch I included mode: no-cors, which resulted in an HTTP 400 error.
Regards, Steve
And where is the example of deleting all DNS records?
Hi Serhii,
As far as I’m aware there is no single API call to delete all DNS records for a domain. You could first delete the domain’s zone record and then re-create it. I assume it’ll have the same affect as you’re trying to achieve, but you’ll also lose all of the Cloudflare configuration settings for the domain.
Regards, Steve.
4.3.1 List All DNS Records for a Zone
Check and update the code for the alternative example. The output success tab is correct, but the code tab is wrong.
Should be
| python3.8 -c $’import sys,json\ndata=json.loads(sys.stdin.read())\n\
if data[“success”]:\n\tfor dict in data[“result”]:\
print(“ID: ” + dict[“id”] + “, Type: ” + dict[“type”] + “, ” + \
“Name: ” + dict[“name”] + “, ” + “Content: ” + dict[“content”])\n\
else:print(“ERROR(” + str(data[“errors”][0][“code”]) + “): ” + data[“errors”][0]
[“message”])’
Much nicer scripting examples here than the cloudflare API site.
Thanks for spotting that Bill and bringing it to my attention. Have made the necessary correction.
Regards, Steve.
Thanks a lot Steven!
I was thinking CloudFlare API is something difficult, but it was so easy to add a bunch of domains using API and a simple bash script.
The power of automation!
Sir, plz tell me how to get zone id of a domain and then update dns records. My output is coming like this when i rquest zone id:
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1790 0 1790 0 0 3572 0 –:–:– –:–:– –:–:– 3572
ZONE_ID: 403f83180ec13138ab591ceff04adccb
@Anantha Raman
You need the domain’s zone_id 4.1.2 List an Existing Zone Record for a Domain and the (dns_)id of the DNS record you want to update 4.3.2 List DNS Records for a Zone Based on DNS Record Name. Once you have these you can use them to update that DNS record 4.3.5 Update an Individual DNS Record.
Regards, Steve.