🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

otterkit

Package Overview
Dependencies
Maintainers
1
Versions
37
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

otterkit

OtterKit CLI - provision and connect tunnels for AI agents

latest
Source
npmnpm
Version
0.35.0
Version published
Weekly downloads
2K
52.47%
Maintainers
1
Weekly downloads
 
Created
Source

otterkit

Instant tunnels and webhooks for AI agents. Pay per use with prepaid credits.

Quick Start

# One-time: log in (opens your browser)
npx otterkit login

# Create a tunnel
npx otterkit tunnel 3000

Buy credits at console.otterkit.com. Once you've logged in, agents on the same machine provision automatically using your credits.

Commands

Tunnel

Expose a local port to the internet.

npx otterkit tunnel <port>                    # Foreground (1 credit/hr)
npx otterkit tunnel <port> --log              # Also capture every request to a JSONL log
npx otterkit tunnel <port> --daemon           # Background, auto-stops after 24h
npx otterkit tunnel <port> --daemon --ttl 3d  # Background, auto-stops after 3 days
npx otterkit tunnel <port> --subdomain myapp  # Stable URL: https://myapp.otterkit.app
npx otterkit tunnel <port> --auth user:pass   # Require HTTP Basic auth on the public URL

--auth is enforced by the CLI on your machine, before anything reaches your local server - unauthenticated requests get a 401 and are never forwarded. Credentials are not sent to or stored by OtterKit's servers.

Stable URLs

