---
title: "Cloudflare API Token"
description: "Writes workers, secrets, and DNS records during deploy."
source: "/docs/keys/cloudflare-api-token"
---


Quick reference [#quick-reference]

* Env var: `CLOUDFLARE_API_TOKEN`
* Required for: every deploy (uploads workers, writes secrets, sets up custom domains)
* Permissions / scopes: **all of the following must be present** — getting any one wrong is the #1 cause of failed deploys.
  * **Account → Workers Scripts → Edit** (write workers)
  * **Account → Account Settings → Read** (verify account access)
  * **Account → Workers KV Storage → Edit** (auth service KV namespace)
  * **Zone → DNS → Edit** (only if using a custom domain — skip if you're deploying to `*.workers.dev`)
  * **Zone → Zone → Read** (only if using a custom domain)
  * **Zone → SSL and Certificates → Edit** (only if using nested subdomain DNS style — see `mastrakit.config.json` → `domainStyle: "nested"`)
* Validation: `mastrakit doctor --key CLOUDFLARE_API_TOKEN` — calls `GET /user/tokens/verify`, then introspects the permissions list and reports specifically which ones are missing.

Create one [#create-one]

> **Use a Custom Token, not "Edit Cloudflare Workers".** The pre-built "Edit Cloudflare Workers" template is too narrow — it can't write DNS records or KV namespaces. You'll get a misleading "Authentication error" partway through deploy.

1. Go to [dash.cloudflare.com/profile/api-tokens](https://dash.cloudflare.com/profile/api-tokens).
2. Click **Create Token**.
3. Scroll to the bottom and click **Get started** under **Create Custom Token**.
4. Token name: `mastrakit-<your-slug>-deploy` (any name, just for your reference).
5. **Permissions** — add each row below:
   | Type    | Resource             | Action                         |
   | ------- | -------------------- | ------------------------------ |
   | Account | Workers Scripts      | Edit                           |
   | Account | Account Settings     | Read                           |
   | Account | Workers KV Storage   | Edit                           |
   | Zone    | DNS                  | Edit *(custom domain only)*    |
   | Zone    | Zone                 | Read *(custom domain only)*    |
   | Zone    | SSL and Certificates | Edit *(nested-subdomain only)* |
6. **Account Resources** — `Include` → `<your account name>`. Don't leave it as "All accounts" — scope it down.
7. **Zone Resources** — `Include` → `<your domain>` (if using custom domain). Otherwise skip.
8. **TTL** — leave blank for no expiry, or set 1 year for hygiene.
9. Click **Continue to summary** → **Create Token**.
10. Copy the token. **You can only view it once.**

Add to your project [#add-to-your-project]

Paste into `.env.dev-secrets` (gitignored):

```
CLOUDFLARE_API_TOKEN=<paste>
```

Common validation failures [#common-validation-failures]

The validator introspects the token's permissions and reports specifically what's missing. Example failure messages:

* **`❌ missing permission: com.cloudflare.api.account.worker.script.write`** — Add `Workers Scripts: Edit` to the token.
* **`❌ missing permission: com.cloudflare.edge.dns.write`** — Add `DNS: Edit` for the zone. Only needed if you're deploying to a custom domain.
* **`❌ missing permission: com.cloudflare.api.account.zone.ssl-cert.write`** — Add `SSL and Certificates: Edit`. Only needed if your `mastrakit.config.json` has `domainStyle: "nested"` (using Cloudflare Advanced Certificate Manager).
* **`❌ token does not have access to account <id>`** — Token's Account Resources don't include the account from your `CF_ACCOUNT_ID`. Edit the token or re-copy the right `CF_ACCOUNT_ID`.
* **`❌ 401 invalid api token`** — Token was revoked, expired, or pasted wrong. Re-create.

To fix: re-edit the token at [dash.cloudflare.com/profile/api-tokens](https://dash.cloudflare.com/profile/api-tokens) → click the token name → **Edit** → add the missing permission → **Continue to summary** → **Save**. You don't need to create a new token; the existing key keeps working.

Why so many permissions? [#why-so-many-permissions]

Each one corresponds to a specific deploy step:

* `Workers Scripts: Edit` — `wrangler deploy` (every service)
* `Workers KV Storage: Edit` — Better Auth needs a KV namespace for rate-limit state
* `DNS: Edit` + `Zone: Read` — setting up `auth-<slug>.<domain>` custom domains
* `SSL and Certificates: Edit` — provisioning the ACM certificate for nested-subdomain style

A token with all six rights is needed for a full first-time deploy. After deploy you can rotate it to a narrower one if you want (only `Workers Scripts: Edit` is needed for re-deploys without DNS changes).
