TL;DR
Cloudflare APIs let you manage DNS, zones, Workers, security, and analytics programmatically. Authenticate with API tokens (recommended) or global keys, call api.cloudflare.com/client/v4, and handle rate limits gracefully. For testing, use Apidog to validate DNS changes, test Worker deployments, and automate configuration across environments.
Introduction
Cloudflare sits in front of millions of websites and provides DNS, CDN, DDoS protection, WAF, Workers serverless functions, and more. The dashboard is useful for small setups, but production environments need repeatable automation.
The Cloudflare API exposes the same core configuration areas programmatically. You can create zones, update DNS records, configure page rules, deploy Workers, manage SSL settings, and pull analytics.
Common API use cases include:
- Infrastructure as code with Terraform or Pulumi
- CI/CD pipeline integration
- Multi-zone management
- Automated DNS updates
- Worker deployments
Apidog can help you test API calls, validate responses, and document your integration. Save zone configurations as reusable requests and share them with your team.
By the end of this guide, you will be able to:
- Authenticate with Cloudflare API tokens
- Manage zones and DNS records
- Deploy and manage Workers
- Configure security settings
- Pull analytics and logs
Authentication
Cloudflare supports two authentication methods. Prefer API tokens over global API keys.
Method 1: API tokens (recommended)
API tokens are scoped to specific permissions. If a token is compromised, the impact is limited to the permissions and resources assigned to it.
Create a token:
- Open Cloudflare Dashboard → My Profile → API Tokens.
- Select Create Token.
- Choose a template, such as DNS editing or Workers deployment, or create a custom token.
- Scope the token to specific zones or accounts where possible.
- Copy the token and store it securely.
Verify a token before using it in automation:
curl -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \
-H "Authorization: Bearer YOUR_API_TOKEN"
Method 2: Global API key (not recommended)
A global API key has full account access. Avoid using it in scripts, CI/CD pipelines, or shared environments.
curl -X GET "https://api.cloudflare.com/client/v4/user" \
-H "X-Auth-Email: your-email@example.com" \
-H "X-Auth-Key: YOUR_GLOBAL_API_KEY"
Response format
Cloudflare API responses use this structure:
{
"result": {},
"success": true,
"errors": [],
"messages": []
}
Check success and errors before using result in your automation.
Zone management
A Cloudflare zone represents a domain managed by Cloudflare.
List zones
Use this request to find zone IDs and confirm token access:
curl -X GET "https://api.cloudflare.com/client/v4/zones" \
-H "Authorization: Bearer YOUR_API_TOKEN"
Example response:
{
"result": [
{
"id": "023e105f4ecef8ad9ca31a8372d0c353",
"name": "example.com",
"status": "active",
"paused": false,
"type": "full",
"development_mode": 0,
"name_servers": [
"ns1.cloudflare.com",
"ns2.cloudflare.com"
],
"original_name_servers": [
"ns1.example.com"
],
"original_registrar": null
}
],
"success": true
}
Save the id value as ZONE_ID for subsequent requests.
Create a zone
Create a zone by providing the domain and Cloudflare account ID:
curl -X POST "https://api.cloudflare.com/client/v4/zones" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "newdomain.com",
"account": {
"id": "ACCOUNT_ID"
},
"type": "full"
}'
Get zone details
Retrieve a zone directly when you already know its ID:
curl -X GET "https://api.cloudflare.com/client/v4/zones/ZONE_ID" \
-H "Authorization: Bearer YOUR_API_TOKEN"
DNS record management
DNS records map hostnames to IP addresses and services.
List DNS records
Start by listing records so you can identify the RECORD_ID needed for updates and deletes:
curl -X GET "https://api.cloudflare.com/client/v4/zones/ZONE_ID/dns_records" \
-H "Authorization: Bearer YOUR_API_TOKEN"
Create a DNS record
Create a proxied A record for www.example.com:
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/dns_records" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "A",
"name": "www",
"content": "192.0.2.1",
"ttl": 3600,
"proxied": true
}'
Common DNS record types:
-
A— IPv4 address -
AAAA— IPv6 address -
CNAME— Alias to another domain -
MX— Mail server -
TXT— Text records such as SPF, DKIM, and domain verification -
NS— Name server
Update a DNS record
Use PUT with the existing record ID to replace a record configuration:
curl -X PUT "https://api.cloudflare.com/client/v4/zones/ZONE_ID/dns_records/RECORD_ID" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "A",
"name": "www",
"content": "192.0.2.2",
"ttl": 3600,
"proxied": true
}'
Delete a DNS record
Delete a record only after confirming its ID:
curl -X DELETE "https://api.cloudflare.com/client/v4/zones/ZONE_ID/dns_records/RECORD_ID" \
-H "Authorization: Bearer YOUR_API_TOKEN"
Cloudflare Workers
Workers run JavaScript at the edge, close to users.
List Workers
List scripts deployed in an account:
curl -X GET "https://api.cloudflare.com/client/v4/accounts/ACCOUNT_ID/workers/scripts" \
-H "Authorization: Bearer YOUR_API_TOKEN"
Upload a Worker
Upload a Worker script from a local worker.js file:
curl -X PUT "https://api.cloudflare.com/client/v4/accounts/ACCOUNT_ID/workers/scripts/my-worker" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/javascript" \
--data-binary @worker.js
Example worker.js:
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url)
if (url.pathname === "/api/hello") {
return new Response(JSON.stringify({ message: "Hello from the edge!" }), {
headers: { "Content-Type": "application/json" }
})
}
return fetch(request)
}
}
Bind a route
Attach the Worker to a route in a zone:
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/workers/routes" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"pattern": "example.com/api/*",
"script": "my-worker"
}'
Create a Worker KV namespace
Create a KV namespace for data accessible from Workers:
curl -X POST "https://api.cloudflare.com/client/v4/accounts/ACCOUNT_ID/storage/kv/namespaces" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "my-kv-namespace"
}'
Security and WAF
Use the API to apply security and caching configuration consistently across zones.
Create a page rule
This page rule enables flexible SSL and aggressive caching for matching URLs:
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/pagerules" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"targets": [
{
"target": "url",
"constraint": {
"operator": "matches",
"value": "example.com/*"
}
}
],
"actions": [
{
"id": "ssl",
"value": "flexible"
},
{
"id": "cache_level",
"value": "aggressive"
}
]
}'
Create a firewall rule
This example blocks requests from China:
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/firewall/rules" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"filter": {
"expression": "ip.geoip.country eq \"CN\"",
"paused": false
},
"action": "block",
"description": "Block traffic from China"
}'
Create a rate limit
This rule limits POST requests to /api/*:
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/rate_limits" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"disabled": false,
"description": "Rate limit API endpoints",
"match": {
"request": {
"methods": ["POST"],
"url_pattern": "*/api/*"
}
},
"threshold": 100,
"period": 60,
"action": {
"mode": "ban",
"timeout": 600
}
}'
Analytics and logs
Retrieve zone analytics
Fetch dashboard analytics for the previous 24 hours:
curl -X GET "https://api.cloudflare.com/client/v4/zones/ZONE_ID/analytics/dashboard?since=-1440&continuous=true" \
-H "Authorization: Bearer YOUR_API_TOKEN"
Example response:
{
"result": {
"totals": {
"requests": {
"all": 1000000,
"cached": 800000,
"uncached": 200000
},
"bandwidth": {
"all": 50000000000,
"cached": 40000000000
},
"threats": {
"all": 5000
},
"pageviews": {
"all": 250000
}
}
}
}
Enable zone logs with Logpush
Configure Logpush to send HTTP request logs to storage:
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/logpush/jobs" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "My Logpush Job",
"destination_conf": "s3://my-bucket/logs?region=us-east-1",
"dataset": "http_requests",
"logpull_options": "fields=ClientIP,ClientRequestPath,EdgeResponseStatus×tamps=rfc3339"
}'
Testing with Apidog
Cloudflare changes can affect production traffic. Test requests, permissions, and response handling before applying configuration changes.
1. Configure an environment
Create an environment and keep IDs and tokens out of individual requests:
CLOUDFLARE_API_TOKEN: your_token
CLOUDFLARE_ACCOUNT_ID: abc123
ZONE_ID: xyz789
BASE_URL: https://api.cloudflare.com/client/v4
Use variables in requests:
{{BASE_URL}}/zones/{{ZONE_ID}}/dns_records
Set the authorization header:
Authorization: Bearer {{CLOUDFLARE_API_TOKEN}}
2. Validate API responses
Add tests to ensure Cloudflare returns a successful response and no errors:
pm.test("Request was successful", () => {
const response = pm.response.json()
pm.expect(response.success).to.be.true
pm.expect(response.errors).to.be.empty
})
For a DNS record creation request, verify the properties your deployment expects:
pm.test("DNS record created correctly", () => {
const response = pm.response.json()
pm.expect(response.result.type).to.eql("A")
pm.expect(response.result.name).to.eql("www")
pm.expect(response.result.proxied).to.be.true
})
3. Test Worker deployments
Save Worker scripts as files in Apidog and test upload responses:
pm.test("Worker uploaded", () => {
const response = pm.response.json()
pm.expect(response.result.id).to.eql("my-worker")
})
Common errors and fixes
403 Forbidden
Cause: The token does not have the required permission.
Fix: Review token permissions in the Cloudflare dashboard. DNS edits need Zone:DNS:Edit. Workers need Account:Workers:Edit.
1003: Invalid or missing zone
Cause: The zone ID does not exist, or the token cannot access it.
Fix: Verify the zone ID in the request URL and confirm that the token scope includes the zone.
81057: Record already exists
Cause: A DNS record with the same name and type already exists.
Fix: Use PUT to update the existing record, or delete the record before creating a replacement.
Rate limit exceeded
Cause: Too many requests. The default limit is 1200 requests per five minutes.
Fix: Batch operations, add delays, and retry 429 responses with backoff.
async function updateRecords(records) {
for (const record of records) {
try {
await updateRecord(record)
await sleep(100) // Rate limit buffer
} catch (error) {
if (error.status === 429) {
await sleep(60000) // Wait a minute
await updateRecord(record) // Retry
}
}
}
}
Alternatives and comparisons
| Feature | Cloudflare | AWS Route 53 | Fastly |
|---|---|---|---|
| DNS API | ✓ | ✓ | ✓ |
| CDN API | ✓ | CloudFront API | ✓ |
| Edge functions | Workers | Lambda@Edge | Compute@Edge |
| WAF API | ✓ | AWS WAF | ✓ |
| Free tier | Generous | Pay per use | Limited |
| Response format | JSON | XML/JSON | JSON |
Cloudflare’s API is more unified than AWS’s fragmented services. Workers provide more flexibility than Lambda@Edge.
Real-world use cases
Multi-tenant SaaS
A platform creates Cloudflare zones automatically when customers add custom domains. Workers handle routing, DNS records are created through the API, and SSL certificates provision automatically.
Blue-green deployments
An engineering team uses DNS record updates to switch traffic between environments. The API updates A records during deployment, with propagation through Cloudflare’s network.
DDoS response automation
A security team monitors traffic through the analytics API. When attack patterns emerge, firewall rules are added through the API to block malicious IPs and reduce response time.
Wrapping up
You can use the Cloudflare API to:
- Authenticate with scoped API tokens
- Manage zones and DNS records programmatically
- Deploy Workers for edge computing
- Configure firewall rules and rate limiting
- Pull analytics and configure log shipping
- Test changes with Apidog before applying them to production
FAQ
What’s the difference between a zone and a domain?
A zone is Cloudflare’s representation of a domain. When you add a domain to Cloudflare, you create a zone. API requests for that domain use its zone ID.
How do I find my zone ID?
Go to Cloudflare Dashboard → select your domain → Overview, then scroll to the API section. The zone ID is displayed there.
Can I use the Cloudflare API without a paid plan?
Yes. Most API features work on free plans. Workers have a generous free tier. Some advanced features, including advanced WAF rules and Logpush, require paid plans.
How long do DNS changes take?
Changes made through the API are immediate in Cloudflare’s system. Propagation to Cloudflare nameservers takes seconds. Global propagation depends on TTL and recursive resolvers, typically taking minutes.
What’s the rate limit?
The default is 1200 requests per five minutes per token. Check the X-RateLimit-Remaining header. Enterprise plans have higher limits.
Can I manage multiple accounts with one token?
No. Tokens are scoped to one account. For multiple accounts, create separate tokens or use user-level tokens with access to multiple accounts.
How do Workers differ from Lambda?
Workers run at Cloudflare edge locations, not in specific regions. Cold starts are minimal. They are suited to request and response manipulation rather than long-running processes.
Can I use the API to purge cache?
Yes. Purge specific files with this request:
bash
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/purge_cache" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"files": ["https://example.com/style.css"]
}'

Top comments (0)