How to Get a Domain's Expiration Date in PHP

November 04, 2026
How to Get a Domain's Expiration Date in PHP

You need to programmatically check when a domain will expire so you can renew it on time, suspend risky signups from throwaway domains, or alert account owners before their site goes dark. By the end of this guide, you’ll call Klazify’s domain expiration endpoint, parse the exact expiration date, and wire the result into your PHP workflow with sane caching and retry logic.

Why Klazify is the Best API for Monitoring Domain Expiration in PHP

When your application depends on accurate domain lifecycle data, the API you choose needs to deliver reliable, current registration dates fast and at scale. Klazify is built for developers who enrich or govern domains in production pipelines, and its strengths map cleanly to expiration tracking in PHP-based systems:

Illustration: How to Get a Domain's Expiration Date in PHP
  • Accurate Website Categorization Using AI: Even if your primary goal is expiration monitoring, you can combine it with Klazify’s content analysis to make decisions like “only renew if the site remains active in our target category.” Classification works by analyzing full website content, not just metadata, which helps you set better rules around renewal and domain hygiene.
  • Global Coverage: Domains from different registrars and languages appear in your queue. Klazify handles multi-language sites and broad domain coverage so your expiration checks don’t stall on international properties.
  • Real-Time Classification: Registration data and site content both evolve. Klazify prioritizes fresh analysis, so when you recheck a domain nearing expiration, you’ll see current values rather than stale lookups.
  • Industry-Level Categories (IAB): If your renewal or risk logic depends on industry verticals, Klazify’s IAB taxonomy helps you filter—e.g., maintain stricter renewal windows for regulated categories—without building your own classifier.
  • Simple API Integration: A clean REST interface with a single POST call for expiration means you can add this to any PHP app with a short cURL snippet or an HTTP client in minutes.
  • Superior Compliance and Filtering: Combine expiration data with brand safety or content categorization to decide whether to keep domains active, flag questionable signups, or block traffic when a domain is close to expiry.

What you’ll build: pull a domain’s expiration date and take action

We’ll fetch a domain’s expiration date and remaining days, then show you how to:

  • Cache the result to avoid repeat calls.
  • Trigger alerts when a threshold (e.g., days left) is crossed.
  • Handle unknown or recently registered domains gracefully.
  • Batch checks across many domains while respecting rate limits.

If you don’t have an account yet, start with the Starter plan ($39.99/mo) and a 7-day trial. Failed or unreachable calls are not billed, which helps you iterate safely. Create your key here: Register. Refer to the full API reference anytime: Documentation. For management and control features, see MCP.

The endpoint you’ll use

To retrieve domain expiration data, call:

  • POST https://www.klazify.com/api/domain_expiration

Authentication: Bearer token in the Authorization header.

Body (JSON): {"url":"https://example.com"}

cURL example

curl -X POST "https://www.klazify.com/api/domain_expiration" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://cbsnews.com"}'

Request notes:

  • Send a full URL or a bare domain—Klazify will resolve it.
  • Use HTTPS for transport; dates are returned as ISO-format strings.

Response fields you’ll use

This call returns the domain’s registration-age date and days, as well as the expiration date and days left before expiry. These are the fields to read:

  • domain_age_date
  • domain_age_days_ago
  • domain_expiration_date
  • domain_expiration_days_left

In many Klazify responses, these are grouped under domain_registration_data. The complete example below shows these fields exactly as provided by the Klazify sample (in the context of a categorization response). We’ll use the same field names in code to keep your integration consistent if you combine endpoints.


{
    "domain": {
        "categories": [
            {
                "confidence": 0.92,
                "name": "/Computers & Electronics/Consumer Electronics",
                "IAB-632-596": "Consumer Electronics/Technology & Computing/Consumer Electronics"
            },
            {
                "confidence": 0.89,
                "name": "/Internet & Telecom/Mobile & Wireless/Mobile Phones"
            }
        ],
        "social_media": null,
        "logo_url": "https://klazify.s3.amazonaws.com/2110787991611585019600ed5fb1d1300.04730104.png"
    },
    "success": true,
    "objects": {
        "company": {
            "url": "https://www.apple.com/",
            "name": "Apple",
            "city": "Cupertino",
            "stateCode": "CA",
            "countryCode": "US",
            "employeesRange": "100K+",
            "revenue": 274515000000,
            "raised": null,
            "tags": [
                "E-commerce",
                "Consumer Electronics",
                "Mobile",
                "B2C"
            ],
            "tech": [
                "omniture_adobe_analytics",
                "atlassian_confluence",
                "successfactors",
                "apache_apex",
                "talend",
                "oracle_peoplesoft",
                "salesforce",
                "stripe",
                "dell_boomi_atomsphere",
                "gigya",
                "sage_50cloud",
                "quickbooks",
                "webmethods",
                "apache_tomcat",
                "alteryx",
                "tibco_rendezvous",
                "atlassian_jira",
                "..."
            ]
        }
    },
    "domain_registration_data": {
        "domain_age_date": "1987-02-19",
        "domain_age_days_ago": "13026",
        "domain_expiration_date": "2030-02-20",
        "domain_expiration_days_left": "123"
    },
    "similar_domains": [
        "bestbuy.com",
        "icloud.com",
        "microsoft.com",
        "macrumors.com",
        "google.com",
        "samsung.com",
        "twitter.com",
        "hp.com",
        "bhphotovideo.com",
        "dell.com"
    ]
}

