Writing

Series · CloudflarePart 1

Automating Cloudflare Pages with the API

The Cloudflare Pages dashboard is fine but I'd rather just curl things. Here's how I set up staging and production branches pointing to different domains without touching the UI.

3 min read441 wordsCloudflaremy-blog

I needed to set up staging and production domains for my blog on Cloudflare Pages. You can do this through the dashboard but I don't know, I just didn't feel like clicking around. The API is right there.

What I wanted

Pretty straightforward: eduuh.com should serve the main branch of blog-2026, and staging.eduuh.com should serve the staging branch.

Getting API access

Grabbed an API token from the Cloudflare dashboard. You need Account > Cloudflare Pages > Edit, Account > Account Settings > Read, and (if you want to script DNS too) Zone > DNS > Edit.

Don't be that guy

Keep the token out of git. I stuck mine in .env and added it to .gitignore.

Adding the domains

Attaching custom domains to a Pages project:

# Root domain
curl -X POST \
  "https://api.cloudflare.com/client/v4/accounts/{account_id}/pages/projects/blog-2026/domains" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  --data '{"name":"eduuh.com"}'
 
# Staging subdomain
curl -X POST \
  "https://api.cloudflare.com/client/v4/accounts/{account_id}/pages/projects/blog-2026/domains" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  --data '{"name":"staging.eduuh.com"}'

Making staging actually point to staging

Here's where I got stuck. Both domains were now attached, but both were serving main. Not what you want from a staging URL.

You have to explicitly tell Cloudflare which branch a domain should serve:

curl -X PATCH \
  "https://api.cloudflare.com/client/v4/accounts/{account_id}/pages/projects/blog-2026/domains/staging.eduuh.com" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  --data '{"branch":"staging"}'

This was the key bit I couldn't figure out from the dashboard. The API made it obvious.

DNS while I'm at it

My domain's already on Cloudflare, so I figured I'd set up the DNS records via API too:

# Root domain
curl -X POST \
  "https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  --data '{
    "type": "CNAME",
    "name": "@",
    "content": "blog-2026-290.pages.dev",
    "proxied": true
  }'
 
# Staging
curl -X POST \
  "https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  --data '{
    "type": "CNAME",
    "name": "staging",
    "content": "blog-2026-290.pages.dev",
    "proxied": true
  }'

Both point to the same pages.dev subdomain - Cloudflare routes to the right branch based on the domain config we set earlier.

That's it

DomainBranch
eduuh.commain
staging.eduuh.comstaging

Push to main, production updates. Push to staging, staging updates.

The PATCH to map a specific branch to a domain was the thing I couldn't figure out how to do in the dashboard. Might be possible, I didn't look that hard. But the API made it obvious.


Claude figured out the APIs for me. Saved me from digging through docs and clicking around the dashboard.

Last updated on January 11th, 2026