verification
use it
# add to stunt.yaml
services:
cloudflare:
adapter: embedded:cloudflare-style
# then
$ stunt upThe embedded: source extracts this adapter from the binary — no git clone, fully offline.
how to mock the Cloudflare API locally
Install stunt, paste the service block above into stunt.yaml, run stunt up — then point your client at localhost instead of Cloudflare API. It works offline, keeps state across requests and restarts, and every response is synthetic: the route shapes, status codes, pagination, and webhook delivery follow the real Cloudflare API 4 surface — the data is fake, the behavior is real.
backing stores
zonesworkersbucketsdatabases
api surface (35)
generated from the adapter manifest — exactly what boots, nothing more · covers 0% of the real API's 3334 routes (derived from spec cloudflare api-schemas (paths /client/v4 prefix stripped) @ 4.0.0)
35 routes
GET/zones
POST/zones
GET/zones/{zone_id}
DELETE/zones/{zone_id}
GET/zones/{zone_id}/dns_records
POST/zones/{zone_id}/dns_records
GET/zones/{zone_id}/dns_records/{dns_record_id}
PUT/zones/{zone_id}/dns_records/{dns_record_id}
PATCH/zones/{zone_id}/dns_records/{dns_record_id}
DELETE/zones/{zone_id}/dns_records/{dns_record_id}
GET/zones/{zone_id}/firewall/rules
POST/zones/{zone_id}/firewall/rules
GET/zones/{zone_id}/firewall/rules/{rule_id}
PUT/zones/{zone_id}/firewall/rules/{rule_id}
PATCH/zones/{zone_id}/firewall/rules/{rule_id}
DELETE/zones/{zone_id}/firewall/rules/{rule_id}
GET/zones/{zone_id}/page_rules
POST/zones/{zone_id}/page_rules
GET/zones/{zone_id}/page_rules/{rule_id}
PUT/zones/{zone_id}/page_rules/{rule_id}
PATCH/zones/{zone_id}/page_rules/{rule_id}
DELETE/zones/{zone_id}/page_rules/{rule_id}
POST/zones/{zone_id}/purge_cache
GET/accounts/{account_id}/workers/scripts
PUT/accounts/{account_id}/workers/scripts/{script_name}
GET/accounts/{account_id}/workers/scripts/{script_name}
DELETE/accounts/{account_id}/workers/scripts/{script_name}
GET/accounts/{account_id}/workers/scripts/{script_name}/deployments
GET/accounts/{account_id}/r2/buckets
POST/accounts/{account_id}/r2/buckets
DELETE/accounts/{account_id}/r2/buckets/{bucket_name}
GET/accounts/{account_id}/d1/database
POST/accounts/{account_id}/d1/database
DELETE/accounts/{account_id}/d1/database/{database_id}
POST/accounts/{account_id}/d1/database/{database_id}/query
SDK-verified behaviors (7)
- ✓Zones list returns the seeded zone
- ✓Zones list filters by name
- ✓CreateZone + ZoneDetails round-trip
- ✓Duplicate CreateZone -> error code 1061
- ✓DNS records create + list + update round-trip
- ✓Firewall rules batch create + list with filter expression
- ✓DNS record delete + zone delete then details fails
Not implemented (8)
- No Workers KV: namespace or key-value endpoints (storage/kv/values)
- No Workers routes, custom domains, cron triggers, secrets, or tail endpoints
- No R2 object endpoints (listing, uploads, downloads) or S3 API surface
- No D1 get/update/import/export or time-travel endpoints
- No user, account, member, or role management endpoints (/user, /accounts)
- No zone settings, SSL/certificates, or GraphQL analytics endpoints
- No bulk DNS create/delete (dns_records/batch) or DNS import/export
- No rate limiting rules or WAF custom rulesets beyond zone firewall rules
Differs from the real API (6)
- any non-empty bearer token accepted; real token permission scoping not validated
- paths served without the /client/v4 prefix — cloudflare-go's BaseURL replaces the whole base, raw REST clients must strip it
- zone status runs pending -> initializing -> active in ~4s; real waits on nameservers
- deployments expose a status field; real Deployment objects carry rollout percentages
- simulate_fail on zone create / worker deploy injects moved or failed; no real trigger
- D1 query runs a small SQL subset; DROP/ALTER and other statements return 400
want more of the Cloudflare API surface? adapters are YAML + Starlark — the authoring guide covers adding routes, fixtures, and state machines. Open an issue for anything big first, or just file a PR — merged routes ship in the next release.