Cloudflare’s Workers Builds API asks for three fields when you create a build token: build_token_name, build_token_secret, and cloudflare_token_id. The API reference lists them as required strings but never explains where the last two values actually come from. Here’s the mapping: build_token_secret is your existing Cloudflare API token’s secret, not a random string you invent, and cloudflare_token_id is the result.id field returned by Cloudflare’s own token verification endpoint. Get those two values right and the request works on the first try.
We ran into this while wiring up CI/CD for a client’s Worker deployment as part of a broader web application development engagement. The example payload in Cloudflare’s docs uses placeholder values like super-secret-token and cf-token-123, which look like something you’re supposed to generate yourself. Even AI coding assistants tend to read it that way and suggest a random UUID. Neither is correct, and the 400 error you get back doesn’t say why. This post is the missing context.
The Create Build Token Endpoint
The endpoint is:
POST https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/builds/tokens
It needs a Bearer token in the Authorization header and returns a build token you’ll use later when setting up a Workers Builds trigger. Cloudflare’s own reference for this endpoint confirms the three required body fields but stops short of explaining the relationship between build_token_secret, cloudflare_token_id, and the Cloudflare API token you already have sitting in your dashboard.
Step 1: Get Your Account ID
You need your Cloudflare Account ID for the URL itself. Fastest way to find it:
- Log in to the Cloudflare dashboard.
- Press
Cmd+Kon macOS orCtrl+Kon Windows/Linux to open the command palette. - Type “Account ID.”
- Click the result to copy it.
Drop it into the URL:
https://api.cloudflare.com/client/v4/accounts/1234567890abcdef1234567890abcdef/builds/tokens
Step 2: Authenticate the Request
Send your Cloudflare API token as a Bearer token, plus a JSON content type:
Authorization: Bearer cfut_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json
This is the same API token you’d use for any other Cloudflare API call. Cloudflare recommends scoped API tokens over the legacy global API key for exactly this kind of automation, and Workers Builds is no exception.
What Does build_token_name Actually Need?
Nothing tricky here. It’s a plain descriptive label:
{
"build_token_name": "ConicPlex Production Build Token"
}
Name it whatever helps you tell tokens apart later: “Production Build Token,” “Client Deployment CI/CD,” “Nuxt Production Build.” It’s cosmetic, and it’s the one field in this whole flow that behaves exactly the way it reads.
What Does build_token_secret Actually Need?
This is where the confusion starts. Cloudflare’s example body shows:
"build_token_secret": "super-secret-token"
which reads like a placeholder you’re meant to swap for a random string of your own choosing. It isn’t. The value should be the secret of the actual Cloudflare API token you’re associating with this build token, the same cfut_... value you’re already sending in the Authorization header:
{
"build_token_secret": "cfut_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
Don’t generate a UUID for this field just because the key is named “secret.” The API reference defines it as a required string without clarifying that relationship, which is the single biggest source of confusion in the whole flow. If you send a made-up value here, the request will either fail outright or create a token that’s disconnected from the API token you actually intended to use.
What Does cloudflare_token_id Actually Need?
The second field trips people up just as often:
"cloudflare_token_id": "cf-token-123"
It is not your Account ID, and it is not the token secret you just used above. It’s the identifier of your Cloudflare API token, and you get it from a completely different endpoint: Cloudflare’s token verification API.
How Do You Get cloudflare_token_id?
Call the verify endpoint with the same API token:
curl "https://api.cloudflare.com/client/v4/user/tokens/verify" \
--header "Authorization: Bearer YOUR_CLOUDFLARE_API_TOKEN"
The response includes an id field, which Cloudflare’s docs label the token’s identifier tag:
{
"success": true,
"result": {
"id": "d3049b00a220a67a31c9bf3cd79a036a",
"status": "active"
},
"errors": [],
"messages": []
}
That result.id value is what goes into cloudflare_token_id.
Putting the Full Request Together
With all three values sorted, the request body looks like this:
POST https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/builds/tokens
Headers:
Authorization: Bearer YOUR_CLOUDFLARE_API_TOKEN
Content-Type: application/json
Body:
{
"build_token_name": "ConicPlex Production Build Token",
"build_token_secret": "cfut_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"cloudflare_token_id": "d3049b00a220a67a31c9bf3cd79a036a"
}
A successful call returns the created token’s details:
{
"success": true,
"errors": [],
"messages": [],
"result": {
"build_token_name": "ConicPlex Production Build Token",
"build_token_uuid": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"cloudflare_token_id": "d3049b00a220a67a31c9bf3cd79a036a",
"owner_type": "user"
}
}
Hold onto build_token_uuid. That’s the value you’ll pass in when creating a Workers Builds CI/CD trigger, which is the whole point of generating this token in the first place.
Don’t Mix Up the Four Different IDs
Workers CI/CD involves more identifiers than the docs make obvious, and they’re easy to confuse under deadline pressure:
| ID | What it identifies | Where it comes from |
|---|---|---|
| Account ID | Your Cloudflare account | Dashboard command palette (Cmd/Ctrl+K) |
| cloudflare_token_id | Your Cloudflare API token | result.id from /user/tokens/verify |
| build_token_uuid | The Workers Build Token itself | Returned when you create the build token |
| Worker Tag | The Worker script tied to the build | Workers dashboard / scripts API |
None of these are interchangeable, and the API won’t warn you if you swap one for another. It’ll usually just fail with an error that doesn’t point back to which field was wrong.
Treat the API Token Secret Like Any Other Credential
Because build_token_secret is your real Cloudflare API token, it deserves the same handling as a database password or a signing key. Keep it out of:
- GitHub repositories, public or private
- Client-side JavaScript, including Vue and Nuxt front-end code
- Public documentation or internal wikis without access controls
- Screenshots shared in tickets or Slack
Store it in environment variables or a secret manager instead:
CLOUDFLARE_API_TOKEN=cfut_xxxxxxxxx
CLOUDFLARE_ACCOUNT_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Cloudflare only shows a token’s secret once, at creation time. If you lose it, the fix is generating a new token, not recovering the old one.
Frequently Asked Questions
Is build_token_secret the same as my Cloudflare API token?
Yes. It’s the secret value of the Cloudflare API token you’re associating with the build token, the exact same string you send as a Bearer token in the Authorization header. It is not a value you generate yourself.
What’s the difference between cloudflare_token_id and my Account ID?
They identify completely different things. Account ID identifies your Cloudflare account and comes from the dashboard. cloudflare_token_id identifies a specific API token and comes from calling /user/tokens/verify and reading result.id.
Why does the Create Build Token API return a 400 error with no clear reason?
The most common cause is sending a random or made-up value for build_token_secret or cloudflare_token_id instead of the real values described above. Double-check both against your actual API token before assuming the request format itself is wrong.
Where do I use build_token_uuid after I get it?
It’s the value the Workers Builds trigger API expects when you connect a repository to CI/CD, so the build system knows which token authorizes that pipeline.



