Skip to content

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:

bash
curl -X POST https://ship.page/deploy \
-H "Content-Type: text/html" \
--data-binary @report.html
json 200 OK
{
"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 becomes index.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

ship.page limits for agents: anonymous/Free compared with Pro and Team
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:

json 402 Payment Required
{
"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 hint to your user verbatim when present — it's written for humans and tells them exactly how to unblock you.
  • upgrade_url / docs_url appear 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.

MCP tools exposed by ship.page
Tool What it does
deploy_htmlDeploy a single HTML document; returns the live URL.
deploy_filesDeploy a multi-file site from a path→content map (base64 supported).
append_filesAdd files to an existing drop; existing paths are overwritten (requires a key and a paid plan).
list_dropsList the account's drops (requires a key).
claim_dropClaim an anonymous drop with its one-time spc_ token (requires a key).
restore_dropRestore an expired owned drop while its files are retained, up to 90 days past expiry (requires a key).
delete_dropPermanently delete a drop by slug (requires a key).
set_drop_passwordSet or rotate a drop password: slug + password (owner key and active paid Pro/Team required).
remove_drop_passwordRemove password protection: slug (owner key required, even after a plan lapses).
get_limitsCurrent plan limits and what upgrading unlocks.
get_accountShow 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):

json · mcp config
{
"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:

  1. Sign in at ship.page (Google / Apple / GitHub — one click).

  2. Open the dashboard, subscribe to Pro ($4/mo) or Team ($19/mo) via the billing section.

  3. Mint an sp_… API key in the dashboard (or POST /keys) — it's shown once.

  4. Hand the key to the agent. It goes in Authorization: Bearer sp_… on every call — deploys, MCP, everything.

Last updated Jun 12, 2026