How to Validate SSL Certificate Expiry for Your Endpoints and Notify the Team

Build a scheduled Spojit workflow that loops over your domains, reads each certificate's expiry date from a certificate-info REST API, computes the days remaining, and sends an early-warning email plus a Slack message whenever a certificate is inside your renewal window.

What This Integration Does

Expired TLS certificates take endpoints offline and erode customer trust, and the renewal email from your certificate authority is easy to miss. This workflow turns certificate monitoring into a hands-off background job: every weekday morning it walks a list of your domains, asks a certificate-info service when each certificate expires, and works out how many days are left. When any certificate falls inside the renewal window you choose (for example 30 days), it emails the platform owner and posts a Slack message to your operations channel so someone can act before the certificate lapses.

The workflow runs on a Schedule trigger, so no human starts it. On each run it iterates your domain list with a Loop node, calls a certificate-info REST API with the http connector, and uses the date and code connectors to calculate days-until-expiry. A Condition node decides whether each domain is inside the window. Notifications fire only for domains that need attention, and the run leaves no stored state: every execution is a fresh, independent check, so re-runs are safe and simply re-evaluate the same domains against the current date.

Prerequisites

  • A Spojit workspace where you can create and enable workflows.
  • A list of the domains (endpoints) you want to monitor, plus your renewal-window threshold in days (for example 30).
  • Access to a certificate-info REST API that returns a certificate's expiry date for a given host. Any HTTPS certificate-lookup service that accepts a host and returns an ISO expiry timestamp works; you reach it with the http connector, so no native tile is required.
  • A Slack connection added under Connections, with permission to post to your operations channel, plus the channel ID or name.
  • Your notification recipients added to the org allowlist under Settings -> General -> Email recipients if they are external to your workspace.

Step 1: Start the workflow on a Schedule trigger

Create a new workflow and open the Workflow Designer. Add a Trigger node and set Trigger Type to Schedule. Enter a 5-field cron expression and an IANA timezone so the check runs every weekday morning, for example 0 8 * * 1-5 with timezone Australia/Sydney. A schedule trigger can hold multiple schedules if you want both a morning and an evening sweep. The trigger output is {{ scheduledAt }}, which you do not need to map downstream because the domain list is defined in the next step.

Step 2: Define your domain list with a Transform node

Add a Transform node to produce the array of domains you want to check. Output a small object such as:

{
  "domains": [
    "www.example.com",
    "api.example.com",
    "shop.example.com"
  ],
  "warningDays": 30
}

This keeps the list and the renewal threshold in one place. Reference them later as {{ domains.domains }} and {{ domains.warningDays }} (name the node output variable domains). If you prefer to keep the list outside the workflow, you can instead fetch it from a database or a file, but a Transform node is the simplest starting point.

Step 3: Loop over each domain

Add a Loop node, set the mode to ForEach, and point it at {{ domains.domains }}. Each iteration exposes the current domain as the loop item, for example {{ domain }} if you name the item variable domain. Everything in the next steps lives inside the loop body so it runs once per domain. Keep the list modest (tens of domains) to stay well within a single run; for hundreds of endpoints, split them across separate scheduled workflows.

Step 4: Read each certificate's expiry with the http connector

Inside the loop body, add a Connector node on the http connector in Direct mode and choose the http-get tool. Point it at your certificate-info REST API, passing the current domain as a query parameter or path segment. For example, set the URL to:

https://api.yourcertservice.com/v1/certificate?host={{ domain }}

Add an Authorization header with your API key if the service requires one. Name the output variable cert. A typical response exposes the expiry timestamp at a field such as {{ cert.data.validTo }} in ISO 8601 form (for example 2026-08-15T23:59:59Z). If your service nests the field differently, use the json connector's get tool to pull the exact path. For background on calling non-native services this way, see the related tutorial linked at the end of this article.

Step 5: Compute days until expiry with the date and code connectors

Add a Connector node on the date connector in Direct mode and choose the diff tool. Map its inputs so it measures from now to the expiry date:

