Webhooks that never sleep.
Tunnels in one command.
Permanent endpoints that answer, verify, and forward webhooks around the clock — and instant HTTPS tunnels to any local port. Point and click in the console, or hand your agents the CLI and built-in MCP server.
One URL, five jobs
What happens when a request lands.
Answered
Your status, headers, body, and delay — or a response rule or script decides per request.
Verified
Signature checked in constant time against 16 provider presets, marked in the feed.
Captured
Full request stored — browse, filter, and export the history as JSON or CSV.
Forwarded
Matching events delivered to any URL — signed, transformed, retried until they land.
Notified
An email or browser ping when the request you are waiting for arrives.
Webhook endpoints
An endpoint with no server behind it.
Provision a URL once and it's simply on: OtterKit answers every sender 24/7, keeps the full history, and buffers nothing on your machine — because nothing runs on your machine. Come back whenever; replay any capture with edited fields, or export the lot.
--ttl neveralways-on, capped at $2/mo--respond 201 --respond-delay 800shape the answerreplay --set amount=42edit & resend capturesrequests · export json/csvhistory anywhere$ npx otterkit webhook --daemon --subdomain stripe-live
Endpoint live https://stripe-live.otterkit.app
answering 200 · storing history · runs until you stop it
# three days later, from anywhere
$ npx otterkit requests stripe-live --last 2
09:14 POST /stripe 200 · 1.2 KB · verified ✓
11:02 POST /stripe 200 · 1.3 KB · verified ✓
Signature verification
Know it's really Stripe before you trust it.
Every capture is checked against the provider's signing scheme as it lands — constant-time, spoof-proof, marked right in the feed. Gate your forwards on it and a forged call can never reach your CI. Sixteen provider presets, public-key schemes included, plus generic HMAC for everything else.
--verify stripe:whsec_…arm at provision time--verified-onlyforwards fail closedsend stripe:payment.succeededcorrectly-signed test eventsDynamic responses
Answer like the API you're pretending to be.
Response rules run first-match-wins: match on method, path, or a JSON field, and answer with a static body or a template that echoes pieces of the request. The Slack challenge, a fake 500, a slow consumer — all declarative, edited live on the console, applied without a restart.
--respond-match type=url_verificationSlack challenge, solved{{$body}}template echoes--respond 500simulate failure--respond-delay 800simulate a slow consumertype=url_verification→200{"challenge":"{{…}}"}templatePOST /fail→500{"error":"simulated_failure"}staticeverything else→200{"received":true}defaultScriptable, sandboxed
When rules run out, write JavaScript.
Both ends of an endpoint take a script. respond() decides the answer to each request; transform() reshapes a forward on its way out. They run in an isolated sandbox with no network access, TypeScript works out of the box, and a script that throws fails open — your URL keeps answering no matter what.
export default {
respond(req) {
// Exercise the sender’s retry logic ~30% of the time.
if (Math.random() < 0.3)
return { status: 500, body: '{"error":"chaos"}' };
return null; // fall through to the next rule
},
};
export default {
transform(req) {
const event = JSON.parse(req.bodyText);
// Forward only what your CI actually wants.
return {
body: JSON.stringify({ run: event.data.id, paid: true }),
headers: { 'X-Event-Type': event.type },
};
},
};
no-egress isolatescripts can't phone homefail-opena throw never takes your URL downTypeScripttypes stripped on savechaos presetretry-testing in one clickDurable forwards
The event that matters finds you. Eventually is guaranteed.
Attach a rule to the endpoint: every request matching a method, path, or JSON field is delivered to your URL — HMAC-signed, reshaped by a template or script if you want, retried until it lands, paused automatically if the target dies. It fires whether or not any machine of yours is awake.
--match event.type=paidmethod · path · JSON field--forward-scriptreshape the payload en routeX-OtterKit-Signaturesigned + retried--notify-matchemail on the ones you care about$ npx otterkit webhook --match event.type=paid \
--forward https://ci.example.com/resume
Forwarding armed · every match delivered, signed
# hours later — laptop closed, payment lands
delivered → ci.example.com (2 retries, 4m total)
Tunnels
When you want it on your machine, it's one command.
Expose any local port on *.otterkit.app with HTTPS — a stable subdomain that survives restarts, a TTL so forgotten tunnels stop themselves, daemon mode for the background, and an otterkit.toml that brings a whole project up at once. Inspect everything, replay anything.
--subdomain api-demo --ttl 4hstable + self-stoppingotterkit upwhole project from toml--auth user:passbasic-auth the doorinspect --haropen in devtools$ npx otterkit tunnel 3000 --subdomain demo --ttl 4h
Tunnel ready https://demo.otterkit.app
→ 127.0.0.1:3000 · auto-stops in 4h · 1¢/hr
200 GET / (11ms)
201 POST /api/orders (18ms)
Built agent-first
Your agents don't ask you for URLs anymore.
Log in once. From then on, any agent on the machine provisions endpoints and tunnels itself against your prepaid credits — no keys to paste, no dashboard round-trips. Every command speaks --json, await blocks until the webhook a test is waiting for actually arrives, and the MCP server plugs into Claude Code or Cursor with one line.
- Agents provision, capture, await, verify, and replay on their own
- Server-held forwards instead of polling — nothing runs locally to miss the event
- llms.txt and an agent skill, so the docs read themselves
# an agent, testing its own payment flow
$ otterkit webhook --daemon --json
{"url":"https://hook-1f2e3d4c.otterkit.app", …}
$ otterkit await hook-1f2e3d4c --path /stripe --count 1 --timeout 5m
waiting for a matching request…
match POST /stripe · verified ✓ · exit 0
Pricing
Fair, and honest about it.
No subscription — prepaid credits, metered by the connected hour, and webhooks are capped so an always-on endpoint can never surprise you.
CLI + console · for you and your agents
Free credits to start · no card required
- Webhook endpoints never bill more than $2 / month — even always-on
- Tunnels bill connected time only
- Credits never expire · log in once, agents self-provision
- Verification, forwards, scripts, notifications — all included
FAQ
Questions, answered.
Two things. Webhook endpoints: permanent URLs served by OtterKit that answer senders, verify signatures, store history, and forward matching events — no server of yours involved. Tunnels: public HTTPS URLs for any local port, one command. Drive it from the console, or hand your agents the CLI and MCP server.
Put a URL on it.
Your first endpoint is one command away, and the free credits cover it. Bring an agent — or don't.
$ npx otterkit webhook