Documentation
Docs.
Everything SnapHook does, in one page. Generate an endpoint, send it traffic, and read the captures as they arrive.
01 — Quickstart
Three steps, no account
- Click Generate free webhook URL on the homepage. You are redirected to your private inspector at
/app/{slug}. - Copy the target URL from the top bar. It looks like
https://snaphook.site/w/{slug}. - Point any HTTP client or webhook provider at it. Captures appear in the inspector the instant they land — no refresh.
Nothing else is required. There is no account to create, no key to configure, and no SDK to install.
02 — URL anatomy
Two URLs per session
| URL | What it is |
|---|---|
/w/{slug} |
Your ingestion endpoint. Give this to the system you are debugging. Every method is accepted, and anything you append — /w/{slug}/orders/created — is captured as the request path. |
/app/{slug} |
Your inspector. Open it in a browser to watch captures live. Anyone with the link can read the session, so treat it as a secret. |
The slug is 12 random characters, and it is the only thing protecting your session. Nobody can guess it, and search engines are told not to index it. But anyone you send it to can read everything in the session, so share it the way you would share a password.
03 — Code examples
Send a capture from anywhere
curl
# POST some JSON curl -X POST https://snaphook.site/w/YOUR_SESSION_ID/orders/created \ -H "Content-Type: application/json" \ -d '{"order_id": 4021, "status": "paid"}' # GET with a query string — both are captured verbatim curl "https://snaphook.site/w/YOUR_SESSION_ID/callback?state=xyz&code=123" # form encoded, custom headers, any method curl -X PUT https://snaphook.site/w/YOUR_SESSION_ID \ -H "X-Signature: t=1700000000,v1=deadbeef" \ --data-urlencode "event=subscription.updated"
JavaScript
// ingestion allows cross-origin requests by default, so this works from a browser too await fetch("https://snaphook.site/w/YOUR_SESSION_ID/test", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ hello: "world" }), });
Python
import urllib.request, json
body = json.dumps({"hello": "world"}).encode()
req = urllib.request.Request(
"https://snaphook.site/w/YOUR_SESSION_ID/test",
data=body,
headers={"Content-Type": "application/json"},
)
print(urllib.request.urlopen(req).read().decode())
04 — The inspector
Reading a capture
The dashboard is a two-pane master-detail view. The left pane lists captures newest first with the method, path, relative time and payload size. The right pane breaks the selected capture into four parts:
- Metadata — method, full path with query string, protocol, client IP, timestamp and captured size.
- Headers — every header exactly as received, including duplicates.
- Query parameters — the parsed query string, with repeated keys preserved as lists.
- Body — pretty-printed when the payload is valid JSON, raw otherwise, with a toggle between the two.
The status pill in the top bar reports the live connection: live when the stream is attached, retrying while reconnecting, and expired once the session is gone. Clear discards the history but keeps the URL working.
05 — Limits
What a session will hold
| Limit | Value | What happens if you hit it |
|---|---|---|
| Body size | 256 KB | The request still succeeds. You get the first 256 KB, marked as truncated. |
| Captures kept | 30 per session | The oldest drops off as a new one arrives. |
| Session lifetime | 2 hours idle | The session goes away and the URL starts returning 404. |
| Sending rate | Fair use | Bursts are fine. Flood it and you get a 429 telling you how long to wait. |
These aren't upsell gates. There's no paid tier to upgrade to. They're there so one busy endpoint can't spoil the service for everybody else.
06 — Provider setup
Wiring up a real sender
The pattern is identical everywhere: paste https://snaphook.site/w/{slug} where the provider asks for a destination URL, then trigger a test event.
- Stripe — Developers → Webhooks → Add endpoint, then Send test webhook. Append a sub-path such as
/stripeto keep senders distinguishable. - GitHub — Repository or organisation Settings → Webhooks → Add webhook. Set content type to
application/json; the Recent Deliveries tab and SnapHook should agree exactly. - Shopify, Twilio, Slack, Zapier, n8n — any field labelled callback, webhook or destination URL accepts a SnapHook endpoint as-is.
- Your own code — point a cron job, CI step or retry queue at it to confirm what it actually sends, headers included.
SnapHook answers quickly — 200 unless you configured something else in the Response dialog — so a provider's delivery log should show success. If it does not, the failure is between the provider and this service: check the sub-path, that the session has not expired, and that you are not deliberately replying with an error.
07 — Security
Treat the session URL as a secret
There are no accounts here, so the slug is your credential. Anyone who gets hold of it can read every capture in the session until it expires. So:
- Use test-mode credentials only. No live API keys, bearer tokens, session cookies or signing secrets.
- Don't send personal data. Real customer records don't belong in a public inspection endpoint, whatever the retention policy says.
- Keep session URLs out of issues, gists and screenshots. Anything you publish is readable.
- Clear the history when you're done — or just walk away. The session is purged after 2 hours of inactivity either way.
On our side, sessions are kept out of search results, nothing you send is written down anywhere, and no third-party script runs on any page. The privacy policy spells out what is kept and for how long; the terms of use cover what the endpoint may not be used for.
08 — FAQ
Frequently asked.
How do I get a webhook testing URL?
Click Generate free webhook URL on the homepage. You get a session slug straight away: send traffic to /w/{slug} and watch it at /app/{slug}.
How long does a SnapHook session last?
A session is purged 2 hours after the last request it received and the last dashboard disconnecting from it. Keeping the inspector tab open keeps the session alive.
What are the payload limits?
Bodies are captured up to 256 KB, and anything longer is flagged as truncated rather than thrown away. Each session keeps its 30 most recent requests.
Is it safe to send real credentials to a webhook testing URL?
No. Anyone who knows a session URL can read what was sent to it. Use test-mode credentials and synthetic data, and never point a production payment, authentication or personal-data webhook at a public inspection endpoint.
Can I reply to a webhook with a custom status or body?
Yes. By default ingestion answers 200 with a small JSON acknowledgement, which is what provider delivery logs want to see. Open the Response dialog in the inspector to set any status from 200 to 599, any content type and any body. It is what you need to finish a Slack URL verification by echoing its challenge, or to exercise a provider's retry logic with a real 500. The capture is recorded before the reply is written, so a configured 500 still shows you every attempt. The setting lives with the session and dies with it.
Can I test CORS against my capture URL?
Yes, in both directions. Capture URLs answer browsers from any origin by default, so a page's fetch() works against one straight away. If what you are checking is your own service's cross-origin headers, that default cannot help you — a URL that permits everything succeeds either way — so you can turn it off per session from the Response dialog. With it off the OPTIONS preflight is captured instead of answered, which is the only way to see from here that a browser call failed at the preflight rather than never being sent. Captures keep working either way; only the browser's permission to read the reply changes.
Why did my session disappear?
Either it sat idle for 2 hours, or the service was restarted. Nothing is kept, so there's nothing to bring back. Generate a new URL and carry on.
Try it now.
A working endpoint is one click away.