Delete CF Pages Deployments

A python script that deals with too many deployments

You may encounter the error Your project has too many deployments to be deleted, follow this guide to delete them: https://cfl.re/3CXesln when trying to delete a pages project which has more than approx. 100 deployments(each construction is considered as one build, like you updated an entry in your blog)

Screenshot

So I tell the big fat fish(Deepseek) to write a python script for me to automatically delete the deployments so that I can delete the project afterwards. The repo cloudflare-buik-delete is broken as the records per page of the pages api query is limited at 25, while the tool send queries with 100 records per page, causing HTTP 400 error

python
 1#!/usr/bin/env python3
 2"""Bulk delete all Cloudflare Pages deployments in a project."""
 3
 4import os
 5import sys
 6import requests
 7
 8# Config — set these via environment variables or edit inline
 9ACCOUNT_ID = os.environ.get("CLOUDFLARE_ACCOUNT_ID", "your_account_id")
10TOKEN = os.environ.get("CLOUDFLARE_API_TOKEN", "cfut_kfcCRAZYthursday")
11PROJECT = os.environ.get("CLOUDFLARE_PROJECT", "hugo")
12
13BASE = f"https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/pages/projects/{PROJECT}/deployments"
14HEADERS = {"Authorization": f"Bearer {TOKEN}"}
15
16
17def fetch_all_deployment_ids():
18    """Fetch all deployment IDs across all pages."""
19    ids = []
20    page = 1
21    while True:
22        resp = requests.get(f"{BASE}?page={page}", headers=HEADERS).json()
23        if not resp["success"]:
24            print(f"Error fetching page {page}: {resp['errors']}", file=sys.stderr)
25            sys.exit(1)
26
27        ids.extend(d["id"] for d in resp["result"])
28        total_pages = resp["result_info"]["total_pages"]
29        print(f"  Page {page}/{total_pages} — collected {len(ids)} total")
30
31        if page >= total_pages:
32            break
33        page += 1
34
35    return ids
36
37
38def delete_deployment(dep_id):
39    """Delete a single deployment. Returns (ok, message)."""
40    r = requests.delete(f"{BASE}/{dep_id}", headers=HEADERS)
41    data = r.json()
42    if data.get("success"):
43        return True, "OK"
44    else:
45        err = data.get("errors", [{}])[0].get("message", "unknown error")
46        return False, err
47
48
49def main():
50    print(f"=== Fetching all deployments for project '{PROJECT}' ===")
51    ids = fetch_all_deployment_ids()
52    print(f"\n=== Deleting {len(ids)} deployments ===")
53
54    ok = 0
55    skip = 0
56    for i, dep_id in enumerate(ids, 1):
57        success, msg = delete_deployment(dep_id)
58        if success:
59            ok += 1
60            print(f"  [{i}/{len(ids)}] OK  {dep_id}")
61        else:
62            skip += 1
63            print(f"  [{i}/{len(ids)}] SKIP ({msg})  {dep_id}")
64
65    print(f"\n=== Done! Deleted {ok}, skipped {skip}, total {len(ids)} ===")
66
67
68if __name__ == "__main__":
69    main()