Test Sume webhooks locally with ngrok or a Cloudflare Tunnel
Sume refuses localhost webhook URLs. Expose your handler with ngrok or a Cloudflare Quick Tunnel, send a signed test, then redeliver real events.

To test Sume webhooks on localhost, run your handler on a local port, expose it with ngrok http 8080 or cloudflared tunnel --url http://localhost:8080, and register the tunnel's HTTPS URL plus your handler's path as the webhook URL. Sume refuses localhost, private-network, and non-HTTPS webhook URLs, so a public HTTPS tunnel is what makes a local handler reachable.
Sume ships no connector for either tool; each one forwards Sume's POST to your port like any other public request. Sume facts come from Webhooks and Run webhooks; tunnel behavior comes from ngrok's and Cloudflare's own docs, read 2026-09-27. For a deployed endpoint that stops receiving events, see Sume webhook not received?
Why can't Sume send webhooks to localhost?
The webhook POST comes from Sume, not from your machine, so the URL has to be reachable from the public internet. The docs say webhook URLs must be public HTTPS; localhost, private-network, and non-HTTPS URLs are rejected with 400 invalid_request when you submit, and the URL is checked again at delivery time. Current code also refuses hostnames ending in .local, .internal, or .test, and any explicit non-default port, so http://localhost:8080/hooks/sume and https://my-laptop.local:8443/hooks/sume both fail.
A tunnel gives you a public HTTPS hostname on the default port that forwards to your machine. Webhook URL rejected as invalid? lists every rule and the exact error.
Should I use ngrok or a Cloudflare Quick Tunnel?
Both give your local port a public HTTPS URL. ngrok's free plan shows a browser warning page, but only on HTML browser traffic; its docs say it does not affect APIs or programmatic requests. Cloudflare says Quick Tunnels are for testing and development only.
| Detail | ngrok free plan | Cloudflare Quick Tunnel |
|---|---|---|
| Start | ngrok config add-authtoken $YOUR_TOKEN, then ngrok http 8080 | cloudflared tunnel --url http://localhost:8080 |
| Account | An ngrok account and its auth token | No Cloudflare account required |
| Public URL | One dev domain assigned to your account, such as your-assigned-name.ngrok-free.app, served over HTTPS | A random subdomain on trycloudflare.com, with automatic HTTPS |
| Limits | 20,000 HTTP requests a month; 4,000 a minute | 200 in-flight requests, then 429; no SLA or uptime guarantee |
| Lifetime | Free endpoints have no timeout | Ends with the cloudflared process |
How do I run the local loop?
Start the handler, open the tunnel, and register the full URL with its path. Sume does not follow redirects: a 3xx, such as a framework's trailing-slash redirect, is a failed attempt. Prove the tunnel and your signing secret with Send test, which POSTs a signed dummy webhook.test event to the URL you name, applies the same URL rules as a real submit, and returns the status_code your handler answered; the debugging guide covers its fields.
Then submit a real job or run with the tunnel URL as its webhook URL. You cannot point an existing job at the tunnel: Redeliver never sends to a different URL, and for jobs a new URL means a new job.
# Terminal 1: your handler listens on localhost:8080. Expose it:
ngrok http 8080
# or, with no account:
cloudflared tunnel --url http://localhost:8080
# Terminal 2: send a signed test event to the printed HTTPS URL plus your path
curl -X POST https://api.sume.com/v1/webhooks/test-deliveries \
-H "Authorization: Bearer $SUME_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "webhook_url": "https://your-assigned-name.ngrok-free.app/hooks/sume" }'Should I replay from ngrok's inspector or use Sume's Redeliver?
ngrok's Traffic Inspector shows each request's headers and body, and Replay resends a captured request with the same method, headers, and body as the original. For a Sume delivery that includes the original x-sume-webhook-timestamp and signature. Sume's docs tell receivers to reject timestamps outside a replay window, five minutes being a reasonable default, so an inspector replay only verifies inside that window.
For anything older, use Sume's Redeliver: POST /v1/jobs/{job_id}/webhook/redeliver with jobs:write, or POST /v1/format-runs/{run_id}/webhook/redeliver with formats:write. It re-POSTs the real terminal event with a fresh timestamp and signature, works after the automatic attempts are exhausted, and does not use up one of the 10.
What breaks during a local session?
Three things to watch:
- Restarting a Quick Tunnel. Each launch generates a new random
trycloudflare.comsubdomain, and the webhook URL is stored with each job or run and checked again at delivery. Work you submitted before the restart still targets the old hostname, while ngrok's free plan keeps one dev domain on your account. - Breakpoints. Each attempt gets 10 seconds, and a slow endpoint burns the budget and gets retried. Job deliveries retry up to 10 attempts at a fixed delay, 30 seconds by default; run deliveries back off exponentially. Store the event, answer
2xx, then debug. - Tunnel limits. Past 200 in-flight requests a Quick Tunnel answers
429, which Sume treats as a failed attempt and retries; run deliveries also honorRetry-Afteron a429.
Sources
- Webhooks
- Run webhooks
- Runs and results
- API reference
- Sume API reference
- ngrok: Free Plan Limits (read 2026-09-27)
- ngrok: Share Localhost Quickstart (read 2026-09-27)
- ngrok: Test Webhooks Locally (read 2026-09-27)
- ngrok: Inspect Traffic and Replay Requests (read 2026-09-27)
- Cloudflare One docs: Quick Tunnels (read 2026-09-27)
- Cloudflare: Quick Tunnels (read 2026-09-27)
Related posts
More in Integrations
- Text-to-video API in Python: submit, poll, and download
Call Sume's text-to-video API from Python with Requests: POST /v1/videos, poll with timeouts, then stream the MP4 the content route redirects to.
- Trigger.dev wait for webhook: waitpoint tokens for Sume runs
Create a Trigger.dev waitpoint token, send token.url as a Sume run's webhook_url, and wait.forToken() returns when Sume POSTs the run's result.
- Vercel AI SDK: generate video with a Sume API tool call
Generate video from the Vercel AI SDK with a tool() that calls Sume's POST /v1/videos on your server, returns the job id, and polls for the clip.
- Vercel Cron Jobs: call the Sume API daily without duplicates
A Vercel cron job sends a GET to your route, which calls the Sume API with a date-based Idempotency-Key, so a duplicate invocation cannot bill twice.
Written by Sume