The inbound layer
for AI agents.
Always-on webhook endpoints, email inboxes, schedules, and instant HTTPS tunnels to localhost. Your agents set them up from the CLI or MCP, and nothing is missed while your laptop sleeps.
npx otterkit webhookA permanent URL that answers, verifies and stores, even while you are offline.
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 a push notification on your devices 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. Flip on the inbox and the endpoint receives email too - messages land in the same feed as requests. Come back whenever; replay any capture with edited fields, or export the lot.
--ttl neveralways-on, capped at $3/mo--respond 201 --respond-delay 800shape the answer--emailan inbox on every endpointreplay --set amount=42edit & resend capturesrequests · export json/csvhistory anywherehooks.your-co.comcustom domains, cert managed$ 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--notify-pushpush notifications on any device$ 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
OtterKit for Mac
Every endpoint you own, live in one window.
Endpoints pile up - a tunnel from this morning's shell, webhooks an agent provisioned last week. The free Mac app is the one place they all show up: live traffic streaming in, full configuration editing, and a menu bar that always knows what's running and what it costs.
One window, every session
Tunnels and webhooks from the app, any terminal, or any agent - same login as the CLI, one live list.
One-click tunnels
The dashboard sees what’s listening on your Mac. Pick a port, click Expose, get an HTTPS URL.
Guardrails a browser tab can’t enforce
Tunnels stop when your Mac sleeps, idle ones nudge you, and the menu bar projects your monthly spend.
Free - spends the same credits · macOS 12+ · signed, notarized, auto-updates
Listening on this Mac
:3000viteExpose:8787wranglerExposeLive now
demo.otterkit.app→ :3000 · tunnel200 GET / · 11ms · 201 POST /api/orders · 18ms
hook-stripe.otterkit.appalways on · webhookPOST /stripe · 200 · verified ✓ - started by an agent, visible here
Pricing
Fair, and honest about it.
No subscription - prepaid credits, metered by the connected hour, and webhooks are capped at $3/mo so an always-on endpoint can never surprise you.
CLI + console · for you and your agents
Free credits to start · no card required
- Nothing bills more than $3 / month - webhooks and tunnels alike
- Tunnels bill connected time only, capped at $3/mo
- Credits never expire · log in once, agents self-provision
- Pulses: scheduled HTTP + dead-man switches, 1¢ per 100 runs
- Verification, forwards, scripts, custom domains - all included
FAQ
Questions, answered.
Two things. Webhook endpoints: permanent URLs served by OtterKit that answer senders, verify signatures, store history, forward matching events, and even receive email at their own address ([email protected]) - no server of yours involved, and attachable to your own domain (hooks.your-company.com). 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