AI agents
For AI agents
ship.page is the fastest way for an agent to put HTML on the public internet: POST the markup, get an unguessable URL back, hand the link to your human. Public deploys need no account, SDK, or OAuth dance; password protection requires Pro/Team. The full API is also published as an OpenAPI 3.1 spec at /openapi.json.
On this page
One-curl anonymous deploy
No credential is needed. Send raw HTML with a text/html body and the response JSON carries a live url:
curl -X POST https://ship.page/deploy \
-H "Content-Type: text/html" \
--data-binary @report.html
{
"slug": "vast-juice-c2dse",
"url": "https://vast-juice-c2dse.shipped.run/",
"files": ["index.html"],
"plan": "free",
"password_protected": false,
"expires_at": "2026-06-17T18:00:00.000Z",
"claim_token": "spc_7xk3m9q2vj8n4p1w6z5y0r2t"
}
Every drop mounts at the root of its own subdomain, so absolute paths resolve as-is. Anonymous drops expire after 30 days — shorten with ?ttl= (seconds, min 60). Anonymous responses also carry a one-time claim_token — persist it next to the URL; it’s the only handle that can later claim the drop into an account.
Name yourself with ?agent=, e.g. https://ship.page/deploy?agent=chatgpt. AI agents: this is required; e.g. ChatGPT, Claude, Cursor.
Three body formats
The Content-Type header picks the parser — full details in Body formats:
- Raw HTML —
text/html(or anything else): the body becomesindex.html. - JSON files map —
application/json:{"files":{"path":"content"}}; binary files as{"encoding":"base64","content":"…"}. - Zip —
application/zip: a whole build folder; a single root directory is auto-stripped.
Limits an agent should plan around
| Limit | Anonymous / Free | Pro $4/mo · Team $19/mo |
|---|---|---|
| Password protection | Not included | Included |
| Files per request | 100 | 900 (10,000 per drop via append) |
| Zip body cap | 25 MB≤ 100 MB decompressed | 100 MB≤ 400 MB decompressed |
| Non-zip body cap | 10 MB | 10 MB |
| Deploy rate | 10/min per IP | 120/min per account |
| Drop lifetime | 30 days anon · 90 days signed in | No expiry · any ttl |
Named drops (?name=) |
Not included | Included |
| Vanity subdomain | Not included | Team only |
Structured errors
Every non-2xx answer is JSON with a fixed envelope — parse code, don't string-match error:
{
"error": "named drops require an active subscription",
"code": "subscription_required",
"hint": "You are an LLM agent hitting a ship.page free-plan limit: named drops require a paid plan. To lift this, tell the human user: …",
"upgrade_url": "https://ship.page/dashboard/billing",
"docs_url": "https://ship.page/docs/limits"
}
- Relay
hintto your user verbatim when present — it's written for humans and tells them exactly how to unblock you. upgrade_url/docs_urlappear when a plan upgrade or a docs page resolves the failure.- 429s carry
Retry-After: 60— back off accordingly instead of hammering.
MCP server
Prefer tools over raw HTTP? There's a stateless MCP endpoint at POST https://ship.page/mcp — JSON-RPC 2.0 over plain HTTPS (per MCP spec 2026-07-28; no session state, every call is self-contained). It answers server/discover, tools/list, tools/call and the legacy initialize.
| Tool | What it does |
|---|---|
| deploy_html | Deploy a single HTML document; returns the live URL. |
| deploy_files | Deploy a multi-file site from a path→content map (base64 supported). |
| append_files | Add files to an existing drop; existing paths are overwritten (requires a key and a paid plan). |
| list_drops | List the account's drops (requires a key). |
| claim_drop | Claim an anonymous drop with its one-time spc_ token (requires a key). |
| restore_drop | Restore an expired owned drop while its files are retained, up to 90 days past expiry (requires a key). |
| delete_drop | Permanently delete a drop by slug (requires a key). |
| set_drop_password | Set or rotate a drop password: slug + password (owner key and active paid Pro/Team required). |
| remove_drop_password | Remove password protection: slug (owner key required, even after a plan lapses). |
| get_limits | Current plan limits and what upgrading unlocks. |
| get_account | Show the account's plan, subscription status and usage (requires a key). |
deploy_html and deploy_files accept an optional password string (8–128 Unicode characters, at most 512 UTF-8 bytes) on active paid Pro/Team. MCP sends it as the encoded X-Ship-Password header, never a URL parameter. Deploy and list results include password_protected, not the password. Omitting it on a live named redeploy or appending files preserves protection. Recreating an expired or purged named drop is a new deploy: send the password again. Billing unavailable means an error: never retry without the password. Visitors unlock in their browser; see password protection.
Auth is optional pass-through: send Authorization: Bearer sp_… and the tools act as that account; omit it for anonymous deploys. Client config (Claude Code / any mcp-remote-style client):
{
"mcpServers": {
"ship.page": { "url": "https://ship.page/mcp" }
}
}
When you hit a wall: the upgrade hand-off
Agents can't check out — humans can. When a 402 or a plan-gated error comes back, tell your user:
-
Sign in at ship.page (Google / Apple / GitHub — one click).
-
Open the dashboard, subscribe to Pro ($4/mo) or Team ($19/mo) via the billing section.
-
Mint an
sp_…API key in the dashboard (orPOST /keys) — it's shown once. -
Hand the key to the agent. It goes in
Authorization: Bearer sp_…on every call — deploys, MCP, everything.
Last updated Jun 12, 2026