Skip to content
Inkbox

Inkbox

DocsPricingBlogContact
GuidesAPI Reference

Ctrl K

GuidesAPI Reference

Jump to

Tunnels

A tunnel gives your agent a stable public hostname — my-agent.inkboxwire.com — that routes inbound HTTP, WebSocket, and raw-TCP traffic from third parties to your agent over a single persistent connection. Your agent stays behind whatever NAT, firewall, or laptop Wi-Fi it happens to be running on; no public IP, no firewall hole, no reverse proxy needed on your end.

Use the Python or TypeScript SDK to bring tunnels online from your agent.

Provisioning a tunnel

Tunnels are provisioned automatically when you create an identity — every identity owns exactly one tunnel, whose name is the identity's agent_handle. To opt into passthrough TLS at create time, pass a nested tunnel body to create_identity(). See the Manage identities reference for the full request shape.

Handles, and therefore tunnel names, must be globally unique across all Inkbox customers. They are 3–63 characters, lowercase letters / digits / hyphens, must start and end with a letter or digit, and may not contain consecutive hyphens.

Connecting your agent

The data-plane connect() helper opens the persistent agent connection and forwards inbound traffic to wherever you point it. The simplest setup forwards traffic to a local HTTP server you're already running. Authentication uses the same INKBOX_API_KEY the rest of the SDK uses — there is no per-tunnel secret on disk.

The TypeScript listener installs SIGINT and SIGTERM handlers automatically only when the parent process has none at construction time, so it stays out of the way of host processes that own their own shutdown — pass installSignalHandlers: false (or true to attach alongside) to override.

To rotate the credential used for the data-plane connection, rotate the underlying API key — see API keys.

In-process handlers

If you don't want to run a separate local HTTP server, hand connect() a handler function and it will run inside your agent process.

The ctx argument on the TypeScript handler exposes forwardedForIp, sniHost, an AbortSignal that fires when the runtime's deadline expires, and a read-only envelope escape hatch for metadata not surfaced on the typed fields.

WebSockets

Inbound WebSocket upgrades are bridged transparently to your handler.

Sync vs async lifecycle

connect() returns a TunnelListener. In Python, pick one lifecycle pair and stick with it — sync (wait / close) and async (serve_forever / aclose) are mutually exclusive on a given listener. In TypeScript, the listener is always async-driven; wait() is the canonical way to block until shutdown.

Deleting a tunnel

Tunnels are owned 1:1 by an agent identity and are deleted as part of the identity-delete cascade. There is no tunnel-level delete — to remove a tunnel, delete its identity.

The deletion is immediate — there is no grace window. TunnelStatus on the SDK side is AWAITING_CERT / ACTIVE.

Listing and inspecting tunnels

metadata is a free-form object capped at 4 KB serialized. It's returned as-is on read and is visible only within your org.

Passthrough TLS

By default, Inkbox terminates TLS at our edge with a managed certificate. If your compliance posture or client-side cert pinning requires TLS to terminate inside your own process, opt into passthrough at identity-create time by passing tunnel: { tls_mode: "passthrough" }, then sign a CSR via inkbox.tunnels.sign_csr(...). See the Passthrough TLS reference for the full flow, including how connect() handles cert provisioning automatically when the tunnel is in passthrough mode.

Reference

Inkbox

Copyright © 2026 Inkbox

This site is protected by reCAPTCHA.

Google Privacy Policy and Terms of Service apply.

Website

Inkbox

Copyright © 2026 Inkbox

This site is protected by reCAPTCHA.

Google Privacy Policy and Terms of Service apply.

Website

Y CombinatorBacked by Y Combinator
Tunnels