← route

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 ProfileAPI TokensCreate 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 record
  • GET /accounts/:id/pages/projects — list Pages projects
  • POST /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 ProfileAudit 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.