🚀 Executive Summary

TL;DR: This guide provides a solution for automating API endpoint uptime monitoring, eliminating the need for manual checks. It leverages a simple Python script and GitHub Actions to create a serverless, scheduled health check that notifies users via webhooks when an API endpoint is down.

🎯 Key Takeaways

  • A Python script (`health_check.py`) uses the `requests` library to perform GET requests to API endpoints, checking for 2xx status codes and sending notifications via a webhook URL for any failures or exceptions.
  • GitHub Actions orchestrates the monitoring by running the Python script on a defined schedule (e.g., every 15 minutes using `cron: ‘*/15 * * * *’`) and supports manual triggering via `workflow_dispatch`.
  • Sensitive configuration data like `ENDPOINT_URL` and `WEBHOOK_URL` are securely managed using GitHub Repository Secrets, which are then passed as environment variables to the GitHub Actions workflow.

Build a Simple uptime monitor for API Endpoints using GitHub Actions

Build a Simple uptime monitor for API Endpoints using GitHub Actions

Hey everyone, Darian Vance here. I want to share a quick automation that has genuinely saved me a ton of headaches. For a long time, part of my morning routine was to manually check the status pages and skim the logs for our critical API endpoints. It felt like due diligence, but I eventually realized I was wasting at least 30 minutes every single day on something a simple script could do. So, I built one.

Today, I’m going to walk you through how to build a dead-simple, serverless uptime monitor using a Python script and a GitHub Actions workflow. This is a “set it and forget it” solution that only notifies you when something is actually wrong. It’s incredibly valuable and takes less than 15 minutes to set up.

Prerequisites

  • A GitHub repository (can be a new, empty one).
  • A basic understanding of Python and Git.
  • An API endpoint URL you want to monitor.
  • A webhook URL to send failure notifications (I use Slack or Discord for this).

The Guide: Step-by-Step

Step 1: The Python Health Check Script

First, let’s write the heart of our monitor. This script will do three things: read our configuration, send a request to our API endpoint, and if the response isn’t what we expect, it’ll fire a notification to our webhook.

I’ll skip the standard virtual environment setup since you likely have your own workflow for that. Let’s jump straight to the logic. You’ll need a couple of Python packages, which you can typically install with a command like pip install requests python-dotenv.

In your project directory, create a script named health_check.py. This is what it looks like:


import os
import requests
from dotenv import load_dotenv

def check_endpoint():
    # Load environment variables from a config.env file
    load_dotenv(dotenv_path='config.env')

    # Get the URL and webhook from environment variables
    endpoint_url = os.getenv('ENDPOINT_URL')
    webhook_url = os.getenv('WEBHOOK_URL')

    if not endpoint_url or not webhook_url:
        print("Error: ENDPOINT_URL and WEBHOOK_URL must be set.")
        return

    try:
        # I highly recommend setting a timeout.
        response = requests.get(endpoint_url, timeout=10)

        # Check for any status code that is NOT in the 200-299 range
        if not response.ok:
            message = f"🚨 Alert: Endpoint {endpoint_url} is down! Status: {response.status_code}"
            send_notification(webhook_url, message)
        else:
            print(f"âś… Success: Endpoint {endpoint_url} is up. Status: {response.status_code}")

    except requests.exceptions.RequestException as e:
        message = f"🚨 Alert: Endpoint {endpoint_url} failed with an exception: {e}"
        send_notification(webhook_url, message)

def send_notification(webhook_url, message):
    # This payload structure is common for Slack/Discord webhooks
    payload = {'content': message}
    try:
        requests.post(webhook_url, json=payload)
        print("Notification sent.")
    except requests.exceptions.RequestException as e:
        print(f"Failed to send notification: {e}")

if __name__ == "__main__":
    check_endpoint()

The logic is straightforward: it makes a GET request and checks if the status code is a success (response.ok covers all 2xx codes). If it fails for any reason—a 404, a 503, or even a network timeout—it calls the send_notification function.

Pro Tip: Always use a timeout in your requests. In my production setups, I’ve seen scripts hang indefinitely waiting for a response from a frozen server. A 10-second timeout is a reasonable starting point to prevent your GitHub Action runner from getting stuck.

Step 2: The GitHub Actions Workflow

Now we need an orchestrator to run our script automatically. GitHub Actions is perfect for this. We’ll set up a workflow that runs on a schedule.

In your repository, create the directory structure .github/workflows/. Inside that, create a file named monitor.yml. Here’s the YAML configuration:


name: API Uptime Monitor