How to use these fields:

  • domain_expiration_date (YYYY-MM-DD): Store as a date in UTC. Use it to schedule renewal attempts and to show users a calendar date.
  • domain_expiration_days_left (string number): Convert to integer for threshold logic (e.g., alert when less than 30 days).
  • domain_age_date (YYYY-MM-DD) and domain_age_days_ago (string number): Useful to flag very new domains during signups or fraud checks.

Field meanings and common actions

Field Type Meaning Typical Action
domain_expiration_date string (YYYY-MM-DD) Registrar expiration (date-only, treat as UTC) Schedule renewal, notify owner, block ad placements if past date
domain_expiration_days_left string (numeric) Days until expiration Trigger alerts at thresholds (e.g., 60/30/7), escalate if near 0
domain_age_date string (YYYY-MM-DD) Date the domain was first registered Score signups lower if domain is very new; deprioritize ad buys
domain_age_days_ago string (numeric) Days since first registration Aggregate for analytics; define age-based segments/policies

JavaScript example: read days left and alert

This Node.js snippet calls the expiration endpoint and handles the key fields. You can run it as a cron job or inside a queue worker.

import fetch from "node-fetch";

const API_URL = "https://www.klazify.com/api/domain_expiration";
const API_KEY = process.env.KLAZIFY_API_KEY || "YOUR_API_KEY";

async function fetchExpiration(url) {
  const res = await fetch(API_URL, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${API_KEY}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({ url })
  });

  if (!res.ok) {
    // Non-2xx are not billed if the call failed or was unreachable.
    // Log and retry with backoff.
    const text = await res.text();
    throw new Error(`Klazify error ${res.status}: ${text}`);
  }

  const data = await res.json();

  // The fields we need commonly live under data.domain_registration_data
  const reg = data.domain_registration_data || {};
  const expDate = reg.domain_expiration_date;       // "YYYY-MM-DD"
  const daysLeftStr = reg.domain_expiration_days_left; // string number
  const daysLeft = daysLeftStr != null ? parseInt(daysLeftStr, 10) : null;

  return {
    expirationDate: expDate,
    daysLeft,
    ageDate: reg.domain_age_date || null,
    ageDays: reg.domain_age_days_ago != null ? parseInt(reg.domain_age_days_ago, 10) : null
  };
}

(async () => {
  const domainToCheck = "https://example.com";
  try {
    const result = await fetchExpiration(domainToCheck);
    console.log(result);

    // Example threshold logic
    if (result.daysLeft != null) {
      if (result.daysLeft <= 7) {
        // escalate
        console.error(`URGENT: ${domainToCheck} expires in ${result.daysLeft} days (${result.expirationDate}).`);
      } else if (result.daysLeft <= 30) {
        console.warn(`Heads up: ${domainToCheck} expires in ${result.daysLeft} days.`);
      }
    }
  } catch (err) {
    console.error("Failed to fetch domain expiration:", err.message);
  }
})();

Integration tip: Parse these as date-only values and treat them as UTC to avoid off-by-one issues around local midnight. For dashboards, show both the date and days left—the latter is best for threshold-driven actions.

PHP quick call with cURL

If you are wiring this check directly inside a PHP controller or job, this minimal example demonstrates the request. Keep the retry, caching, and alerting logic in your service layer.

<?php
$apiUrl = "https://www.klazify.com/api/domain_expiration";
$apiKey = "YOUR_API_KEY";
$payload = json_encode(["url" => "https://example.com"]);