By default each tunnel gets a fresh random URL (https://tunnel-a1b2c3d4.otterkit.app). Pass --subdomain <name> to get a stable, reserved URL instead. The name is claimed to your account the first time you use it and reused on every run after that - so the same public URL (https://myapp.otterkit.app) always points at your tunnel, across machines and restarts. It works on tunnel and webhook, foreground and --daemon.

Holding a name is free - you still only pay the normal 1 credit/hr while a tunnel is connected. If another account already owns the name you'll get a "taken" error and no credit is charged; pick another name or omit the flag for an auto name.

npx otterkit subdomains                 # List your reserved subdomains
npx otterkit subdomains reserve myapp   # Reserve a name without starting a tunnel
npx otterkit subdomains release myapp   # Release a name so it can be reused

Project Config (otterkit up)

Define named tunnel profiles in an otterkit.toml and bring them all up with one command. Every profile runs as a background daemon, so status, inspect, and stop work as usual.

# otterkit.toml
[tunnels.web]
port = 3000
subdomain = "myapp"          # stable URL (optional)
auth = "admin:s3cret"        # HTTP Basic auth (optional)
log = true                   # capture requests (optional)
ttl = "8h"                   # auto-stop (optional, default 24h)

[tunnels.hooks]
webhook = true               # capture-only endpoint, no local server
subdomain = "myapp-hooks"
respond = 200                # custom auto-response (optional)
respond_body = '{"ok":true}'
npx otterkit up                  # Start everything (skips profiles already running)
npx otterkit up --json           # Machine-readable results
npx otterkit down                # Stop the daemons started from the config
npx otterkit up --config ./deploy/otterkit.toml

Webhook

Capture incoming HTTP requests without a local server. Every request is saved to ~/.otterkit/requests/<subdomain>.jsonl so nothing is lost when the terminal closes.

npx otterkit webhook                           # Foreground (1 credit/hr)
npx otterkit webhook --daemon --ttl 4h         # Background, auto-stops after 4h

Some providers require a specific response before they deliver events (challenge echoes, strict 2xx checks). Customize the auto-response with --respond / --respond-body (default: 200 {"received":true}):

npx otterkit webhook --respond 204
npx otterkit webhook --respond 200 --respond-body '{"challenge":"accepted"}'

With --standby, the endpoint stays live while you're disconnected (laptop closed, daemon killed): the server answers each request with your auto-response and buffers up to 200 captures (64 KB bodies), replaying them into your local log on reconnect - providers never see downtime. Billing continues while disconnected (still capped at 10 credits/day; the session still auto-stops at its --ttl).

npx otterkit webhook --standby
npx otterkit webhook --daemon --standby --respond 204

Inspect

View requests captured by webhook or tunnel --log.

npx otterkit inspect <subdomain>               # Pretty-print last 20 requests
npx otterkit inspect <subdomain> --json        # Raw JSONL (pipe-friendly)
npx otterkit inspect <subdomain> --last 50     # Show last 50 requests
npx otterkit inspect <subdomain> --follow      # Live-tail new requests (Ctrl+C to stop)
npx otterkit inspect <subdomain> --method POST --status 5xx --path /webhook
npx otterkit inspect <subdomain> --har > session.har   # HAR 1.2 for devtools/HAR viewers

Filters (--method, --status, --path) combine and work with --json, --follow, and --har. --status accepts an exact code (500) or a class (5xx).

Replay

Re-send a captured request to your local server - same as the desktop app's replay, straight to the target with no tunnel round-trip. Great for re-testing webhook handlers after a fix without waiting for the provider to fire again. The replayed exchange is appended to the capture log, so it shows up in otterkit inspect.

The target defaults to the running daemon's host:port for that subdomain; pass --target for webhook captures or stopped tunnels.

npx otterkit replay <subdomain>                          # Re-send the latest request
npx otterkit replay <subdomain> --index 3                # Re-send request #3 (1 = oldest, -1 = latest)
npx otterkit replay <subdomain> --target 127.0.0.1:3000  # Explicit local target
npx otterkit replay <subdomain> --json                   # Machine-readable response (base64 body)

# Tweak the request before re-sending
npx otterkit replay <subdomain> --method PUT --path /v2/hook \
  -H "X-Debug: 1" --body '{"event":"payment.failed"}'

# Edit individual JSON body fields (repeatable; numbers/booleans parse as JSON)
npx otterkit replay <subdomain> --set data.amount=999 --set data.livemode=false

Capture logs record the full exchange - response status, headers, and body - so inspect --json and --har exports carry both sides of every request.

Await

Block until a matching request arrives - the scriptable primitive for CI and agents: "trigger the event, await its arrival, assert on the payload." By default it keeps streaming matches (your session keeps running either way - await never stops the tunnel it watches). Pass --count for a deterministic exit.

npx otterkit await <subdomain>                            # Stream every request (Ctrl+C to stop)
npx otterkit await <subdomain> --count 1 --timeout 120s   # CI: exit 0 on arrival, 2 on timeout
npx otterkit await <subdomain> --method POST --path /stripe --json

Exit codes: 0 when --count is satisfied (or on Ctrl+C), 2 when --timeout expires unmet. Filters (--method, --status, --path) match inspect's.

Continue a /try session

Started on otterkit.com/try? The page shows a claim command that moves the session into your terminal - same public URL, and everything already captured on the page is imported into your local log:

npx otterkit webhook --claim <code>   # code comes from the /try page

Send & Verify Events

Develop a webhook handler with no provider account, dashboard, or real event. send fires a correctly-signed synthetic event at your local handler; verify checks whether captured requests carry a valid signature. Both run locally - the secret never leaves your machine. Schemes: Stripe, GitHub, Shopify, Slack.

# Fire a signed event straight at your handler (passes its signature check)
npx otterkit send stripe:payment_intent.succeeded 127.0.0.1:3000/webhooks/stripe --secret whsec_...
npx otterkit send github:push 127.0.0.1:3000/hooks --secret ghs_...
npx otterkit send --list                              # all providers + events

# "Is my verification wrong, or the payload?" - answered against captured requests
npx otterkit verify myhooks stripe --secret whsec_...

# Replay a captured request with an edited body, re-signed so it still validates
npx otterkit replay myhooks --set data.object.amount=999 --resign stripe --secret whsec_...

MCP Server (for AI agents)

otterkit mcp runs a Model Context Protocol server over stdio - Claude Code, Cursor, and any MCP client get tunnels, webhooks, capture logs, await, and replay as native tools, authenticated by the same otterkit login.

# Claude Code
claude mcp add otterkit -- npx otterkit mcp
// Cursor & friends (.cursor/mcp.json)
{ "mcpServers": { "otterkit": { "command": "npx", "args": ["otterkit", "mcp"] } } }

Tools: webhook_create, tunnel_create, sessions_list, session_stop, requests_list, request_await, request_replay, event_send, request_verify, try_claim, account_status.

Account

npx otterkit login                             # Log in via browser
npx otterkit whoami                            # Show account + balance
npx otterkit balance                           # Show credit balance
npx otterkit logout                            # Remove the saved token

Manage Daemons

npx otterkit status                            # List running daemons
npx otterkit stop <subdomain>                  # Stop a daemon

JSON Output (for agents & scripts)

Every read/provision command takes --json and prints one machine-readable result:

npx otterkit tunnel 3000 --daemon --json   # {"subdomain":..., "publicUrl":..., "pid":...}
npx otterkit webhook --daemon --json
npx otterkit up --json
npx otterkit status --json
npx otterkit subdomains list --json
npx otterkit inspect <subdomain> --json
npx otterkit replay <subdomain> --json
npx otterkit whoami --json
npx otterkit balance --json

Errors in --json mode are also JSON ({"error":"insufficient_credits", ...}) with exit code 1.

Options

FlagDescriptionDefault
--host <host>Local host to forward to127.0.0.1
--logCapture requests to a JSONL log (tunnel only)off
--daemonRun in backgroundoff
--ttl <duration>Auto-stop after duration, e.g. 4h, 3d (max 7d)24h
--subdomain <name>Use a stable reserved URL (claimed on first use)auto
--auth <user:pass>Require HTTP Basic auth (tunnel only, enforced locally)off
--respond <status>Webhook auto-response status (webhook only)200
--respond-body <d>Webhook auto-response body (webhook only){"received":true}
--claim <code>Continue a /try page session (webhook only)-
--set <path=value>Edit a JSON body field before replaying (repeatable)-
--count <n>await: exit 0 after N matchesstream forever
--timeout <dur>await: give up after e.g. 30s, 5m (exit 2)none
--jsonMachine-readable output (daemon/read commands)off

Pricing

Metered by connected time. 1 credit = $0.01. Buy prepaid credits in the console.

WhatCost
Per connected hour1 credit ($0.01), first hour up front
Daily cap per tunnel10 credits ($0.10) - hours beyond are free
While disconnectedFree - billing pauses
Auto-stopDefault 24h, --ttl up to 7d

A forgotten tunnel bills at most the daily cap, then auto-stops at its TTL.

How It Works

  • otterkit login runs a browser device-flow and saves an API token to ~/.otterkit/credentials.json.
  • The CLI sends that token when provisioning; the server debits your credit balance.
  • Server provisions a public URL like https://tunnel-a1b2c3d4.otterkit.app (or your reserved --subdomain name, if given).
  • CLI connects via WebSocket and forwards traffic to your local port.

For headless/CI, set OTTERKIT_TOKEN (create a token at console.otterkit.com) instead of otterkit login.

License

MIT

Keywords

tunnel

FAQs

Package last updated on 03 Aug 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts