LSN 09/10 ▸API 10 MIN TIER FREE
API tokens and automation
How to give scripts and CI access to Cloudflare without handing over your account, and the difference between the legacy Global API Key and modern API tokens.
Before this: 06 Workers: code at the edge
Anything Cloudflare exposes in the dashboard, you can do through their
REST API. This is how wrangler works, how CI deploys without a human,
how Terraform manages Cloudflare resources, and how custom scripts
automate the bits the dashboard makes painful. The thing that gates
all of it is credentials. Cloudflare has two: one you should avoid, and
one you should prefer.
The Global API Key (don’t use it)
This was the original mechanism. One key per account, never expires, account-wide permissions. It is essentially a password. Cloudflare keeps it for backwards compatibility but discourages its use in their own documentation now.
If you see a tutorial telling you to set CLOUDFLARE_API_KEY plus
CLOUDFLARE_EMAIL, that tutorial is outdated. Use an API token instead.
API tokens
The modern mechanism. Each token is independently created, scoped, and revocable. You can have many tokens, each doing a narrow job.
To create one: dashboard → My Profile → API Tokens → Create Token.
There are templates for common cases (Edit zone DNS, Pages: Edit, etc.) or you can start from scratch with Custom token.
A custom token’s anatomy:
- Permissions. A list of (Resource group, action) pairs. Examples:
- Account: Cloudflare Pages: Edit
- Zone: DNS: Edit
- Zone: Workers Scripts: Edit
- User: Memberships: Read
- Resources. Which accounts and zones the token applies to. You can scope to one specific zone, all zones in one account, or all zones you can access.
- Client IP filtering (optional). Restrict to a CIDR range. Useful for CI runners with fixed IPs.
- TTL (optional). Token expires at a specified time.
Save. Cloudflare shows the token value once. Copy it then. There is no way to retrieve it later. If you lose it, revoke the token and create a new one.
Wrangler authentication
wrangler login runs an OAuth flow in your browser, gets a short-lived
token, and stores it in ~/.wrangler/config/. This is the right path
for interactive development.
For CI, do not run wrangler login. Instead, create an API token
scoped to exactly what the CI job needs (typically Account: Workers Scripts: Edit and Account: Cloudflare Pages: Edit), expose it as an
environment variable, and wrangler will pick it up:
export CLOUDFLARE_API_TOKEN=...
wrangler deploy
wrangler also reads CLOUDFLARE_ACCOUNT_ID if it cannot infer the
account from the token (rare).
A GitHub Actions example
Deploying a Worker on every push to main:
name: deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 22 }
- run: npm ci
- run: npx wrangler deploy
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
The token in secrets.CLOUDFLARE_API_TOKEN should be scoped narrowly:
just Account: Workers Scripts: Edit for this account. If it leaks,
the blast radius is “can deploy and overwrite Workers in this account”,
not “can do anything to my entire Cloudflare presence”.
Calling the REST API directly
For things wrangler does not cover, the REST API is at
api.cloudflare.com/client/v4. Send the token as a Bearer header:
curl -X GET https://api.cloudflare.com/client/v4/zones \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN"
The responses are JSON envelopes with a success field and a result
field. There is a Postman collection and an OpenAPI spec published in
Cloudflare’s docs, and the official Node SDK (cloudflare) wraps the
whole surface.
A few common endpoints worth knowing about:
GET /zones— list zones (sites)POST /zones/:id/dns_records— create a DNS recordGET /accounts/:id/pages/projects— list Pages projectsPOST /accounts/:id/workers/scripts/:name— upload a Worker
Audit logs
Cloudflare logs every action taken through the API or the dashboard, attributed to the user or token that performed it. My Profile → Audit Log shows the last 90 days. If something changed on your account and you do not recognize it, this is where you look first.
Rotation and hygiene
Treat tokens like SSH keys:
- One token per purpose. Not one master token for everything.
- Scope as narrowly as the workflow allows.
- Set an expiry if the token only needs to work for a known window.
- Rotate periodically. CI tokens should be rotated when a maintainer leaves, when a runner is compromised, or annually as a baseline.
- Never commit a token to a repo. Use the platform’s secret store (GitHub Secrets, your CI provider, or an actual secret manager).
- On suspicion of leak, revoke immediately in the dashboard. Tokens are revocable; passwords are not.
With tokens in hand, you can drive almost the entire stack from scripts, leaving the dashboard for the parts that genuinely benefit from a human-in-the-loop view.