Cloudflare
Package cloudflare is your Cloudflare account, managed from Hanzo: zones, Pages, Workers, Workers AI, R2, KV and D1.
Package cloudflare is your Cloudflare account, managed from Hanzo: zones, Pages, Workers, Workers AI, R2, KV and D1.
| Base URL | https://api.hanzo.ai |
| Operations | 33 |
| Auth | Authorization: Bearer $HANZO_API_KEY |
cloudflare
POST /v1/cloudflare/ai/run/{wildcard1}
Run a Cloudflare Workers AI model and get its output back
Runs a Workers AI model — the model id is the rest of the path, e.g. @cf/meta/llama-3.1-8b-instruct — on the org's OWN Cloudflare account and relays the model's output. The request body is whatever the chosen model takes (a prompt, chat messages, a base64 audio clip) and is forwarded unchanged; the response is the model's own, which for an image or audio model is BYTES under Cloudflare's content type rather than JSON. Both halves are why this is not a typed op.
It is the ONE PRICED route on this plane, because a run is inference rather than passthrough. The org's own token already paid Cloudflare for the compute, so Hanzo debits only the thin BYO routing fee — never the full inference cost — and meters it on the SAME ai product axis and per-project caps as every other model call, so Workers AI spend sums with LLM spend. The fee has a floor, so every run leaves a usage row even for a modality that reports no tokens, and it emits one gen_ai span with gen_ai.system = cloudflare.
Gated by BALANCE, not by the admin bit that guards the destructive verbs here: a validated org is enough, and a frozen, broke or over-cap org is refused with the fleet-wide 402/503 billing contract BEFORE any byte reaches Cloudflare — no run, and no account discovery either. An empty or oversized body is 400, as is a model id that is not a plain Cloudflare model path; 503 if the org has never connected a Cloudflare token.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
wildcard1 | path | string | yes |
POST /v1/cloudflare/d1/databases/{database}/query
Run a SQL statement against a D1 database
Executes a statement on one D1 database on the org's OWN Cloudflare account and relays D1's result set. sql is required and params carries the bound values in placeholder order — use them rather than interpolating values into the statement.
The body is checked for a non-empty sql and then forwarded VERBATIM, so every field D1 accepts reaches D1 even though only two are named here; the declared schema is open for that reason. That verbatim forward is why this is not a typed op — decoding and re-encoding the body would drop params, where the query's bound values live. Requires ORG ADMIN (403 otherwise); a malformed body or missing sql is 400; 503 if the org has never connected a Cloudflare token.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
database | path | string | yes |
Request body — application/json
| Field | Type | Required | Description |
|---|---|---|---|
params | any[] | — | |
sql | string | — |
DELETE /v1/cloudflare/d1/databases/{database}
Deletes a D1 database and everything stored in it. Requires org admin.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
database | path | string | yes | Database is the Cloudflare D1 database id or name. |
GET /v1/cloudflare/d1/databases
Lists the D1 databases on the org's Cloudflare account. Any org member may read.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
page | query | string | — | Page is the 1-based page of databases to return. |
per_page | query | string | — | PerPage is how many databases one page holds. |
name | query | string | — | Name filters to the database with this name. |
POST /v1/cloudflare/d1/databases
Creates a D1 database on the org's Cloudflare account. Requires org admin.
Request body — application/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
name | string | — | Name is the database name to create. |
GET /v1/cloudflare/kv/namespaces/{namespace}/values/{key}
Read a Workers KV value as its stored bytes
Answers one KV key's value from the org's OWN Cloudflare account as RAW BYTES under the content type it was written with — not wrapped in a JSON envelope, which is why this is not a typed op. Any org member may read. A key that does not exist is Cloudflare's own 404; an invalid namespace, or a key that is empty, over 512 bytes, not valid UTF-8, or carries a control character, is 400; 503 if the org has never connected a Cloudflare token.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
namespace | path | string | yes | |
key | path | string | yes |
PUT /v1/cloudflare/kv/namespaces/{namespace}/values/{key}
Write a Workers KV value from the request body
Stores one KV key on the org's OWN Cloudflare account. The REQUEST BODY IS THE VALUE, forwarded verbatim under the caller's own Content-Type (text/plain when none is sent), so a value is never re-encoded on the way in — which is why this is not a typed op. expiration and expiration_ttl may ride the query string and are passed through to Cloudflare. Requires ORG ADMIN (403 otherwise); the same namespace and key validation as the read answers 400; 503 if the org has never connected a Cloudflare token.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
namespace | path | string | yes | |
key | path | string | yes |
DELETE /v1/cloudflare/kv/namespaces/{namespace}/values/{key}
KVValueDelete removes one key from a Workers KV namespace. Requires org admin.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
namespace | path | string | yes | Namespace is the Cloudflare KV namespace id. |
key | path | string | yes | Key is the key within that namespace. KV keys are broad (up to 512 bytes), so this one is escaped rather than… |
DELETE /v1/cloudflare/kv/namespaces/{namespace}
KVNamespaceDelete deletes a Workers KV namespace and every key in it. Requires org admin.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
namespace | path | string | yes | Namespace is the Cloudflare KV namespace id. |
GET /v1/cloudflare/kv/namespaces
KVNamespaceList lists the Workers KV namespaces on the org's Cloudflare account. Any org member may read.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
page | query | string | — | Page is the 1-based page of namespaces to return. |
per_page | query | string | — | PerPage is how many namespaces one page holds. |
order | query | string | — | Order names the field to sort by, and Direction sorts asc or desc. |
direction | query | string | — |
POST /v1/cloudflare/kv/namespaces
KVNamespaceCreate creates a Workers KV namespace on the org's Cloudflare account. Requires org admin. Cloudflare mints the namespace id the value routes address.
Request body — application/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
title | string | — | Title is the namespace's display title. |
POST /v1/cloudflare/pages/projects/{project}/deployments
Trigger a new Pages deployment for a project
Starts a build and deployment of one Cloudflare Pages project on the org's OWN Cloudflare account, and relays Cloudflare's deployment record back. branch picks what to build; OMITTING it builds the project's production branch.
A body it cannot parse is IGNORED rather than refused — the deployment falls back to the production branch — which is the one rule to get right here and the reason this is not a typed op: a typed request would answer 400 where this deploys. Requires ORG ADMIN (403 otherwise), and 503 if the org has never connected a Cloudflare token.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes |
Request body — application/json
| Field | Type | Required | Description |
|---|---|---|---|
branch | string | — |
DELETE /v1/cloudflare/pages/projects/{project}/domains/{domain}
Detaches a custom domain from a Cloudflare Pages project. Requires org admin.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | Project is the Pages project name. |
domain | path | string | yes | Domain is the attached custom domain to detach. |
POST /v1/cloudflare/pages/projects/{project}/domains
Attaches a custom domain to a Cloudflare Pages project. Requires org admin. Cloudflare owns validation and certificate issuance from here on.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | Project is the Pages project name, from the path. |
Request body — application/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
name | string | — | Name is the custom domain to attach, e.g. |
project | string | — | Project is the Pages project name, from the path. |
GET /v1/cloudflare/pages/projects/{project}
Reads one Cloudflare Pages project — its build config, deployment configs and latest deployment. Any org member may read.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | Project is the Pages project name. |
DELETE /v1/cloudflare/pages/projects/{project}
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
project | path | string | yes | Project is the Pages project name. |
GET /v1/cloudflare/pages/projects
Lists the org's Cloudflare Pages projects. Any org member may read.
POST /v1/cloudflare/pages/projects
Creates a Cloudflare Pages project on the org's account. Requires org admin. Only the modeled fields reach Cloudflare, so an unmodeled key in the request is dropped rather than forwarded.
Request body — application/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
build_config | PagesBuildConfig | — | |
deployment_configs | PagesDeploymentConfigs | — | |
name | string | — | |
production_branch | string | — |
DELETE /v1/cloudflare/r2/buckets/{bucket}
Deletes an R2 bucket. Requires org admin. Cloudflare refuses a bucket that still holds objects, and that refusal is relayed.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
bucket | path | string | yes | Bucket is the R2 bucket name. |
GET /v1/cloudflare/r2/buckets
Lists the R2 buckets on the org's Cloudflare account. Any org member may read.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
per_page | query | string | — | PerPage is how many buckets one page holds. |
cursor | query | string | — | Cursor continues from the position a previous page returned. |
name_contains | query | string | — | NameContains filters to buckets whose name contains this substring. |
order | query | string | — | Order names the field to sort by, and Direction sorts asc or desc. |
direction | query | string | — |
POST /v1/cloudflare/r2/buckets
Creates an R2 bucket on the org's Cloudflare account. Requires org admin.
Request body — application/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
name | string | — | Name is the bucket name to create. |
POST /v1/cloudflare/workers/scripts/{script}/subdomain
Publishes or withdraws one Worker script on the account's workers.dev subdomain. Requires org admin.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
script | path | string | yes | Script is the Worker script name, from the path. |
Request body — application/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
enabled | boolean | — | Enabled publishes the script on <script>.<subdomain>.workers.dev when true, and withdraws it when false. |
script | string | — | Script is the Worker script name, from the path. |
PUT /v1/cloudflare/workers/scripts/{script}
Upload or replace a module Worker script
Publishes a module Worker to the org's OWN Cloudflare account under the name in the path, replacing whatever was there, and relays Cloudflare's result. script carries the module SOURCE; the optional compatibility date, compatibility flags and bindings are packed into the multipart upload Cloudflare expects.
The path names the script and the body field named script is its source — two different things that share a name, which is exactly why this cannot be a typed op: a binder that gives the URL the last word would overwrite the source with the script's name. Requires ORG ADMIN (403 otherwise); an unparseable body or empty source is 400; 503 if the org has never connected a Cloudflare token.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
script | path | string | yes |
Request body — application/json
| Field | Type | Required | Description |
|---|---|---|---|
bindings | — | ||
compatibilityDate | string | — | |
compatibilityFlags | string[] | — | |
mainModule | string | — | |
script | string | — |
DELETE /v1/cloudflare/workers/scripts/{script}
Removes a Worker script from the org's Cloudflare account. Requires org admin. Routes bound to the script stop serving it.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
script | path | string | yes | Script is the Worker script name. |
GET /v1/cloudflare/workers/scripts
Lists the Worker scripts on the org's Cloudflare account. Any org member may read.
GET /v1/cloudflare/workers/subdomain
Reads the org account's workers.dev subdomain — the name under which every subdomain-enabled script is served. Any org member may read.
DELETE /v1/cloudflare/workers/zones/{zone}/routes/{route}
Unbinds a Worker route, so its pattern stops dispatching to a script. Requires org admin.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
zone | path | string | yes | Zone is the 32-hex Cloudflare zone id. |
route | path | string | yes | Route is the 32-hex Cloudflare route id. |
GET /v1/cloudflare/workers/zones/{zone}/routes
Lists the Worker routes bound within one zone — the URL patterns that dispatch to a script. Any org member may read. Routes are zone-scoped, so no account is resolved.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
zone | path | string | yes | Zone is the 32-hex Cloudflare zone id. |
POST /v1/cloudflare/workers/zones/{zone}/routes
Binds a URL pattern in a zone to a Worker script. Requires org admin — a route is what puts a script in front of live traffic.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
zone | path | string | yes | Zone is the 32-hex Cloudflare zone id, from the path. |
Request body — application/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
pattern | string | — | Pattern is the URL pattern to bind, e.g. |
script | string | — | Script is the Worker script to dispatch to. |
zone | string | — | Zone is the 32-hex Cloudflare zone id, from the path. |
GET /v1/cloudflare/zones/{zone}/analytics
Reads a zone's Cloudflare traffic dashboard — requests, bandwidth, threats and pageviews over the since/until window. Any org member may read.
A zone whose Cloudflare plan does not serve this endpoint yields Cloudflare's OWN error, never a fabricated success.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
zone | path | string | yes | Zone is the 32-hex Cloudflare zone id. |
since | query | string | — | Since and Until bound the window, in the form Cloudflare accepts — an RFC 3339 time or a negative number of minutes… |
until | query | string | — | |
continuous | query | string | — | Continuous asks Cloudflare for only fully-aggregated buckets. |
POST /v1/cloudflare/zones/{zone}/purge
Drops a zone's Cloudflare edge cache — either the whole zone (purge_everything) or exactly the listed file URLs. Requires org admin.
Purging is the one zone-scoped WRITE this plane owns. It is not DNS — no record changes — so it does not belong on /v1/dns, and it is not a connection, so it does not belong on the integrations plane. It is a cache operation on a zone, which is what this asset plane is for. It takes the admin gate because dropping a zone's cache sends every subsequent request to the origin: on a site fronting a small origin that is a self-inflicted load spike, so it is a change, not a look.
Exactly one selector is required. Cloudflare treats a body with neither as a no-op and answers 200, which reads as "purged" to a caller that never purged anything — the failure we refuse to pass through.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
zone | path | string | yes | Zone is the 32-hex Cloudflare zone id, from the path. |
Request body — application/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
files | string[] | — | Files purges exactly the listed URLs — at most 30, Cloudflare's per-request cap. |
purge_everything | boolean | — | Everything drops the zone's entire edge cache. |
zone | string | — | Zone is the 32-hex Cloudflare zone id, from the path. |
GET /v1/cloudflare/zones/{zone}
Reads one Cloudflare zone the org's token can see. Any org member may read. A zone id the token cannot see is Cloudflare's own not-found, relayed.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
zone | path | string | yes | Zone is the 32-hex Cloudflare zone id. |
GET /v1/cloudflare/zones
Lists the Cloudflare zones the org's connected API token can see, paged and filtered by the query parameters Cloudflare itself accepts. Zones are token-scoped by Cloudflare, so no account is resolved. Any org member may read.
Zone and DNS-record MANAGEMENT is not here: it stays on the Hanzo DNS plane (/v1/dns). This only surfaces the Cloudflare zone objects the asset plane needs — a zone id is what addresses a Worker route or an analytics read.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
page | query | string | — | Page is the 1-based page of zones to return. |
per_page | query | string | — | PerPage is how many zones one page holds. |
name | query | string | — | Name filters to the zone with this domain name. |
status | query | string | — | Status filters by zone status (active, pending, initializing, …). |
order | query | string | — | Order names the field to sort by, and Direction sorts asc or desc. |
direction | query | string | — |
How is this guide?