$ch = curl_init($apiUrl);
curl_setopt_array($ch, [
  CURLOPT_POST => true,
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    "Authorization: Bearer {$apiKey}",
    "Content-Type: application/json"
  ],
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_TIMEOUT => 20
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($response === false || $httpCode >= 400) {
  // Not billed for failed/unreachable calls; handle retry/backoff
  error_log("Klazify error: " . curl_error($ch) . " (HTTP {$httpCode})");
  curl_close($ch);
  exit;
}
curl_close($ch);

$data = json_decode($response, true);
$reg = $data["domain_registration_data"] ?? [];
$expDate = $reg["domain_expiration_date"] ?? null;
$daysLeft = isset($reg["domain_expiration_days_left"]) ? (int)$reg["domain_expiration_days_left"] : null;

// Example threshold
if ($daysLeft !== null && $daysLeft <= 30) {
  // Notify owner or create a task
  error_log("Domain expires soon: {$expDate} ({$daysLeft} days left)");
}

Pipeline design: batching, caching, retries, and alerts

When you scale expiration checks across thousands of domains, build a small control loop with these pieces:

  • Batching: Group domains per job run. Keep batch sizes modest and parallelize workers to hit your throughput goal while staying under rate limits.
  • Caching per domain: Cache domain_registration_data keyed by the registrable domain (e.g., example.com). Set a dynamic TTL: for domains with many days left, refresh less frequently; for those nearing expiration, refresh more often. Store the last-seen payload and timestamp.
  • Retry and backoff: Network errors or transient service issues can happen. Implement exponential backoff and jitter. Because failed or unreachable calls are not billed, safe retries won’t impact cost unexpectedly.
  • Idempotency: Avoid duplicating notifications by storing “last alerted threshold” per domain (e.g., fired at 30 days, do not fire again until 7 days).
  • Observability: Log http_code, latency, and the values of domain_expiration_date and domain_expiration_days_left. Emit metrics for counts of domains in each threshold band.

Handling edge cases and unknowns

  • New or obscure domains: Some domains may have sparse data or recent registrations. If domain_expiration_date is missing, flag the record for manual review or retry after a backoff interval.
  • Registrar anomalies: Treat the date fields as authoritative if present. If the days-left number and the date appear inconsistent (e.g., due to timezone math in your system), prefer the date for long-term scheduling and compute your own delta in UTC.
  • Redirects and subpages: Always normalize to the registrable domain for caching and threshold logic. You can pass a full URL in the call; cache the result under the effective domain (e.g., example.com).
  • Combining with classification: If you also need to gate renewals or signups by topic (e.g., only certain industries), use Klazify categorization in the same pipeline. The domain_registration_data structure appears in that context as well, simplifying your data model.

Optional: correlate expiration with categorization

You can enrich decisions by checking both the expiration data and how Klazify categorizes the site. For example, if a domain is expiring soon and is categorized as a low-priority vertical for your business, you might defer a renewal. The sample above shows how categorization and domain_registration_data can be consumed together. If you need the full categorization endpoint for that purpose, refer to the Documentation.

Operational notes: rate limits, costs, and environments

  • Rate limits: Implement a client-side limiter (token bucket or leaky bucket) and plan for 429 handling. Throttle concurrent requests and queue excess.
  • Costs: The Starter plan is $39.99/mo and comes with a 7-day trial, suitable for development and initial rollout. Because failed or unreachable calls are not billed, you can safely test resilience.
  • Environments: Keep separate API keys for dev/staging/prod. In dev, stub responses with the official example to speed front-end and workflow work; in prod, always validate the JSON contract before writing to your DB.
  • Data hygiene: Normalize all dates to UTC and store both the raw string and a computed epoch for fast comparisons and sorting.

Putting it all together: event flow

  1. Collector pulls a batch of domains from your DB queue.
  2. For each domain, check cache. If stale or missing, POST to /api/domain_expiration with a backoff-aware client.
  3. Parse domain_registration_data:
    • Store domain_expiration_date and domain_expiration_days_left.
    • Update a next-check-at timestamp based on days left.
    • If days left crosses a threshold, enqueue notifications or renewal tasks.
  4. Emit metrics for observability and create audit logs including the received dates.
  5. Repeat on a schedule; for near-expiry domains, recheck more frequently.

Testing and validation checklist

  • Unit test: JSON parsing for domain_registration_data with and without missing fields.
  • Integration test: Simulate non-2xx responses and ensure you do not double-charge your pipeline or over-alert.
  • Time math: Verify your UTC difference calculation between today and domain_expiration_date matches domain_expiration_days_left.
  • Idempotency: Run your batch twice in quick succession; ensure no duplicate alerts when state hasn’t changed.

FAQ

Does the endpoint require the full URL or just the domain?
You can provide either; using a full URL is fine. Internally, cache and key results by the registrable domain (e.g., example.com).

How often should I recheck a domain?
Use a dynamic schedule: check less often when many days are left and more often as the threshold approaches. Persist next-check-at per domain and update it after each response.

What happens if the API call fails?
Implement retries with backoff. Failed or unreachable calls are not billed, so you can safely retry without cost surprises.

How do I align this with my own taxonomy or business rules?
If your workflow also depends on industry or content type, call Klazify’s categorization and map IAB categories to your internal labels. Apply your expiration thresholds per label as needed.

Are dates timezone-aware?
Treat returned dates as date-only strings and normalize to UTC in your system. For threshold math, compute deltas in UTC to avoid off-by-one issues.

Ready to implement domain expiration checks in your PHP stack with a few lines of code? Create your free trial key and start integrating today: Register. Explore all available fields and endpoints in the Documentation and manage your setup with MCP.

Ready to use Klazify?

Start classifying websites, enriching company data, and exploring web intelligence.

Get Started Free