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

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":42,"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"}'

Your site is now live at https://<slug>.shipsite.co/

Anonymous sites expire after 24 hours. Authenticate to make them permanent.

Authentication

Passwordless via email OTP. Two steps to get an API 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_..."}

Save your API key immediately. It is shown only once and cannot be recovered.

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", "hash": "sha256:..."}
  ],
  "viewer": {
    "title": "My Project",
    "description": "A demo site",
    "ogImagePath": "og.png"
  }
}

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"}}
    ],
    "skipped": ["style.css"],
    "finalizeUrl": "https://shipsite.co/api/v1/publish/bright-canvas-a7k2/finalize",
    "expiresInSeconds": 3600
  }
}
Provide a hash (SHA-256) for each file to enable incremental deploys. Files with matching hashes are skipped and copied server-side.

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

Presigned URLs expire after 1 hour. Use the uploads/refresh endpoint to get new ones.

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..."}

Activates the uploaded version. The site is now live. For incremental deploys, hash-matched files are copied server-side during finalization.

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

Returns site metadata, current/pending version IDs, and the file manifest.

List Sites

GET/api/v1/publishes

Returns all sites for the authenticated user.

Update Metadata

PATCH/api/v1/publish/:slug/metadata

{
  "viewer": {"title": "New Title", "description": "Updated desc"},
  "ttlSeconds": 86400,
  "password": "secret"
}

Set password to a string to enable password protection. Set to null to remove.

Set ttlSeconds to auto-expire the site. Set to null to remove expiry.

Claim Anonymous Site

POST/api/v1/publish/:slug/claim

{"claimToken": "abc123..."}

Converts an anonymous site to your account. Removes the 24-hour expiry. Requires auth + the claim token from the original create response.

Duplicate a Site

POST/api/v1/publish/:slug/duplicate

Server-side copy to a new slug. Files are copied in S3 without re-upload.

Delete a Site

DELETE/api/v1/publish/:slug

Permanently deletes the site and all its files.

Version History ShipSite

GET/api/v1/publish/:slug/versions

List all deployed versions with timestamps and file counts. 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..."}

Instantly revert to any previous version. No re-upload needed — the files are already in S3.

{
  "success": true,
  "slug": "bright-canvas-a7k2",
  "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}
}
Analytics data is retained for 90 days. IP addresses are hashed for privacy and never stored in plain text.

Limits

FeatureAnonymousAuthenticated
Max file size25 MB5 GB
Max files per site20500
Site expiry24 hoursPermanent
Rate limit5/hour per IP200/hour
Version historyFull
RollbackAny version
ZIP downloadCurrent version
Analytics90-day retention

Serving Rules

When a request hits <slug>.shipsite.co/:

  1. If index.html exists, serve it
  2. If only one file, serve that file
  3. Otherwise, show a directory listing

Subdirectory paths resolve to <path>/index.html if present.