How to Run Scheduled Health Checks on Your REST APIs and Alert Slack

Build a Spojit workflow that pings several of your REST endpoints on a cron schedule, evaluates their status codes and latency, and posts a consolidated up/down report to Slack only when something is unhealthy.

What This Integration Does

If you run a handful of services, APIs, or third-party dependencies, you want to know the moment one of them starts returning errors or slowing down, without paying for a separate monitoring product or wiring up scripts on a server you have to babysit. This workflow turns Spojit into a lightweight uptime monitor: on a fixed schedule it calls each endpoint you care about, checks whether the response code is healthy and whether the round-trip time stays under your threshold, and pushes a single readable summary into a Slack channel. Because it only alerts when at least one check fails, your team is not buried in green-status noise.

The run model is simple and deterministic. A Schedule trigger fires on a 5-field cron expression (for example every five minutes), producing a {{ scheduledAt }} timestamp. A Parallel node fans out into one branch per endpoint so every check runs concurrently rather than one after another. Each branch uses the http connector's http-get tool in Direct mode to call an endpoint, and an execute-javascript step in the code connector turns the raw response into a clean health verdict. A Condition node then decides whether anything is unhealthy, and only on the unhealthy path does the workflow call Slack's send-message tool. The workflow holds no state between runs: each scheduled execution is independent and self-contained, so a re-run simply re-checks everything from scratch.