on:
  schedule:
    # Runs every 15 minutes
    - cron: '*/15 * * * *'
  workflow_dispatch: # Allows manual triggering

jobs:
  check-api-status:
    runs-on: ubuntu-latest
    steps:
      - name: Check out repository code
        uses: actions/checkout@v3

      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.10'

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install requests python-dotenv

      - name: Run health check script
        run: python health_check.py
        env:
          ENDPOINT_URL: ${{ secrets.ENDPOINT_URL }}
          WEBHOOK_URL: ${{ secrets.WEBHOOK_URL }}

Let’s break this down:

  • on.schedule.cron: This is the magic. '*/15 * * * *' tells GitHub to run this job every 15 minutes. You can adjust this to your needs.
  • workflow_dispatch: A nice-to-have that adds a button in the Actions tab to run the workflow manually. Great for testing.
  • jobs: We define one job that runs on the latest Ubuntu runner.
  • steps: It checks out your code, sets up Python, installs the dependencies from our script, and finally, runs the script.
  • env: This is the crucial part. We are securely passing the secrets we’re about to configure into the script as environment variables. Our Python script will read these using os.getenv().

Step 3: Configuring Repository Secrets

We never, ever hardcode sensitive information like URLs or webhooks directly into our code. That’s what GitHub’s encrypted secrets are for.

  1. In your GitHub repository, go to Settings.
  2. In the left sidebar, navigate to Secrets and variables > Actions.
  3. Click the New repository secret button.
  4. Create a secret named ENDPOINT_URL and paste your API endpoint URL as the value.
  5. Click Add secret.
  6. Repeat the process to create another secret named WEBHOOK_URL with your Slack/Discord webhook URL.

Once you commit these files (health_check.py and .github/workflows/monitor.yml) and push them to your repository, the Action will automatically start running on its defined schedule.

Common Pitfalls

Here are a couple of spots where I usually mess up when setting this up from scratch:

  • Secret Name Mismatch: I’ve spent way too long debugging a workflow only to realize I named my secret ENDPOINT in the GitHub UI but called it ENDPOINT_URL in my YAML file. They must match exactly.
  • Incorrect Cron Syntax: I once accidentally set a monitor to run every minute instead of every hour. My service survived, but my logs were a mess. Use a tool like crontab.guru to validate your schedule before committing.
  • Forgetting .gitignore: If you test locally with a config.env file, make sure to add it to your .gitignore file. You never want to commit credentials, even for a test environment. The Action will use the secure repository secrets, not this local file.

Conclusion

And that’s it. For the low cost of zero dollars and about 15 minutes of your time, you now have a reliable, serverless uptime monitor. This simple pattern is incredibly powerful. You can easily expand it to check multiple endpoints, validate the JSON response body, or even create a GitHub Issue automatically when a check fails.

It’s a perfect example of a small automation that delivers significant peace of mind. Let me know if you run into any issues or come up with cool extensions for it.

Darian Vance - Lead Cloud Architect

Darian Vance

Lead Cloud Architect & DevOps Strategist

With over 12 years in system architecture and automation, Darian specializes in simplifying complex cloud infrastructures. An advocate for open-source solutions, he founded TechResolve to provide engineers with actionable, battle-tested troubleshooting guides and robust software alternatives.


🤖 Frequently Asked Questions

âť“ How can I monitor API endpoint uptime using serverless tools?

You can monitor API endpoint uptime using a serverless approach by combining a Python script for health checks with GitHub Actions. The script makes requests to your API, and GitHub Actions schedules its execution, sending notifications via webhooks (e.g., Slack, Discord) upon detecting downtime or errors.

âť“ How does this GitHub Actions uptime monitor compare to dedicated monitoring services?

This GitHub Actions-based monitor offers a free, serverless, and highly customizable solution, requiring minimal setup and leveraging existing GitHub infrastructure. While dedicated services often provide more advanced features like global checks, detailed dashboards, and incident management, this method is excellent for basic, cost-effective, and self-hosted uptime checks with full control over the logic.

âť“ What are common pitfalls when setting up this uptime monitor?

Common pitfalls include ensuring exact matches between GitHub secret names and their references in the workflow YAML, validating cron syntax to prevent unintended run frequencies (e.g., using `crontab.guru`), and adding local `config.env` files to `.gitignore` to prevent accidental credential exposure.

Leave a Reply

Discover more from TechResolve - SaaS Troubleshooting & Software Alternatives

Subscribe now to keep reading and get access to the full archive.

Continue reading