
Cloudflare Api
- 846 installs
- 946 repo stars
- Updated July 2, 2026
- jezweb/claude-skills
cloudflare-api is a Claude agent skill that documents REST API patterns for Cloudflare developer platform services for developers who need bulk operations, cross-service queries, and automation beyond what Wrangler CLI e
About
cloudflare-api is a skill from jezweb/claude-skills cataloging REST API patterns for Cloudflare's developer platform: D1 SQL databases, R2 object storage, KV, Workers, Vectorize, Queues, and Durable Objects. All endpoints use the https://api.cloudflare.com/client/v4/accounts/{account_id}/ base path with Bearer token authorization. The skill complements Wrangler by covering bulk database listing, SQL queries, cross-database operations, and automation scripts Wrangler does not surface. Developers reach for cloudflare-api when writing curl-based ops, CI automation, or multi-service Cloudflare scripts that need direct API access across D1, R2, KV, Workers, Vectorize, Queues, and Durable Objects.
- REST API patterns for D1, R2, KV, Workers, Vectorize, Queues and Durable Objects
- Direct SQL querying and batch operations on D1 databases via API
- Parameterized queries that prevent SQL injection
- Bulk and automation scripts beyond Wrangler CLI capabilities
- All calls use official https://api.cloudflare.com/client/v4/accounts/{account_id} base path
Cloudflare Api by the numbers
- 846 all-time installs (skills.sh)
- +25 installs in the week ending Jul 29, 2026 (Skillselion tracking)
- Ranked #465 of 4,353 Backend & APIs skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Jul 31, 2026 (Skillselion catalog sync)
npx skills add https://github.com/jezweb/claude-skills --skill cloudflare-apiAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 846 |
|---|---|
| repo stars | ★ 946 |
| Security audit | 3 / 3 scanners passed |
| Last updated | July 2, 2026 |
| Repository | jezweb/claude-skills ↗ |
How do you automate Cloudflare APIs beyond Wrangler?
Execute bulk operations, run cross-service queries, and automate Cloudflare platform tasks that Wrangler does not expose.
Who is it for?
Developers automating Cloudflare platform tasks with REST APIs when Wrangler lacks bulk queries, cross-service ops, or CI-friendly endpoints.
Skip if: Simple single-worker deploys fully covered by Wrangler alone or teams not using Cloudflare's developer platform services.
When should I use this skill?
User needs Cloudflare API curl examples, bulk D1 operations, cross-service automation, or tasks Wrangler does not support.
What you get
Working curl scripts and REST calls for D1 queries, R2/KV operations, Workers deployment tasks, Vectorize, Queues, and Durable Objects management.
- curl REST scripts
- Bulk Cloudflare API automation commands
By the numbers
- Covers 7 Cloudflare developer platform services: D1, R2, KV, Workers, Vectorize, Queues, and Durable Objects
- All endpoints use the client/v4 accounts/{account_id}/ REST base path
Files
Cloudflare API
Hit the Cloudflare REST API directly when wrangler CLI or MCP servers aren't the right tool. For bulk operations, fleet-wide changes, and features that wrangler doesn't expose.
When to Use This Instead of Wrangler or MCP
| Use case | Wrangler | MCP | This skill |
|---|---|---|---|
| Deploy a Worker | Yes | Yes | No |
| Create a D1 database | Yes | Yes | No |
| Bulk update 50 DNS records | Slow (one at a time) | Slow (one tool call each) | Yes — batch script |
| Custom hostnames for white-label | No | Partial | Yes |
| Email routing rules | No | Partial | Yes |
| WAF/firewall rules | No | Yes but verbose | Yes — direct API |
| Redirect rules in bulk | No | One at a time | Yes — batch script |
| Zone settings across 20 zones | No | 20 separate calls | Yes — fleet script |
| Cache purge by tag/prefix | No | Yes | Yes (when scripting) |
| Worker route management | Limited | Yes | Yes (when bulk) |
| Analytics/logs query | No | Partial | Yes — GraphQL |
| D1 query/export across databases | One DB at a time | One DB at a time | Yes — cross-DB scripts |
| R2 bulk object operations | No | One at a time | Yes — S3 API + batch |
| KV bulk read/write/delete | One at a time | One at a time | Yes — bulk endpoints |
| Vectorize query/delete | No | Via Worker only | Yes — direct API |
| Queue message injection | No | Via Worker only | Yes — direct API |
| Audit all resources in account | No | Tedious | Yes — inventory script |
Rule of thumb: Single operations → MCP or wrangler. Bulk/fleet/scripted → API directly.
Auth Setup
API Token (recommended)
Create a scoped token at: Dashboard → My Profile → API Tokens → Create Token
# Store it
export CLOUDFLARE_API_TOKEN="your-token-here"
# Test it
curl -s "https://api.cloudflare.com/client/v4/user/tokens/verify" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" | jq '.success'Token scopes: Always use minimal permissions. Common presets:
- "Edit zone DNS" — for DNS operations
- "Edit zone settings" — for zone config changes
- "Edit Cloudflare Workers" — for Worker route management
- "Read analytics" — for GraphQL analytics
Account and Zone IDs
# List your zones (find zone IDs)
curl -s "https://api.cloudflare.com/client/v4/zones?per_page=50" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" | jq '.result[] | {name, id}'
# Get zone ID by domain name
ZONE_ID=$(curl -s "https://api.cloudflare.com/client/v4/zones?name=example.com" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" | jq -r '.result[0].id')Store IDs in environment or a config file — don't hardcode them in scripts.
Workflows
Bulk DNS Operations
Add/update many records at once (e.g. migrating a domain, setting up a new client):
# Pattern: read records from a file, create in batch
while IFS=',' read -r type name content proxied; do
curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"type\":\"$type\",\"name\":\"$name\",\"content\":\"$content\",\"proxied\":$proxied,\"ttl\":1}" \
| jq '{name: .result.name, id: .result.id, success: .success}'
sleep 0.25 # Rate limit: 1200 req/5min
done < dns-records.csvExport all records from a zone (backup or migration):
curl -s "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records?per_page=100" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
| jq -r '.result[] | [.type, .name, .content, .proxied] | @csv' > dns-export.csvFind and replace across records (e.g. IP migration):
OLD_IP="203.0.113.1"
NEW_IP="198.51.100.1"
# Find records pointing to old IP
RECORDS=$(curl -s "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records?content=$OLD_IP" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" | jq -r '.result[].id')
# Update each one
for RECORD_ID in $RECORDS; do
curl -s -X PATCH "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$RECORD_ID" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"content\":\"$NEW_IP\"}" | jq '.success'
doneCustom Hostnames (White-Label Client Domains)
For SaaS apps where clients use their own domain (e.g. app.clientdomain.com → your Worker):
# Create custom hostname
curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/custom_hostnames" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"hostname": "app.clientdomain.com",
"ssl": {
"method": "http",
"type": "dv",
"settings": {
"min_tls_version": "1.2"
}
}
}' | jq '{id: .result.id, status: .result.status, ssl_status: .result.ssl.status}'
# List custom hostnames
curl -s "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/custom_hostnames?per_page=50" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
| jq '.result[] | {hostname, status, ssl_status: .ssl.status}'
# Check status (client needs to add CNAME)
curl -s "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/custom_hostnames/$HOSTNAME_ID" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" | jq '.result.status'Client setup: They add a CNAME: app.clientdomain.com → your-worker.your-domain.com
Email Routing Rules
# Enable email routing on zone
curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/email/routing/enable" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN"
# Create a routing rule (forward info@ to a real address)
curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/email/routing/rules" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Forward info@",
"enabled": true,
"matchers": [{"type": "literal", "field": "to", "value": "info@example.com"}],
"actions": [{"type": "forward", "value": ["real-inbox@gmail.com"]}]
}' | jq '.success'
# Create catch-all rule
curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/email/routing/rules" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Catch-all",
"enabled": true,
"matchers": [{"type": "all"}],
"actions": [{"type": "forward", "value": ["catchall@company.com"]}]
}' | jq '.success'
# List rules
curl -s "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/email/routing/rules" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" | jq '.result[] | {name, enabled, matchers, actions}'Cache Purge
# Purge everything (nuclear option)
curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"purge_everything": true}'
# Purge specific URLs
curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"files": ["https://example.com/styles.css", "https://example.com/app.js"]}'
# Purge by cache tag (requires Enterprise or cache tag headers)
curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"tags": ["product-123", "homepage"]}'
# Purge by prefix
curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"prefixes": ["https://example.com/images/"]}'Redirect Rules (Bulk)
# Create a redirect rule
curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/rulesets/phases/http_request_dynamic_redirect/entrypoint" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"rules": [
{
"expression": "(http.request.uri.path eq \"/old-page\")",
"description": "Redirect old-page to new-page",
"action": "redirect",
"action_parameters": {
"from_value": {
"target_url": {"value": "https://example.com/new-page"},
"status_code": 301
}
}
}
]
}'For bulk redirects (301s from a CSV), generate the rules array programmatically:
import json, csv
rules = []
with open('redirects.csv') as f:
for row in csv.reader(f):
old_path, new_url = row
rules.append({
"expression": f'(http.request.uri.path eq "{old_path}")',
"description": f"Redirect {old_path}",
"action": "redirect",
"action_parameters": {
"from_value": {
"target_url": {"value": new_url},
"status_code": 301
}
}
})
print(json.dumps({"rules": rules}, indent=2))Zone Settings (Fleet-Wide)
Apply the same settings across multiple zones:
# Settings to apply
SETTINGS='{"value":"full"}' # SSL mode: full (strict)
# Get all active zones
ZONES=$(curl -s "https://api.cloudflare.com/client/v4/zones?status=active&per_page=50" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" | jq -r '.result[].id')
# Apply to each zone
for ZONE in $ZONES; do
curl -s -X PATCH "https://api.cloudflare.com/client/v4/zones/$ZONE/settings/ssl" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
-d "$SETTINGS" | jq "{zone: .result.id, success: .success}"
sleep 0.25
doneCommon fleet settings:
ssl— "full" or "strict"min_tls_version— "1.2"always_use_https— "on"security_level— "medium"browser_cache_ttl— 14400
WAF / Firewall Rules
# Create a WAF custom rule (block by country)
curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/rulesets/phases/http_request_firewall_custom/entrypoint" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"rules": [{
"expression": "(ip.geoip.country in {\"RU\" \"CN\"})",
"action": "block",
"description": "Block traffic from RU and CN"
}]
}'
# Rate limiting rule
curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/rulesets/phases/http_ratelimit/entrypoint" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"rules": [{
"expression": "(http.request.uri.path contains \"/api/\")",
"action": "block",
"ratelimit": {
"characteristics": ["ip.src"],
"period": 60,
"requests_per_period": 100
},
"description": "Rate limit API to 100 req/min per IP"
}]
}'Worker Routes
# List routes
curl -s "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/workers/routes" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" | jq '.result[] | {pattern, id}'
# Create route
curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/workers/routes" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"pattern": "api.example.com/*", "script": "my-worker"}'
# Delete route
curl -s -X DELETE "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/workers/routes/$ROUTE_ID" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN"Analytics (GraphQL)
# Worker analytics (requests, errors, CPU time)
curl -s -X POST "https://api.cloudflare.com/client/v4/graphql" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "{ viewer { zones(filter: {zoneTag: \"'$ZONE_ID'\"}) { httpRequests1dGroups(limit: 7, filter: {date_gt: \"2026-03-10\"}) { dimensions { date } sum { requests pageViews } } } } }"
}' | jq '.data.viewer.zones[0].httpRequests1dGroups'Rate Limits
| Endpoint | Limit |
|---|---|
| Most API calls | 1200 requests / 5 minutes |
| DNS record operations | 1200 / 5 min (shared with above) |
| Cache purge | 1000 purge calls / day |
| Zone creation | 5 per minute |
In scripts: Add sleep 0.25 between calls for sustained operations. Use p-limit or xargs -P 4 for controlled parallelism.
Script Generation
When the user describes what they need, generate a script in .jez/scripts/ that:
- Reads API token from environment (never hardcode)
- Handles pagination for list operations
- Includes error checking (
jq '.success'after each call) - Adds rate limit sleep between calls
- Logs what it does
- Supports
--dry-runwhere possible
Prefer curl + jq for simple operations. Use Python for complex logic (pagination loops, error handling, CSV processing). Use TypeScript with the cloudflare npm package for type safety in larger scripts.
API Reference
Base URL: https://api.cloudflare.com/client/v4/
Full docs: https://developers.cloudflare.com/api/
The API follows a consistent pattern:
GET /zones— listPOST /zones— createGET /zones/:id— readPATCH /zones/:id— updateDELETE /zones/:id— deletePUT /zones/:id/settings/:name— update setting
Every response has { success: bool, errors: [], messages: [], result: {} }.
Reference Files
| When | Read |
|---|---|
| D1, R2, KV, Workers, Vectorize, Queues API patterns | references/developer-platform-api.md |
Developer Platform API Patterns
REST API patterns for Cloudflare's developer platform services: D1, R2, KV, Workers, Vectorize, Queues, and Durable Objects. These complement what wrangler does — use the API for bulk operations, cross-database queries, automation scripts, and operations wrangler doesn't expose.
All endpoints use: https://api.cloudflare.com/client/v4/accounts/{account_id}/...
---
D1 (SQL Database)
List Databases
curl -s "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/d1/database" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
| jq '.result[] | {uuid, name, num_tables, file_size, version}'Query a Database
# Run SQL directly via API (useful for scripts, automation, debugging)
curl -s -X POST "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/d1/database/$DB_ID/query" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"sql": "SELECT * FROM users LIMIT 10"}' \
| jq '.result[0].results'
# With parameters (prevents SQL injection)
curl -s -X POST "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/d1/database/$DB_ID/query" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"sql": "SELECT * FROM users WHERE email = ?1", "params": ["jez@example.com"]}' \
| jq '.result[0].results'Raw SQL via API (Batch)
# Run multiple statements in one call
curl -s -X POST "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/d1/database/$DB_ID/raw" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"sql": "INSERT INTO users (id, name, email) VALUES (?1, ?2, ?3); INSERT INTO users (id, name, email) VALUES (?4, ?5, ?6);",
"params": ["id1", "Alice", "alice@example.com", "id2", "Bob", "bob@example.com"]
}'Export/Backup a D1 Database
# Export as SQL dump
curl -s -X POST "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/d1/database/$DB_ID/export" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"output_format": "file"}' \
| jq '.result'
# Then poll for the export to complete and downloadCross-Database Operations
Wrangler can only talk to one database at a time. The API lets you script across multiple:
import json, urllib.request
def query_d1(db_id, sql, params=None):
url = f"https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/d1/database/{db_id}/query"
payload = {"sql": sql}
if params:
payload["params"] = params
req = urllib.request.Request(url, data=json.dumps(payload).encode(),
headers={"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"})
return json.loads(urllib.request.urlopen(req).read())["result"][0]["results"]
# Query across multiple D1 databases
for db_name, db_id in databases.items():
users = query_d1(db_id, "SELECT COUNT(*) as count FROM users")
print(f"{db_name}: {users[0]['count']} users")D1 Gotchas via API
- Max 100KB per single SQL statement
- Max 1000 bound parameters per query
queryendpoint returns results;rawendpoint for DDL/DML without result sets- Export is async — returns a bookmark to poll, not the dump directly
---
R2 (Object Storage)
List Buckets
curl -s "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/r2/buckets" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
| jq '.result.buckets[] | {name, creation_date}'Create Bucket
curl -s -X POST "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/r2/buckets" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "my-bucket", "locationHint": "apac"}'List Objects in a Bucket (S3 API)
R2 objects are managed via the S3-compatible API, not the Cloudflare API:
# Using AWS CLI with R2 credentials
aws s3api list-objects-v2 \
--bucket my-bucket \
--endpoint-url "https://$ACCOUNT_ID.r2.cloudflarestorage.com" \
--max-keys 100 \
| jq '.Contents[] | {Key, Size, LastModified}'Bulk Delete Objects
# Delete all objects matching a prefix
aws s3 rm "s3://my-bucket/uploads/2025/" \
--endpoint-url "https://$ACCOUNT_ID.r2.cloudflarestorage.com" \
--recursiveR2 Usage Stats
curl -s "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/r2/buckets/$BUCKET_NAME/usage" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
| jq '.result'---
KV (Key-Value Store)
List Namespaces
curl -s "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/storage/kv/namespaces" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
| jq '.result[] | {id, title}'Read/Write Values
# Write
curl -s -X PUT "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/storage/kv/namespaces/$NS_ID/values/my-key" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-d "my-value"
# Write with metadata and expiration
curl -s -X PUT "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/storage/kv/namespaces/$NS_ID/values/my-key" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: multipart/form-data" \
-F "value=my-value" \
-F 'metadata={"source": "api"}' \
-F "expiration_ttl=3600"
# Read
curl -s "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/storage/kv/namespaces/$NS_ID/values/my-key" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN"
# Delete
curl -s -X DELETE "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/storage/kv/namespaces/$NS_ID/values/my-key" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN"List All Keys (with pagination)
curl -s "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/storage/kv/namespaces/$NS_ID/keys?limit=1000" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
| jq '.result[] | .name'Bulk Write (up to 10,000 pairs)
curl -s -X PUT "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/storage/kv/namespaces/$NS_ID/bulk" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '[
{"key": "key1", "value": "value1"},
{"key": "key2", "value": "value2", "expiration_ttl": 3600}
]'Bulk Delete
curl -s -X DELETE "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/storage/kv/namespaces/$NS_ID/bulk" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '["key1", "key2", "key3"]'---
Workers
List Workers
curl -s "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/scripts" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
| jq '.result[] | {id, modified_on, usage_model}'Get Worker Details
curl -s "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/scripts/$WORKER_NAME" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
| jq '.result'Get Worker Settings (Bindings, Compatibility)
curl -s "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/scripts/$WORKER_NAME/settings" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
| jq '.result | {bindings, compatibility_date, compatibility_flags}'List All Worker Bindings Across Account
Useful for auditing what's connected to what:
import json, urllib.request
url = f"https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/workers/scripts"
req = urllib.request.Request(url, headers={"Authorization": f"Bearer {TOKEN}"})
workers = json.loads(urllib.request.urlopen(req).read())["result"]
for w in workers:
settings_url = f"{url}/{w['id']}/settings"
req = urllib.request.Request(settings_url, headers={"Authorization": f"Bearer {TOKEN}"})
settings = json.loads(urllib.request.urlopen(req).read())["result"]
bindings = settings.get("bindings", [])
if bindings:
print(f"\n{w['id']}:")
for b in bindings:
print(f" {b['type']}: {b.get('name', '')} → {b.get('namespace_id', b.get('database_id', b.get('bucket_name', '')))}")Worker Subdomain
# Get current subdomain
curl -s "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/subdomain" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" | jq '.result.subdomain'---
Vectorize
List Indexes
curl -s "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/vectorize/v2/indexes" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
| jq '.result[] | {name, config}'Get Index Info
curl -s "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/vectorize/v2/indexes/$INDEX_NAME" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
| jq '.result'Query Vectors
curl -s -X POST "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/vectorize/v2/indexes/$INDEX_NAME/query" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"vector": [0.1, 0.2, ...],
"topK": 10,
"returnValues": false,
"returnMetadata": "all",
"filter": {"type": {"$eq": "client"}}
}'Delete Vectors by ID
curl -s -X POST "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/vectorize/v2/indexes/$INDEX_NAME/delete-by-ids" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"ids": ["vec-1", "vec-2"]}'Vectorize Gotchas
- Metadata indexes must be created BEFORE inserting vectors (vectors inserted before are NOT retroactively indexed)
- Max 1000 vectors per upsert call
- Metadata filter values are case-sensitive
---
Queues
List Queues
curl -s "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/queues" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
| jq '.result[] | {queue_id, queue_name, producers_total_count, consumers_total_count}'Send Message to Queue
curl -s -X POST "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/queues/$QUEUE_ID/messages" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"body": {"task": "process_image", "id": "123"}}'Bulk Send Messages
curl -s -X POST "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/queues/$QUEUE_ID/messages/batch" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{"body": {"task": "resize", "id": "1"}},
{"body": {"task": "resize", "id": "2"}}
]
}'---
Fleet Operations
Audit All Resources Across Account
Generate a full inventory of what's deployed:
import json, urllib.request
BASE = f"https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}"
HEADERS = {"Authorization": f"Bearer {TOKEN}"}
def get(path):
req = urllib.request.Request(f"{BASE}/{path}", headers=HEADERS)
return json.loads(urllib.request.urlopen(req).read()).get("result", [])
print("=== Workers ===")
for w in get("workers/scripts"):
print(f" {w['id']}")
print("\n=== D1 Databases ===")
for db in get("d1/database"):
print(f" {db['name']} ({db['uuid'][:8]}...)")
print("\n=== R2 Buckets ===")
for b in get("r2/buckets").get("buckets", []):
print(f" {b['name']}")
print("\n=== KV Namespaces ===")
for ns in get("storage/kv/namespaces"):
print(f" {ns['title']} ({ns['id'][:8]}...)")
print("\n=== Vectorize Indexes ===")
for idx in get("vectorize/v2/indexes"):
print(f" {idx['name']}")
print("\n=== Queues ===")
for q in get("queues"):
print(f" {q['queue_name']}")Compare Resources Across Two Accounts
Useful when migrating between Jezweb Team and Jez Personal accounts:
accounts = {
"team": "YOUR_TEAM_ACCOUNT_ID",
"personal": "YOUR_PERSONAL_ACCOUNT_ID",
}
for name, acct_id in accounts.items():
workers = get_for_account(acct_id, "workers/scripts")
d1s = get_for_account(acct_id, "d1/database")
print(f"\n{name}: {len(workers)} workers, {len(d1s)} D1 databases")Related skills
How it compares
Pick cloudflare-api for REST bulk automation and cross-service scripts; use Wrangler for standard local dev, config, and deploy workflows.
FAQ
Which Cloudflare services does cloudflare-api cover?
cloudflare-api documents REST patterns for D1, R2, KV, Workers, Vectorize, Queues, and Durable Objects via the client/v4 accounts API, covering bulk and cross-service operations beyond Wrangler.
When should developers use cloudflare-api instead of Wrangler?
cloudflare-api is for bulk operations, cross-database queries, automation scripts, and API tasks Wrangler does not expose, while Wrangler remains best for standard local development and deploy workflows.
Is Cloudflare Api safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.