# WarpTunnel — HTML in, link out Base URL: https://warptunnel.com OpenAPI: https://warptunnel.com/openapi.json This guide: https://warptunnel.com/llms.txt WarpTunnel publishes a self-contained HTML file at a public URL. Management requires one API key. Public URLs need no login: anyone with the link can view them. The page directory and metadata are private to the key holder. ## Start here Set WT_URL to the base URL and WT_TOKEN to the owner's API key in the agent's environment. WT_TOKEN is the same secret configured on the server as WARPT_API_KEY. Never put the key in HTML, query strings, or published content. Supply it as a Bearer header. ```bash export WT_URL="https://warptunnel.com" # WT_TOKEN is provided by the owner through the environment. curl --fail-with-body "$WT_URL/api/v1/pages" \ -H "Authorization: Bearer $WT_TOKEN" \ -F file=@report.html -F title="Build report" ``` The response is a JSON page with id, title, url, createdAt, updatedAt, expiresAt, keep, bytes, and version. Share `url`, and retain `id` for future operations. expiresAt is an ISO 8601 UTC timestamp, or null when retained indefinitely. Public links look like `https://warptunnel.com/p/calm-otter-7k2m`. Page IDs contain two familiar lowercase words (3–8 letters each) and a random four-character suffix, separated by hyphens. The suffix uses digits `2`–`9` and lowercase letters except `l` and `o`. Use the ID exactly as returned; uppercase and older ID formats are not accepted. Public pages and the API share the same hostname; management still requires the API key. ## Optional CLI The HTTP API works without a CLI installation. The `warpt` CLI currently requires a separate source build or packaged tarball; it is not published to npm. If it is already installed: ```bash warpt publish report.html --title "Build report" warpt publish diagram.html --keep --json cat report.html | warpt publish - --title "Report" --json warpt list --json warpt info --json warpt update revised.html warpt keep warpt expire --days 30 warpt delete warpt get > saved.html ``` Publishing prints the URL; --json prints full metadata. `list` follows pagination automatically. Commands never prompt. Help is available at `warpt --help` and `warpt --help`. WT_URL and WT_TOKEN override saved settings; `warpt config set --url URL --token-stdin` saves a token read from stdin with owner-only file permissions. `warpt config show` always redacts it. ## HTTP interface All /api/v1 routes require `Authorization: Bearer `. | Method | Path | Behavior | | ------ | --------------------------------- | ------------------------------------------- | | POST | /api/v1/pages | Publish HTML; optional title and keep | | GET | /api/v1/pages?limit=50&cursor=... | List active pages; returns pages and cursor | | GET | /api/v1/pages/{id} | Read metadata | | GET | /api/v1/pages/{id}/content | Download original HTML | | PUT | /api/v1/pages/{id} | Replace HTML; optional title and keep | | PATCH | /api/v1/pages/{id}/retention | Set retention using JSON | | DELETE | /api/v1/pages/{id} | Delete; repeating the request is safe | Uploads support three formats: 1. multipart/form-data: one `file`, optional `title` and `keep=true|false`. 2. application/json: `{"html":"

Hello

","title":"Hello","keep":false}`. 3. text/html: raw UTF-8 HTML; optional `?title=Hello&keep=true` query parameters. HTML may be a document or fragment, up to 2 MiB. Inline scripts, CSS, SVG, and charts are supported. Assets must be embedded or use absolute public URLs; this is a single-file host, not a ZIP or site-folder deployment service. Pages are served with a sandboxed origin: cookies, localStorage, and same-origin API access are unavailable. Ordinary script execution and external assets still work. For list results, pass the returned cursor until it is null. A batch can be empty while still containing a cursor because expired and deleted pages are filtered. Ordering is by page ID, not creation time. The CLI collects and sorts by update time. ## Retention New pages expire 30 days after publishing unless keep=true. Updating temporary HTML restarts its expiration at 30 days; updating kept HTML preserves indefinite retention unless you explicitly send keep=false. Titles are preserved on updates unless supplied. URLs remain stable through updates and retention changes. Keep indefinitely: `PATCH /api/v1/pages/{id}/retention` with `{"keep":true}`. Restore expiration: `PATCH /api/v1/pages/{id}/retention` with `{"keep":false,"days":30}`. days defaults to 30 and must be an integer from 1 through 30. The timer starts now. Longer-lived pages should use keep=true. An expired page cannot be restored; publish a fresh copy. Keep indefinitely means until explicitly deleted. Expired URLs and metadata return 404 immediately. R2 eventually removes temporary HTML via its 30-day lifecycle rule. Shorter expiration hides pages earlier; it does not accelerate physical deletion. Tiny metadata records remain for listing and concurrency protection; deleted records retain no title or content. ## Errors and retries Failures return JSON: `{"error":{"code":"...","message":"...","docs":"..."}}`. 400 means invalid input; 401 missing/wrong token; 404 missing/expired page; 409 means an overlapping mutation or stale version; 413 means too much HTML; 415 unsupported Content-Type; 503 means the owner has not configured a key or could not allocate a page ID (retry publishing). The CLI exits nonzero and sends diagnostics to stderr. In --json mode, errors are JSON on stderr, leaving stdout empty. Metadata returns a version and an ETag containing that version. For updates, retention changes, and deletion, optionally send `If-Match: ""`; a stale version returns 409. On conflict, read current metadata before deciding to retry. The CLI supports --if-match on these commands. Publishing creates a new page each time. If a POST times out, list recent pages before retrying to avoid duplicates. Updates target an existing ID and preserve its public URL. No endpoint publishes its authentication token.