Prerequisites

  • A Slack connection added under Connections -> Add connection, with permission to post to your target channel. You will need the channel's ID (for example C0123ABCD), not its display name.
  • The list of endpoints you want to monitor, each as a full URL (for example https://api.example.com/health). Public health endpoints work as-is; protected endpoints need an auth header value ready.
  • The http and code connectors. These are built-in utility connectors in Spojit and require no separate connection or credentials.
  • A latency threshold in mind (for example 800 ms) and agreement on which HTTP status codes count as healthy (typically 200 through 299).

Step 1: Add a Schedule trigger

Create a new workflow in the Spojit designer and set the trigger node type to Trigger with type Schedule. Enter a 5-field Unix cron expression and an IANA timezone. To run every five minutes, use:

*/5 * * * *

Set the timezone to something explicit such as Australia/Sydney or UTC so the schedule does not drift with daylight saving. A single Schedule trigger can hold multiple schedules if you want, for example tighter intervals during business hours. The trigger output is {{ scheduledAt }}, which you can include later in the Slack message so each alert is timestamped.

Step 2: Fan out with a Parallel node

Add a Parallel node directly after the trigger and connect the trigger's output into it. Create one branch per endpoint you want to monitor. Each branch runs concurrently, so total run time is roughly the slowest single endpoint rather than the sum of all of them. Give each branch a clear label such as checkout-api, auth-api, and billing-api so the downstream report reads cleanly. Keep the branch count reasonable (a few up to a couple of dozen); for very large fleets, consider a Loop node over a list instead, but the Parallel pattern is ideal for a fixed, named set of services.

Step 3: Call each endpoint with http-get in Direct mode

Inside each Parallel branch, add a Connector node on the http connector in Direct mode and select the http-get tool. Direct mode is the right choice here because the call is predictable and costs no AI credits. Set the url field to that branch's endpoint, for example https://api.example.com/health. If the endpoint requires authentication, add a headers entry such as Authorization: Bearer YOUR_TOKEN. You can also set timeout in milliseconds so a hung endpoint does not stall the branch; a value like 5000 is a sensible cap.

The http-get response exposes status (the numeric HTTP code such as 200 or 503), statusText, headers, and body. Note the result variable name Spojit assigns to this node (for example checkout_result); you will reference it in the next step.

If your service has no native Spojit tile, this same http-get pattern reaches it directly. For a deeper walkthrough of authenticating arbitrary endpoints, see the related tutorial linked at the end of this article.

Step 4: Evaluate status and latency with execute-javascript

Still inside each branch, add a Connector node on the code connector in Direct mode and select execute-javascript. This step measures latency and produces a tidy verdict object the report can consume. Read the previous step's status and pass in the trigger timestamp so you can compute round-trip time. A representative script:

const status = {{ checkout_result.status }};
const latencyMs = Date.now() - new Date("{{ scheduledAt }}").getTime();
const THRESHOLD_MS = 800;

const codeOk = status >= 200 && status < 300;
const fastEnough = latencyMs < THRESHOLD_MS;

return {
  name: "checkout-api",
  healthy: codeOk && fastEnough,
  status,
  latencyMs,
  reason: !codeOk ? `status ${status}` : (!fastEnough ? `slow ${latencyMs}ms` : "ok")
};

Each branch returns an object with name, healthy, status, latencyMs, and a short reason. Because the branches run inside the Parallel node, every endpoint's verdict is available after the fan-out completes.

Step 5: Build the consolidated report and decide if it is unhealthy

After the Parallel node, add one more code connector node with execute-javascript to gather every branch verdict into a single report and a flag. Reference each branch's verdict variable (for example checkout_health, auth_health, billing_health) and assemble them:

const checks = [
  {{ checkout_health }},
  {{ auth_health }},
  {{ billing_health }}
];

const unhealthy = checks.filter(c => !c.healthy);

const lines = checks.map(c =>
  `${c.healthy ? ":large_green_circle:" : ":red_circle:"} ${c.name} - ${c.reason} (${c.latencyMs}ms)`
);

return {
  anyUnhealthy: unhealthy.length > 0,
  unhealthyCount: unhealthy.length,
  report: lines.join("\n")
};

Now add a Condition node and branch on whether anything failed. Set the condition to check that the report's anyUnhealthy value equals true. The true path leads to the Slack alert; the false path simply ends the run, so a fully healthy check posts nothing and keeps the channel quiet.

Step 6: Post the alert to Slack with send-message

On the Condition node's true output, add a Connector node on the slack connector in Direct mode and select the send-message tool. Set channel to your channel ID (for example C0123ABCD) and set text to a templated summary that pulls in the report you built:

:rotating_light: API health check at {{ scheduledAt }}
{{ report_result.unhealthyCount }} endpoint(s) unhealthy

{{ report_result.report }}

The text field doubles as the notification fallback, so a plain-text summary like this is enough. If you want richer formatting later, send-message also accepts a blocks field for Block Kit layout, and a thread_ts field if you would rather reply in an existing thread. Save the workflow and enable it; from this point the Schedule trigger drives every run.

Tips

  • Set a per-call timeout on each http-get so a single dead endpoint cannot block the whole batch; treat a timeout as an unhealthy result in your execute-javascript verdict.
  • Keep the cron interval honest about your real needs. Every-minute checks multiply executions fast; every five minutes is plenty for most services and keeps run volume sane.
  • Ask Miraxa, the intelligent layer across your automation, to scaffold the fan-out for you with a prompt like "Add a Parallel node with three branches, each calling http-get and then execute-javascript", then fine-tune each branch in the properties panel.
  • For recovery visibility, you can post a single "all clear" message on the next healthy run by tracking state in a database connector such as mongodb, though the simplest version stays stateless and alerts only on failure.

Common Pitfalls

  • The Slack channel field needs the channel ID (like C0123ABCD), not the #name. Use the channel's ID from Slack or look it up first with the slack connector before relying on a name.
  • Latency measured from {{ scheduledAt }} includes the small gap before the branch starts. For precise timing, capture a start time inside the same execute-javascript step right before reading status rather than off the trigger timestamp.
  • An endpoint that returns 200 with an error payload in the body will look healthy by status alone. If your service signals failure in the JSON body, add a body check to the verdict script.
  • Timezones bite schedules: a bare cron without an explicit IANA timezone can fire at unexpected local hours. Always set the timezone field on the Schedule trigger.

Testing

Before turning the schedule loose, validate the logic on a small scope. Start with a single endpoint in one Parallel branch and temporarily lower the cron interval, or use the designer's run controls to fire the workflow on demand. Confirm in the execution log that http-get returns the expected status and that your execute-javascript verdict reads healthy: true for a known-good endpoint. Then point one branch at a URL you know is down (or set an impossibly low latency threshold) to confirm the Condition node routes to Slack and that the send-message call lands in your channel with the right report text. Once both the healthy (silent) and unhealthy (alerting) paths behave, add the rest of your endpoints and restore the real interval.

Learn More

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