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.ship.place/",
"files": ["index.html"],
"plan": "free",
"password_protected": false,
"expires_at": "2026-06-17T18:00:00.000Z",
"claim_token": "spc_7xk3m9q2vj8n4p1w6z5y0r2t",
"claim_url": "https://ship.page/claim?slug=vast-juice-c2dse&token=spc_7xk3m9q2vj8n4p1w6z5y0r2t&via=api",
"next_step": "This page goes offline on 2026-06-17. Opening claim_url saves it to a free ship.page account and keeps it online for 90 days. Anyone with that link can claim the page, so share it only with the person this page was made for."
}

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. They also carry claim_url and next_step; pass both on to the person the page is for, since opening the link saves the drop to their account. Anyone with that link can claim the drop, so keep it out of public places.

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 10,000
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, or a sign-in link by email).

  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