# https://tunnels.io/use-cases/webhooks

[Home](https://tunnels.io/) / [Use cases](https://tunnels.io/use-cases) / Webhooks

Webhook testing

# Receive real webhooks on your laptop.

Point Stripe, GitHub, Shopify or anything else at a public HTTPS URL that forwards into your local handler. Real payloads, real signatures, real retries, with a breakpoint in your editor and nothing deployed.

[Get started free →](https://tunnels.io/get-started) [See pricing](https://tunnels.io/pricing)

## What a provider demands of your endpoint

Every provider wants the same four things from your URL: a scheme it trusts, a name that stays put, a status code it can read, and a signature it can verify. How strictly each enforces that is where local testing goes wrong.

| Provider | HTTPS | Stable URL | Retries | Secret tied to the URL |
| --- | --- | --- | --- | --- |
| Stripe | Required | Yes, per endpoint | Backoff, for days | Yes, one secret per endpoint |
| GitHub | Expected, http still accepted | Yes, per hook | Redeliver by hand from the log | Yes, set on the hook |
| Shopify | Required | Yes, per subscription | About two days, then drops it | No, app-wide HMAC secret |
| Twilio | Recommended | Yes, per number | Often none | The URL is in the signed string |
| Slack | Required | Yes, plus a challenge check | A few, then it backs off | No, one secret per app |
| PayPal | Required | Yes, per webhook | Over a few days | Bound to the webhook id |

Providers change this as they ship. Treat it as the shape of the requirement, not a contract, and read their own documentation before you depend on a retry window.

Two columns cost the most time. Where the signing secret belongs to the endpoint, a new hostname means a new endpoint and a new secret. Where the URL sits inside the signed string, as at Twilio, moving the hostname changes the signature by definition.

## Why does a URL that changes break every webhook you registered?

Because the registration outlives the session. On the free plan your hostname is 16 random characters on `tunnels.host`, held on a seven-day lease and released when the client disconnects. Restart tomorrow and the name is different, so every endpoint you registered yesterday points somewhere that is not yours.

Nothing warns you. The provider keeps delivering, marks the attempts failed in its own log, and you find out through an order that never got fulfilled. A reserved subdomain fixes it: you pick the name and it survives restarts, so the endpoint registered in January still resolves in June. Reserved subdomains start on Professional at $4 a month, three included. [Reserved subdomains explained](https://tunnels.io/learn/what-is-a-reserved-subdomain) covers the rest.

## How do you see what the provider actually sent?

A failed delivery is only fixable if you can see both halves of it. The provider's log shows what it sent and what came back. It cannot show which middleware rejected the request, or that the bytes your handler read were not the bytes that arrived.

The client runs a request inspector on `http://127.0.0.1:4040` whenever a tunnel is up. The most recent fifty deliveries are listed with method, path, status, duration and time, so you can confirm a request reached your handler and see exactly what it answered. It shows the transaction, not the payload: there is no header view and no body capture, so a signature check stays a job for your own logs. The terminal shows the same traffic as a live table. The address is the `inspect_addr` config key, and `disabled` turns it off on a shared machine.

### The body arrives untouched

Bytes in, bytes out. If a signature check fails through the tunnel, the tunnel is not what changed the payload, so look at your middleware and at which endpoint's signing secret you are checking against.

### Redelivery is theirs

We do not replay requests. The resend control in their delivery log is the only replay carrying a signature your verifier accepts.

## Can you run several provider tunnels at once?

Yes, and most integrations need it. Payments on one port, the repository hook on another, the storefront on a third. Define each as a named tunnel in the config file and start the set with one command.

```
$ tunnels start-all
Active Tunnels:
▸ https://pay-dev.tunnels.host → localhost:3000  [https]
▸ https://gh-dev.tunnels.host → localhost:4000  [https]
▸ https://shop-dev.tunnels.host → localhost:5000  [https]
```

Concurrency is the limit that bites, not bandwidth. Basic runs one tunnel. Professional runs five, but split by protocol: four HTTPS and one raw TCP. Since webhooks are HTTPS, four providers at once is the Professional ceiling. Gold runs ten of any kind and Premium is uncapped. Three registered providers is three concurrent tunnels, so a real multi-provider integration starts on Professional and a fifth provider needs Gold. `tunnels start <name>` brings up a single one.

## What happens to deliveries while your laptop is closed?

They fail, and the provider decides what that costs you. Nothing is queued at our edge while no client is connected. Read the retry column again: Stripe and PayPal keep trying for days, Shopify eventually drops the subscription, and a missed Twilio callback is usually gone.

When the machine wakes, the client reconnects on its own with exponential backoff and jitter, and it honours a server-directed reconnect delay so a restart does not stampede. On a reserved subdomain the hostname is identical afterwards and the retries land. On a random free hostname the name has gone, so update the provider first, then redeliver.

## Which plan you need

Webhooks are HTTPS, and HTTPS tunnels work on the free plan, so this starts at $0 with no card. The reason to pay is the hostname, not the protocol.

Basic, free

$0

One tunnel, 4 GB a month, 1,024 requests per second, and a random 16-character subdomain on a seven-day lease. Student is also $0 with a school email, at double the rate and bandwidth.

Professional

$4/mo

Three reserved subdomains, four concurrent HTTPS tunnels (five in total, one of which may be TCP), 128 GB, 8,192 requests per second. The webhook plan: a name you chose, kept across restarts, with room for several providers. $40 a year, or $72 for 24 months.

Gold and above

$10/mo

Bring your own domain, so the endpoint reads `hooks.yourcompany.com`. Certificates come through Cloudflare for SaaS once you point a CNAME at us. Premium at $20 lifts the tunnel and rate caps.

Raw TCP also starts on Professional, but no webhook needs it. [Pricing](https://tunnels.io/pricing) is always authoritative.

## What this does not do

A tunnel is transport. It carries a request from the internet to a port on your machine and carries your response back. The rest is out of scope.

- No queue and no buffer. Nothing is held while you are offline, so the provider's retry policy is the only safety net.
- No replay and no signature tooling. Redelivery belongs to the provider, verification belongs to your handler.
- HTTPS and raw TCP only. UDP is not supported. There is no SMTP tunnel type either, though SMTP is TCP and rides a raw TCP tunnel like any other TCP service.
- No OAuth, SSO or IP allowlisting at the edge. The one control we offer is `--httpauth user:pass`, and a caller never given those credentials will only collect 401s.
- TLS is terminated at our edge. TLS 1.3 where the caller supports it, TLS 1.2 as the floor, then plain HTTP over loopback. [HTTP vs HTTPS tunnels](https://tunnels.io/learn/http-vs-https-tunnels) has the detail.
- Free does not let you choose a name. It is 16 random characters, reassigned after a restart.

## Questions

### Do webhooks work on the free plan?

Yes. HTTPS tunnels work on Basic at $0 with no card, so any provider can reach your laptop. What free does not give you is a name you chose: the hostname is 16 random characters and changes after a restart. That is fine for a session you finish the same day.

### Which plan gives me a webhook URL that survives a restart?

Professional, at $4 a month or $40 a year, which includes three reserved subdomains and four concurrent HTTPS tunnels (five in total, one of which may be raw TCP). Register the reserved hostname at the provider once and it keeps resolving across restarts and reconnects, so the signing secret tied to that endpoint stays valid.

### Can I test several providers at the same time?

Yes, if your plan allows enough concurrent tunnels. Define each as a named tunnel in the config file and run tunnels start-all. Basic allows one tunnel at a time. Professional allows four HTTPS tunnels plus one raw TCP one, so four providers. Gold allows ten of any kind and Premium is uncapped.

### Does tunnels.io store deliveries that arrive while I am offline?

No. Nothing is queued at our edge, so a delivery that arrives with no client connected fails. Whether you lose the event is entirely the provider's policy: some retry on a backoff for days, some retry a few times, some never. Check the delivery log when you reconnect and redeliver what gave up.

### Will a provider signature still verify through a tunnel?

Yes. The body is forwarded through unchanged, so a handler that verifies the raw bytes behaves as it does in production. The two things that break it are a signing secret belonging to a different registered endpoint, and JSON middleware that re-serializes the body before verification runs.

## Related reading

[The step-by-step walkthrough Webhook debugging in detail, including failures that look like the tunnel and are not.](https://tunnels.io/learn/how-to-test-webhooks-locally) [What is a reserved subdomain? What reserving a name holds, and when a random hostname is still fine.](https://tunnels.io/learn/what-is-a-reserved-subdomain) [HTTP vs HTTPS tunnels Where TLS is terminated, and what your handler sees once the request is on loopback.](https://tunnels.io/learn/http-vs-https-tunnels) [tunnels.io vs ngrok Flat plans against metered usage, and why an interstitial in front of an endpoint matters.](https://tunnels.io/compare/ngrok) [Mobile testing Point a real handset on cellular data at the API running on your laptop.](https://tunnels.io/use-cases/mobile-testing) [CI and CD Reach a service that only exists inside a build job, for the length of a pipeline run.](https://tunnels.io/use-cases/ci-cd)

More explainers in [Learn](https://tunnels.io/learn).

## Give the provider somewhere to deliver.

One command puts a public HTTPS URL in front of the port your handler already listens on. Reserve a name once something other than you is remembering the URL.

[Get started →](https://tunnels.io/get-started) [See plans and limits](https://tunnels.io/pricing)
