ShipSite API
Instant static site hosting. Publish files and get a live URL at <slug>.shipsite.co.
Inspired by and API-compatible with here.now — whose elegant design made instant static hosting accessible to agents everywhere. ShipSite builds on that foundation with additional features: version history, instant rollback, ZIP export, and built-in analytics.
- Quick Start
- Plans and Billing
- Authentication
- Create a Site
- Upload Files
- Finalize
- Update a Site
- Get Site Details
- List Sites
- Update Metadata
- Claim Anonymous Site
- Duplicate a Site
- Delete a Site
- Version History ShipSite
- Rollback ShipSite
- Download as ZIP ShipSite
- Analytics ShipSite
- Share via Email ShipSite
- Limits
Quick Start
No account needed. Create an anonymous site in three steps:
1. Create
curl -sS https://shipsite.co/api/v1/publish \
-H "content-type: application/json" \
-d '{"files":[{"path":"index.html","size":20,"contentType":"text/html"}]}'
Returns presigned upload URLs and a finalizeUrl.
2. Upload
# PUT each file to its presigned URL
curl -X PUT "$UPLOAD_URL" \
-H "Content-Type: text/html" \
--data-binary "<h1>Hello world</h1>"
3. Finalize
curl -sS -X POST "$FINALIZE_URL" \
-H "content-type: application/json" \
-d "{\"versionId\":\"$VERSION_ID\",\"claimToken\":\"$CLAIM_TOKEN\"}"
Your site is now live at https://<slug>.shipsite.co/
Temporary, paid, and sponsored hosting
Permanent hosting is available with an active paid subscription or administrator sponsorship. Manage your account and billing.
Signing in and getting an API key are free; they do not grant permanent hosting. When available, the US$3.99/month subscription enables permanent hosting through the same API key. Administrator sponsorship waives payment, with the same limits and content rules.
With active paid or sponsored access, new sites are permanent by default. Pass "permanent": false to create a temporary site or "permanent": true to require permanent hosting. Permanent sites return expiresAt: null. An explicit permanent request returns 402 without access, or 503 while permanent hosting is disabled.
Limits: 500 MB shared storage (including versions, metadata, and temporary upload reservations), 5 GB transfer, 100,000 hosted/management requests, and 1,000 deployments per UTC calendar month. Permanent files are limited to 25 MB each (Markdown: 1 MB). Up to 500 files per deployment. Signed PUTs require the exact declared Content-Length; browsers set this automatically for Blob uploads. Upload links last 15 minutes and may be refreshed within one hour.
Only one deployment per site may be pending. Old versions count toward storage until deleted with DELETE /api/v1/publish/:slug/versions/:versionId; current versions cannot be deleted. Abandon a pending upload with DELETE /api/v1/publish/:slug/pending. Cleanup releases reservations after upload links expire; unfinished deployments are cleaned after one day. Permanent duplication requires a new publish with the source files.
GET /api/billing returns plan and usage. POST /api/billing/checkout and POST /api/billing/portal return Stripe URLs; POST /api/billing/sync refreshes access after payment. All require Bearer authentication. Cancellation preserves hosting through the paid period, followed by seven days of offline file retention.
Browser visits show a small ShipSite banner around sandboxed content on a separate origin. Top-level navigation, popups, and fullscreen from uploaded pages are unavailable. Agent instructions and abuse reporting remain outside the uploaded content. An administrator can exempt an individual account from the banner; neither payment nor sponsorship grants that exemption on its own.
Authentication
Passwordless via email OTP. An API key enables account management; it is not a paid subscription. Two steps to get a key:
Request a code
POST/api/auth/agent/request-code
{"email": "you@example.com"}
Verify and get your key
POST/api/auth/agent/verify-code
{"email": "you@example.com", "code": "ABCD-EFGH"}
Returns: {"apiKey": "sk_..."}
Use it in requests:
Authorization: Bearer sk_your_api_key_here
Create a Site
POST/api/v1/publish
Request body:
{
"files": [
{"path": "index.html", "size": 1024, "contentType": "text/html"},
{"path": "style.css", "size": 512, "contentType": "text/css"}
],
"viewer": {
"title": "My Project",
"description": "A demo site",
"ogImagePath": "og.png"
},
"spa": false
}
Set "spa": true for a single-page app that routes in the browser: an unmatched browser navigation then serves index.html instead of returning 404, so a reload on a client-side route works. Missing assets still return 404, because a script or stylesheet must never receive HTML. The flag defaults to false, which keeps genuine 404s for a multi-page site, and can be changed later with PATCH /api/v1/publish/:slug/metadata.
Example temporary-site response:
{
"slug": "bright-canvas-a7k2",
"siteUrl": "https://bright-canvas-a7k2.shipsite.co/",
"upload": {
"versionId": "01ABC...",
"uploads": [
{"path": "index.html", "method": "PUT", "url": "https://...", "headers": {"Content-Type": "text/html"}},
{"path": "style.css", "method": "PUT", "url": "https://...", "headers": {"Content-Type": "text/css"}}
],
"skipped": [],
"finalizeUrl": "https://shipsite.co/api/v1/publish/bright-canvas-a7k2/finalize",
"expiresInSeconds": 3600
},
"claimToken": "abc123...",
"expiresAt": "2026-03-30T12:00:00.000Z",
"anonymous": true,
"warning": "IMPORTANT: Save the claimToken for finalizing and managing this site. It is returned only once. Free sites expire 24 hours after creation."
}
expiresAt field is returned for every site. The claimToken, anonymous, and warning fields only appear for anonymous (unauthenticated) publishes. Save the claimToken — you need it to finalize, update, or claim the site.hash (64 hexadecimal SHA-256 characters, without a sha256: prefix) for each file to enable incremental deploys. Files with matching hashes are skipped and copied server-side.Viewer field limits: title max 200 chars, description max 500 chars, ogImagePath max 500 chars.
Upload Files
PUT each file to its presigned URL from the create/update response. Uploads go directly to S3 — the server never proxies file bytes.
curl -X PUT "$UPLOAD_URL" \
-H "Content-Type: text/html" \
--data-binary @index.html
Temporary-site upload URLs default to 1 hour. Permanent-site upload URLs last up to 15 minutes and can be refreshed only within the deployment’s original one-hour upload window. Use the returned expiresInSeconds. Send the returned upload headers and the exact declared file size; permanent uploads enforce Content-Length.
Refresh upload URLs
POST/api/v1/publish/:slug/uploads/refresh
Requires auth. Returns fresh presigned URLs for the pending version.
Finalize
POST/api/v1/publish/:slug/finalize
{"versionId": "01ABC...", "claimToken": "abc123..."}
Activates the uploaded version. The site is now live. For authenticated sites, use your API key. For anonymous sites, include the claimToken from the create response.
Markdown files (.md, .markdown) are automatically converted to styled HTML during finalization.
Response:
{
"success": true,
"slug": "bright-canvas-a7k2",
"siteUrl": "https://bright-canvas-a7k2.shipsite.co/",
"previousVersionId": null,
"currentVersionId": "01ABC..."
}
Update a Site
PUT/api/v1/publish/:slug
{"files": [...], "claimToken": "..." }
Same format as create. For authenticated sites, use your API key. For anonymous sites, include the claimToken.
Get Site Details
GET/api/v1/publish/:slug
Authorization: Bearer sk_...
Requires auth. Returns site metadata, current/pending version IDs, and the file manifest.
List Sites
GET/api/v1/publishes
Returns unexpired sites for the authenticated user.
Update Metadata
PATCH/api/v1/publish/:slug/metadata
{
"viewer": {"title": "New Title", "description": "Updated desc"},
"password": "secret"
}
Expiry cannot be changed. Requests containing ttlSeconds, including null or 0, return 400.
Password protection
Set password to a non-empty string to lock the site behind a passcode. Visitors see a password prompt and must enter the correct code before any content is served. The browser remembers the password for 24 hours via a cookie.
Set password to null to remove protection:
// Lock
{"password": "my-secret-code"}
// Unlock
{"password": null}
Passwords are hashed with scrypt before storage and never stored in plain text.
API clients and agents can bypass the browser prompt by sending the password in a header:
x-site-password: my-secret-code
Claim Anonymous Site
POST/api/v1/publish/:slug/claim
{"claimToken": "abc123..."}
Links an anonymous site to your account for management and sharing. The original expiry time is unchanged. Requires auth + the claim token from the original create response.
Duplicate a Site
POST/api/v1/publish/:slug/duplicate
{"viewer": {"title": "New Title", "description": "Optional override"}}
For temporary sites only: server-side copy to a new slug with the same expiry deadline as the source. Permanent sites return 400; publish a new site using the source files instead. Files are copied in S3 without re-upload. Optionally override the viewer title and description on the copy.
Response:
{
"slug": "new-slug-xyz",
"siteUrl": "https://new-slug-xyz.shipsite.co/",
"sourceSlug": "bright-canvas-a7k2",
"status": "active",
"currentVersionId": "01GHI...",
"filesCount": 5
}
Delete a Site
DELETE/api/v1/publish/:slug
Requires the owner’s API key. Takes the site offline. Permanent-site files and their storage reservations are removed by scheduled cleanup after outstanding uploads and a safety window; quota is not released immediately. Deleting sites does not cancel your subscription. Use the billing portal to cancel.
Version History ShipSite
GET/api/v1/publish/:slug/versions
List retained versions with timestamps. Temporary versions include file counts; permanent versions include storageBytes. Each publish or update creates a new version.
{
"slug": "bright-canvas-a7k2",
"versions": [
{"versionId": "01DEF...", "createdAt": "2026-03-29T...", "fileCount": 5, "current": true},
{"versionId": "01ABC...", "createdAt": "2026-03-28T...", "fileCount": 3, "current": false}
]
}
Rollback ShipSite
POST/api/v1/publish/:slug/rollback
{"versionId": "01ABC..."}
Revert to a retained, committed version. Permanent-site rollback requires active hosting access and no pending deployment. No re-upload needed — the files are already in S3.
{
"success": true,
"slug": "bright-canvas-a7k2",
"siteUrl": "https://bright-canvas-a7k2.shipsite.co/",
"previousVersionId": "01DEF...",
"currentVersionId": "01ABC..."
}
Download as ZIP ShipSite
GET/api/v1/publish/:slug/download
Download the current version of a site as a ZIP archive. Useful for backups or migrating to another host.
curl -OJ -H "Authorization: Bearer sk_..." \
https://shipsite.co/api/v1/publish/bright-canvas-a7k2/download
Analytics ShipSite
GET/api/v1/publish/:slug/analytics?days=30
View traffic analytics for your site. Returns daily breakdowns of views, unique visitors, top paths, and top referrers.
Query params: days (1–90, default 30)
{
"slug": "bright-canvas-a7k2",
"period": {"startDate": "2026-02-27", "endDate": "2026-03-29", "days": 30},
"daily": [
{
"date": "2026-03-29",
"views": 142,
"uniqueVisitors": 89,
"topPaths": [["/", 98], ["/about.html", 44]],
"topReferrers": [["google.com", 34], ["twitter.com", 12]]
}
],
"totals": {"views": 4210, "uniqueVisitors": 1893}
}
Share via Email ShipSite
POST/api/v1/publish/:slug/share
{
"senderName": "Kent",
"recipientName": "Alice",
"recipientEmail": "alice@example.com",
"message": "Check out my new project!"
}
Send a branded email to someone with a link to your site. The recipient receives a styled email with your name, an optional personal message, and a prominent link to the site.
Request body:
| Field | Required | Description |
|---|---|---|
senderName | Yes | Your name (max 64 chars) |
recipientName | Yes | Recipient's name (max 64 chars) |
recipientEmail | Yes | Valid email address (max 254 chars) |
message | No | Optional personal note (max 500 chars) |
Response:
{"success": true, "slug": "bright-canvas-a7k2", "recipientEmail": "alice@example.com"}
422 and the email is not sent. Rate limited to 10 shares per hour per user.Limits
ShipSite offers free temporary hosting and paid permanent hosting. The 24-hour limit is a maximum lifetime, not a guarantee of availability or content retention. Keep your own backups. Warranty and liability exclusions apply to the extent permitted by law; see the Terms of Service.
If we detect malicious content, we may remove the site immediately, without prior notice, regardless of payment or sponsorship. See the Terms of Service.
Expired sites return 410 Gone while their records await cleanup, then 404 Not Found. They cannot be updated, claimed, duplicated, downloaded, or reactivated. Existing temporary sites also expire no later than 24 hours after their original creation.
| Feature | Temporary · anonymous | Temporary · API key | Permanent · paid/sponsored |
|---|---|---|---|
| Price | Free | Free | US$3.99/month; sponsored accounts exempt |
| Site lifetime | Up to 24 hours | Up to 24 hours | While hosting access remains active |
| Maximum file size | 25 MiB | 5 GiB | 25 MB; Markdown 1 MB |
| Files per deployment | 20 | 500 | 500 |
| Permanent storage per account | Not included | Not included | 500 MB shared across all permanent sites |
| Permanent monthly allowances | Not included | Not included | 5 GB transfer; 100,000 hosted/management requests; 1,000 deployments |
| Management tools | Update/finalize with claim token | Versions, rollback, ZIP export, analytics, passwords, sharing | Same tools, within account allowances |
Temporary file limits use binary MiB/GiB (1 MiB = 1,048,576 bytes). Permanent-plan MB and GB are decimal (1 MB = 1,000,000 bytes). Storage includes retained versions, metadata, generated HTML, and upload reservations. Monthly allowances reset on the first day of each UTC calendar month, independently of your billing date. There are no automatic overage charges.
Temporary publish/update requests are limited to 5/hour per IP anonymously or 200/hour per signed-in account. Other endpoint rate limits also apply. Authentication is limited to 10 requests per 15 minutes per IP and 5 verification attempts per 15 minutes per email; email sharing is limited to 10/hour per account.
Markdown Support
Markdown files (.md, .markdown, .mdown, .mkd) are automatically converted to styled HTML during finalization. The original .md file is preserved and a new .html version is added to the manifest. If no index.html exists, the first root-level .md file is converted to index.html so it serves at /.
Serving Rules
Hosted subdomains reserve /robots.txt with Disallow: / and send X-Robots-Tag: noindex, nofollow, noarchive. This requests that compliant search engines avoid crawling and indexing hosted content; it does not restrict access or guarantee removal of previously indexed URLs.
Sites owned by accounts an administrator has exempted from the banner load directly at their normal URL, without a banner or sandboxed frame. Paid and sponsored accounts are not exempt by default. All other browser document visits show the ShipSite banner with content in a sandboxed frame at content-<slug>.shipsite.co. The banner does not certify uploaded content as safe. Direct browser navigation to the content host is blocked. Within the frame, or for non-browser requests, files resolve as follows:
On a site published with "spa": true, a browser navigation that matches no file serves index.html with status 200 instead of a 404; requests that do not accept HTML still 404.
- If
index.htmlexists, serve it - If only one file, serve that file
- Otherwise, show a directory listing
Subdirectory paths resolve to <path>/index.html if present.