If you've ever tried to debug a webhook integration inside a GitHub Actions workflow, you know the pain.
Your CI pipeline fires a webhook to an external service. Something goes wrong. You have no idea what payload actually got sent — GitHub's UI shows you the trigger, not what your workflow delivered downstream.
The usual answer is ngrok: spin up a tunnel, expose a local server, redirect your webhook, inspect it manually. It works, but it's tedious, stateful, and dies the moment your laptop sleeps.
There's a better way.
The Problem in Detail
Say you have a workflow like this:
name: Notify on Deploy
on:
push:
branches: [main]
jobs:
notify:
runs-on: ubuntu-latest
steps:
- name: Send deploy webhook
run: |
curl -X POST ${{ secrets.WEBHOOK_URL }} \
-H "Content-Type: application/json" \
-d '{"ref": "${{ github.ref }}", "sha": "${{ github.sha }}", "actor": "${{ github.actor }}"}'
When this breaks, you want to see the exact payload that was sent — headers, body, response code. But:
- GitHub shows you workflow logs, not what the receiving server saw
- If your target URL is broken or returns a 500, you can't see what it received
- Replay is impossible without re-triggering the whole pipeline
Using a Webhook Inspection Endpoint
HookTest lets you create a disposable HTTPS endpoint that captures every request — headers, body, method, timestamp. No install, no local server, no tunnels.
Here's how to wire it into the workflow above:
Step 1: Create a test endpoint
curl -X POST https://hooktest.peakline-ops.workers.dev/api/endpoints \
-H "Content-Type: application/json" \
-d '{"label": "github-actions-debug"}'
Response:
{
"id": "abc123",
"url": "https://hooktest.peakline-ops.workers.dev/w/abc123",
"label": "github-actions-debug"
}
Step 2: Point your test run at it
Temporarily swap your WEBHOOK_URL secret for the HookTest endpoint URL, or add a parallel debug step:
- name: Debug webhook payload
if: env.DEBUG_WEBHOOKS == 'true'
run: |
curl -X POST https://hooktest.peakline-ops.workers.dev/w/abc123 \
-H "Content-Type: application/json" \
-H "X-GitHub-Run-ID: ${{ github.run_id }}" \
-d '{"ref": "${{ github.ref }}", "sha": "${{ github.sha }}", "actor": "${{ github.actor }}"}'
Set DEBUG_WEBHOOKS=true as a repo variable when debugging, false in production. Zero secrets exposed.
Step 3: Inspect the captured request
curl https://hooktest.peakline-ops.workers.dev/api/endpoints/abc123/requests
You'll get back everything:
[
{
"id": "req_xyz",
"method": "POST",
"headers": {
"content-type": "application/json",
"x-github-run-id": "12345678"
},
"body": "{\"ref\":\"refs/heads/main\",\"sha\":\"a1b2c3d4\",\"actor\":\"octocat\"}",
"captured_at": "2026-03-29T10:23:45Z"
}
]
Step 4: Replay to the real target when ready
curl -X POST https://hooktest.peakline-ops.workers.dev/api/requests/req_xyz/replay \
-H "Content-Type: application/json" \
-d '{"target_url": "https://your-real-service.com/webhook"}'
Replay lets you test your receiving service without re-triggering the entire CI pipeline.
Dashboard View
If you prefer a visual interface, the HookTest dashboard gives you a real-time view of all captured requests with full header and body inspection. No account required for the free tier.
Pro Tips for CI/CD Webhook Debugging
1. Add a GitHub run ID header to every webhook
Always include X-GitHub-Run-ID: ${{ github.run_id }} in your outgoing webhooks. This lets you correlate captured payloads back to specific pipeline runs in the GitHub UI.
2. Test the receiving service in isolation
Capture your payload once with HookTest, then replay it repeatedly against your service as you iterate — no need to keep pushing commits.
3. Use transform rules to sanitize before forwarding
HookTest's Pro tier supports transform rules: mask sensitive fields (like tokens), rename fields for compatibility, or filter out requests by header value. Useful when your payload contains secrets you don't want stored in plain text.
4. Temporary endpoints are free
Free tier endpoints auto-expire after 24 hours. For debugging a CI pipeline, that's usually enough. Pro endpoints persist indefinitely, which is useful for long-running test environments.
Why Not Just Log the Payload in the Workflow?
You can — and you should — add echo statements or cat the payload in your workflow logs. But that only shows you what you sent. It doesn't show you what your receiving server saw (after any proxies, load balancers, or CDN rewrites), what headers arrived, or how the response looked. An inspection endpoint captures the full inbound request as the server sees it.
HookTest is free to use at hooktest.peakline-ops.workers.dev. Free tier: 3 endpoints, 24-hour expiry, 100 requests per endpoint. Pro ($9/mo): 10 persistent endpoints, transform rules, unlimited requests.
Happy debugging.
Top comments (0)