diff --git a/src/ddns/providers.py b/src/ddns/providers.py
index 59f9665..df0f3a9 100644
--- a/src/ddns/providers.py
+++ b/src/ddns/providers.py
@@ -341,6 +341,127 @@ def have_address(self, proto):

  return False

+class DDNSProviderCloudflareV4(DDNSProvider):
+    """
+    Cloudflare v4 API using a Bearer Token.
+    Put the API Token in the 'token' OR 'password' field of the DDNS entry.
+    Optional in ddns.conf:
+      proxied = false|true   (default false; keep false for WireGuard)
+      ttl     = 1|60|120...  (default 1 = 'automatic')
+    """
+    handle    = "cloudflare.com-v4"
+    name      = "Cloudflare (v4)"
+    website   = "https://www.cloudflare.com/"
+    protocols = ("ipv4",)
+    supports_token_auth = True
+    holdoff_failure_days = 0
+
+    def _bool(self, key, default=False):
+        v = str(self.get(key, default)).strip().lower()
+        return v in ("1", "true", "yes", "on")
+
+    def update(self):
+        import json, urllib.request, urllib.error
+
+        tok = self.get("token") or self.get("password")
+        if not tok:
+            raise DDNSConfigurationError("API Token (password/token)
is missing.")
+
+        proxied = self._bool("proxied", False)
+        try:
+            ttl = int(self.get("ttl", 1))
+        except Exception:
+            ttl = 1
+
+        headers = {
+            "Authorization": "Bearer {0}".format(tok),
+            "Content-Type": "application/json",
+            "User-Agent": "IPFireDDNSUpdater/CFv4",
+        }
+
+        # --- find zone ---
+        parts = self.hostname.split(".")
+        if len(parts) < 2:
+            raise DDNSRequestError("Hostname '{0}' is not a valid
domain.".format(self.hostname))
+
+        zone_id = None
+        zone_name = None
+        for i in range(len(parts) - 1):
+            candidate = ".".join(parts[i:])
+            url =
f"https://api.cloudflare.com/client/v4/zones?name={candidate}"
+            try:
+                req = urllib.request.Request(url, headers=headers,
method="GET")
+                with urllib.request.urlopen(req, timeout=20) as r:
+                    data = json.loads(r.read().decode())
+            except Exception as e:
+                raise DDNSUpdateError(f"Failed to query Cloudflare
zones API: {e}")
+
+            if data.get("success") and data.get("result"):
+                zone_id = data["result"][0]["id"]
+                zone_name = candidate
+                break
+
+        if not zone_id:
+            raise DDNSRequestError(f"Could not find a Cloudflare Zone
for '{self.hostname}'.")
+
+        logger.info("CFv4: zone=%s id=%s", zone_name, zone_id)
+
+        # --- get record ---
+        rec_url =
f"https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records?type=A&name={self.hostname}"
+        try:
+            req = urllib.request.Request(rec_url, headers=headers,
method="GET")
+            with urllib.request.urlopen(req, timeout=20) as r:
+                rec_data = json.loads(r.read().decode())
+        except Exception as e:
+            raise DDNSUpdateError(f"Failed to query Cloudflare DNS
records API: {e}")
+
+        if not rec_data.get("success"):
+            errs = rec_data.get("errors") or []
+            if any("Authentication error" in (e.get("message", "") or
"") for e in errs):
+                raise DDNSAuthenticationError("Invalid API Token.")
+            raise DDNSUpdateError(f"Cloudflare API error finding
record: {errs}")
+
+        results = rec_data.get("result") or []
+        if not results:
+            raise DDNSRequestError(f"No A record found for
'{self.hostname}' in zone '{zone_name}'.")
+
+        record_id = results[0]["id"]
+        stored_ip = results[0]["content"]
+        logger.info("CFv4: record_id=%s stored_ip=%s", record_id, stored_ip)
+
+        # --- compare IPs ---
+        current_ip = self.get_address("ipv4")
+        logger.info("CFv4: current_ip=%s vs stored_ip=%s",
current_ip, stored_ip)
+        if current_ip == stored_ip:
+            logger.info("CFv4: no update needed")
+            return
+
+        # --- update ---
+        upd_url =
f"https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records/{record_id}"
+        payload = {
+            "type": "A",
+            "name": self.hostname,
+            "content": current_ip,
+            "ttl": ttl,
+            "proxied": proxied,
+        }
+        logger.info("CFv4: updating %s -> %s (proxied=%s ttl=%s)",
self.hostname, current_ip, proxied, ttl)
+
+        try:
+            req = urllib.request.Request(
+                upd_url, data=json.dumps(payload).encode(),
