integrations

FastAPI

A complete Python receiver using FastAPI. Handles signature verification, filters by job type, logs each posting, and returns a fast 200.

Dependencies

pip install fastapi uvicorn

main.py

# main.py
import hmac
import hashlib
import json
import logging
from fastapi import FastAPI, Header, HTTPException, Request

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

app = FastAPI()
WEBHOOK_SECRET = "replace-with-your-sign-key"


def verify_signature(jobs: list[dict], secret: str, received: str) -> bool:
    canonical = json.dumps(
        sorted(jobs, key=lambda j: j["url"]),
        sort_keys=True,
        separators=(",", ":"),
    )
    expected = hmac.new(
        secret.encode("utf-8"),
        canonical.encode("utf-8"),
        hashlib.sha256,
    ).hexdigest()
    return hmac.compare_digest(expected, received)


@app.post("/webhook")
async def receive_webhook(
    request: Request,
    webhook_signature: str = Header(..., alias="webhook-signature"),
):
    body = await request.json()
    jobs: list[dict] = body.get("data", [])

    if not verify_signature(jobs, WEBHOOK_SECRET, webhook_signature):
        raise HTTPException(status_code=401, detail="Invalid signature")

    for job in jobs:
        # Skip test events in production
        if job.get("is_test"):
            logger.info("Skipping test event")
            continue

        # Filter by job type
        if job.get("is_intern"):
            logger.info("Internship: %s at %s", job.get("title"), job.get("company_name"))
        elif job.get("is_fte"):
            logger.info("FTE: %s at %s", job.get("title"), job.get("company_name"))

    return {"ok": True, "received": len(jobs)}

Run it

uvicorn main:app --reload --port 8000

Local testing with ngrok

Freshbatch needs a public URL to POST to. During local development, use ngrok to tunnel your local server:

# In a separate terminal
ngrok http 8000

# Copy the https:// URL ngrok gives you, e.g.:
# https://abc123.ngrok-free.app/webhook
# Paste that into Dashboard Settings as your webhook URL

For signature verification details, see Signature Verification — Python