date1 = {{ cert.data.validTo }}
date2 = (leave empty to use the current date, or pass {{ scheduledAt }})
unit  = day

The diff tool returns { value, unit }, so the whole number of days remaining is available as {{ daysLeft.value }} when you name the output variable daysLeft. If you need extra logic (rounding, ignoring already-expired hosts, or combining several certificate fields), add a Connector node on the code connector and use execute-javascript to refine the number. A minimal script that normalizes the value and flags expired certificates looks like:

const days = Math.floor(input.daysLeft);
return {
  days,
  expired: days < 0,
  host: input.host
};

Pass {{ daysLeft.value }} and {{ domain }} into the script inputs as daysLeft and host, and name this node's output check.

Step 6: Branch on the renewal window with a Condition node

Add a Condition node that evaluates whether the certificate is inside your warning window. Configure the test as {{ check.days }} is less than or equal to {{ domains.warningDays }}. The true branch handles certificates that need attention; the false branch does nothing and the loop simply moves on to the next domain. If you also want to call out already-expired certificates with stronger wording, add a second nested Condition on {{ check.expired }} inside the true branch.

Step 7: Notify the team by email and Slack

On the true branch, add a Send Email node so the certificate owner gets an early warning straight from Spojit's built-in mail service. Set Recipients to your platform owner address, a templated Subject such as Certificate expiring soon: {{ domain }}, and a Body like:

Heads up: the TLS certificate for {{ domain }}
expires in {{ check.days }} day(s) (on {{ cert.data.validTo }}).
Please renew it before it lapses.

Then add a Connector node on the slack connector in Direct mode and choose the send-message tool. Set the channel to your operations channel and the text to a short summary, for example :warning: {{ domain }} certificate expires in {{ check.days }} days. Because both notifications sit inside the true branch of the loop, they fire only for the domains that actually fall inside the window, once per affected domain. You can have Miraxa, the intelligent layer across your automation, scaffold this branch for you with a prompt like "Add a Send Email node and a Slack send-message node on the true branch of my Condition node that report {{ domain }} and {{ check.days }}", then fine-tune the fields in the properties panel.

Tips

  • Keep the renewal window generous (30 days or more) so there is time to order, validate, and deploy a replacement certificate before the old one expires.
  • Use the date connector's diff with unit set to day for whole-day countdowns; switch to hour only if you monitor very short-lived certificates.
  • If your certificate-info service rate-limits requests, keep the domain list small per workflow or add a brief code step to space out calls, and split large estates across several scheduled workflows.
  • Group the alerts: instead of one Slack message per domain, collect the at-risk hosts into an array during the loop and send a single digest message after it. This is quieter for busy channels.

Common Pitfalls

  • Timezone drift: the diff result depends on the current moment, so always set an explicit IANA timezone on the Schedule trigger to avoid off-by-one-day surprises near midnight.
  • Wrong expiry field: certificate-info APIs name the expiry field differently (validTo, not_after, expires). Inspect a real response in the execution logs and map the exact path before trusting {{ check.days }}.
  • Already-expired hosts: a negative day count still satisfies a "less than or equal to" test, which is usually what you want, but make the message wording clear so the team can tell "expires soon" from "already expired".
  • External recipients blocked: the Send Email node only delivers to addresses on your org allowlist. Add any external recipient under Settings -> General -> Email recipients first, or the send will fail.

Testing

Before enabling the schedule, validate the logic on a small scope. Temporarily reduce the Transform node's domain list to one or two hosts, including one with a known near-term expiry, and set warningDays high (for example 3650) so the Condition branch is guaranteed to fire. Trigger a run manually from the designer and open the execution logs to confirm the http-get response, the diff output, and the computed {{ check.days }} value, then check that the email and the Slack message arrived. Once the numbers look right, restore your full domain list and your real renewal window, and enable the workflow so the Schedule trigger takes over.

Learn More

Did this answer your question? Thanks for the feedback There was a problem submitting your feedback. Please try again later.