Automating domain renewal tracking with Cloudflare and HaloPSA

David Pottrell

David Pottrell

Hi! I’m a web developer and Head of Digital at Nebula Design who loves all things tech. When I’m not surrounded by code, I’m probably reading up on the latest development trends or on the pottery wheel.

I got my start in technology as a self-taught web freelancer, after studying at university and joining a small agency, Nebula Design was created. I specialise in both front-end and back-end development, typically around WordPress, I’ve also got expertise in Search Engine Optimisation, Ecommerce and various emerging tech standards.

Published on August 21st, 2025

Managing domain renewals is one of those background tasks that doesn’t sound exciting, but it’s absolutely critical. Forgetting to renew a client’s domain name can cause downtime, lost emails, and reputational damage that no business wants to face. Historically, this has been a manual process for us, we’d get an email reminder, we’d approach the client to query if they wish to renew, create the ticket, close the ticket.

We’ve recently moved to using HaloPSA for our tickets/time tracking, so whilst the IT side of Nebula has been hard at work migrating data and setting things up, it didn’t take long for us (the agency side of Nebula) to start poking around with Halo API and work out a handy, albeit simple, feature.

This blog introduces our handy Cloudflare > HaloPSA function in the hope it helps others using HaloPSA and Cloudflare domains.

What does the webhook do?

Our PHP-based webhook integrates directly with Cloudflare’s Registrar API and HaloPSA’s ticketing API. In plain English, here’s what it does:

  1. Fetches all domains from Cloudflare – pulling expiry dates via their API.
  2. Checks expiry timelines – looking 0–65 days ahead to flag anything due soon.
  3. Prevents duplicate tickets – scanning recent tickets in HaloPSA to avoid spamming the system.
  4. Creates a renewal ticket automatically – if a domain is within the renewal window and no ticket exists.

Each ticket includes the domain name, its expiry date, and next steps for the support team. That means the right people are notified at the right time, every time.

Why create a webhook?

It’s simple, but it ensures that every domain is looked at by either ourselves or our customer success team.

  • Reliability – Domains won’t slip through the cracks because the system checks daily.
  • Efficiency – Staff don’t waste time manually tracking expiry dates.
  • Proactive support – Clients see that you’re on top of their renewals well before issues arise.
  • Consistency – Tickets always follow the same format, routed to the same team.

From a client’s perspective, this looks like seamless, proactive account management. From a technician’s perspective, it removes a repetitive, error-prone task.

Setup and how it works

For the technically curious, here are some key parts of the process:

  • Cloudflare Registrar API – The webhook queries Cloudflare using authentication headers (X-Auth-Email and X-Auth-Key), returning all domains linked to the account.
  • HaloPSA API – Before creating a ticket, the script authenticates with HaloPSA using client_id and client_secret credentials to obtain a secure access token.
  • Ticket creation – The system then posts a JSON payload to HaloPSA’s /tickets endpoint, including client ID, team, priority, and a structured summary of the renewal.
  • Logging – Every action (skipped domains, created tickets, errors) is written to a log file for transparency and troubleshooting.
  • Cron job – Simple daily cron job to call the webhook.

API Setup

Cloudflare: https://dash.cloudflare.com/profile/api-tokens

HaloPSA: https://halo.example.com/config/integrations/api

For Halo, you’re looking for the Integrations page, within here, you’ll find “Applications” – this is where we’ll set up the necessary authentication.

Within the Application setup, you’ll want to set up the name, authentication method, whilst retrieving the created client ID and client secret.

We use Client ID and Secret (Services) for the Authentication Method.

Ensure you update the permissions tab to include:

Cron job set up

Simple, effective, daily cron job to run whilst I brew the first coffee of the day.

MinuteHourDayMonthWeekdayCommand
308***curl -s https://example.com/domain_expiry.php > /dev/null 2>&1

In short: it’s a daily, unattended helper that handles all the admin around renewals. We’ve stopped development here but there’s 100% scope for improvement!