Docs
API
One request:
curl -X POST https://sharehtml.org/api/v1/pages \
-H 'Authorization: Bearer $SHAREHTML_TOKEN' \
-H 'Content-Type: text/html' \
--data-binary @page.htmlreturns {"url":"https://<name>.sharehtml.org/","id":"...","bytes":...}. Anonymous uploads need no token and get a manage key back instead. PUT replaces the file (same URL, new version, history kept on Pro). DELETE removes it. Limits: 5 MB free, 25 MB Pro, HTML only, 5 uploads a minute per IP. Every error is JSON with a stable code.
Base URL https://sharehtml.org/api/v1. All responses are JSON.
Authentication
Precedence, first match wins:
Authorization: Bearer <token>. API tokens are created from your dashboard once signed in. Pages belong to your account and count toward its quota.- The session cookie, when calling from the sharehtml.org site itself.
- Nothing: the upload is anonymous. The response includes
manageKeyandmanageUrl, shown once. Send the key asX-Manage-Keyon later GET, PUT and DELETE calls. Lose it and the page can still be claimed from the same browser after signing in, but not from curl.
POST /pages
Creates a page. Three body forms are accepted:
Raw HTML
Content-Type: text/html, the file as the body. Optional ?slug= query (Pro).
curl -X POST https://sharehtml.org/api/v1/pages \
-H 'Authorization: Bearer $SHAREHTML_TOKEN' \
-H 'Content-Type: text/html' \
--data-binary @page.htmlJSON
{"html": "...", "slug"?: "..."}
curl -X POST https://sharehtml.org/api/v1/pages \
-H 'Content-Type: application/json' \
-d '{"html":"<!doctype html><title>Hi</title><h1>Hi</h1>","slug":"hello-there"}'Multipart form
Field file, optional slug, optional cf-turnstile-response. This is what the browser sends.
curl -X POST https://sharehtml.org/api/v1/pages \
-F 'file=@page.html' \
-F 'cf-turnstile-response=<token from the widget>'From JavaScript
const res = await fetch('https://sharehtml.org/api/v1/pages', {
method: 'POST',
headers: { 'Content-Type': 'text/html' },
body: html,
})
const page = await res.json() // page.url, page.id, page.manageKeyResponse: 201
{
"id": "2b6f0c1e-7d2a-4d5a-9b1c-4f2e8a9d3c71",
"url": "https://k3x9q2a.sharehtml.org/",
"slug": "k3x9q2a",
"bytes": 18342,
"visibility": "unlisted",
"status": "active",
"manageUrl": "https://sharehtml.org/m/<manage-key>",
"manageKey": "<manage-key>",
"qrSvg": "<svg xmlns=\"http://www.w3.org/2000/svg\" ...>"
}statusisactive, orheldwhen the page is under review.visibilityis alwaysunlistedon creation; change it with PATCH.manageUrlandmanageKeyappear only on anonymous uploads.qrSvgis an SVG of the URL (error correction M, 2-module border, drawn incurrentColoron a transparent background) ready to inline.- Uploading bytes identical to one of your own active pages returns that page instead of a new one.
Anonymous limits
- With a valid Turnstile token: 30 uploads a day per IP.
- Without one (curl, agents): 10 uploads a day per IP.
- Every call: 5 uploads a minute per IP.
- 25 live pages per person, free or anonymous. 1,000 on Pro.
GET /pages/{id}
Owner via bearer or session, or anonymous with X-Manage-Key.
curl https://sharehtml.org/api/v1/pages/<id> \
-H 'X-Manage-Key: <manage-key>'{
"id": "2b6f0c1e-7d2a-4d5a-9b1c-4f2e8a9d3c71",
"url": "https://k3x9q2a.sharehtml.org/",
"slug": "k3x9q2a",
"bytes": 18342,
"visibility": "unlisted",
"indexable": false,
"status": "active",
"version": 1,
"views": 12,
"title": "Q3 report",
"createdAt": "2026-09-03T10:15:00.000Z",
"updatedAt": "2026-09-03T10:15:00.000Z"
}viewscounts page loads at the edge.versionincrements on every PUT.titleis the document title read from the HTML, or null.indexableis the Pro publish-to-search switch.
PUT /pages/{id}
Replaces the file. Same auth and body forms as POST. Returns 200 with the POST shape. The URL does not change. Pro keeps the previous versions; free keeps the latest only.
curl -X PUT https://sharehtml.org/api/v1/pages/<id> \
-H 'Authorization: Bearer $SHAREHTML_TOKEN' \
-H 'Content-Type: text/html' \
--data-binary @page.htmlPATCH /pages/{id}
Owner only. JSON body, any subset of:
visibility:unlisted,public,privateorpasswordpassword: string, required when visibility ispasswordindexable: boolean, publish to searchslug: a custom name, 2-63 lowercase letters, digits or hyphens
private, password, indexable and slug need Pro; otherwise 403 pro_required. Returns 200 with the GET shape.
curl -X PATCH https://sharehtml.org/api/v1/pages/<id> \
-H 'Authorization: Bearer $SHAREHTML_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"visibility":"password","password":"correct horse","slug":"q3-report"}'DELETE /pages/{id}
Returns 204. The bytes are removed and the slug stays reserved, so nobody can reuse an address you once shared.
curl -X DELETE https://sharehtml.org/api/v1/pages/<id> \
-H 'X-Manage-Key: <manage-key>'GET /me
Bearer or session. Returns your id, email, plan and live page count.
curl https://sharehtml.org/api/v1/me \
-H 'Authorization: Bearer $SHAREHTML_TOKEN'
{"id":"...","email":"you@example.com","plan":"pro","pages":14}Errors
Every error is {"error":{"code","message"}}:
{"error":{"code":"too_large","message":"Free pages are limited to 5 MB."}}| Status | Code | Meaning |
|---|---|---|
| 413 | too_large | over 5 MB (free) or 25 MB (Pro) |
| 415 | not_html | the body is not an HTML document (PDF, ZIP, image, SVG and JSON magic bytes are rejected) |
| 422 | invalid_utf8 | the body is not valid UTF-8 (a NUL byte is 415 not_html) |
| 422 | rejected | the page failed the abuse heuristics (phishing patterns, droppers, hidden redirects) |
| 422 | slug_invalid | the slug is not 2-63 lowercase letters, digits or hyphens, or is reserved or a brand word |
| 409 | slug_taken | that slug belongs to another page |
| 429 | rate_limited | more than 5 uploads a minute; Retry-After is set when known |
| 429 | quota_exceeded | the daily anonymous cap, or 25 live pages (free) / 1,000 (Pro) |
| 403 | turnstile_failed | the cf-turnstile-response token did not verify |
| 403 | pro_required | private, password, indexable or a custom slug on a free page |
| 401 | unauthorized | bad or missing bearer token or manage key |
| 404 | not_found | no such page, or not yours |
Codes are stable. Match on code, not on message. See limits for the numbers behind them.
What your page is served with
Content-Type: text/html; charset=utf-8,X-Content-Type-Options: nosniffX-Robots-Tag: noindex, nofollowunless published to search on ProOrigin-Agent-Cluster: ?1,Referrer-Policy: strict-origin-when-cross-origin- No Content-Security-Policy, no X-Frame-Options, no cookies. Your page runs as written.
ETagand edge caching; updates purge within seconds.
CLI and MCP
A CLI is planned. Until then, the API is the interface; for agents has the copy-paste snippet.