JSON API

shareyourhtml has a tiny JSON API so you can create and manage pages from any tool that can make an HTTP request — including LLMs with tool-use capabilities.

All requests must include Content-Type: application/json. The API automatically returns JSON when it sees this header — no need to append .json to URLs or set an Accept header.

Create a page

POST https://shareyourhtml.com/pages with Content-Type: application/json.

{
  "slug": "my-page",
  "html": "<h1>Hello</h1>",
  "password": "optional-viewer-password",
  "expiry": "30"
}

curl

curl -X POST https://shareyourhtml.com/pages \
  -H "Content-Type: application/json" \
  -d '{"slug":"my-page","html":"<h1>Hello</h1>","password":"secret"}'

fetch (JavaScript)

await fetch("https://shareyourhtml.com/pages", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    slug: "my-page",
    html: "<h1>Hello</h1>"
  })
}).then(r => r.json());

Ruby (Net::HTTP)

require "net/http"
require "json"

uri = URI("https://shareyourhtml.com/pages")
res = Net::HTTP.post(
  uri,
  { slug: "my-page", html: "<h1>Hello</h1>" }.to_json,
  "Content-Type" => "application/json"
)
JSON.parse(res.body)

Success response (201 Created)

{
  "slug": "my-page",
  "url": "https://my-page.shareyourhtml.com",
  "edit_key": "f1e2d3c4-b5a6-7890-1234-567890abcdef"
}

What you get back

Save the edit_key. It is the only way to edit or delete the page. We cannot recover it for you.

Update a page

PATCH https://shareyourhtml.com/pages/:slug with Content-Type: application/json.

Update any combination of fields on an existing page. Requires edit_key. Include only the fields you want to change — omitted fields are left unchanged.

{
  "edit_key": "f1e2d3c4-b5a6-7890-1234-567890abcdef",
  "html": "<h1>Updated content</h1>",
  "password": "viewer-secret"
}

Examples

Update content only:

curl -X PATCH https://shareyourhtml.com/pages/my-page \
  -H "Content-Type: application/json" \
  -d '{"edit_key":"f1e2d3c4-...","html":"<h1>New version</h1>"}'

Add a password without changing content:

curl -X PATCH https://shareyourhtml.com/pages/my-page \
  -H "Content-Type: application/json" \
  -d '{"edit_key":"f1e2d3c4-...","password":"secret"}'

Remove a password:

curl -X PATCH https://shareyourhtml.com/pages/my-page \
  -H "Content-Type: application/json" \
  -d '{"edit_key":"f1e2d3c4-...","password":null}'

Update content and set a password at the same time:

curl -X PATCH https://shareyourhtml.com/pages/my-page \
  -H "Content-Type: application/json" \
  -d '{"edit_key":"f1e2d3c4-...","html":"<h1>Private</h1>","password":"secret"}'

Success response (200 OK)

{
  "slug": "my-page",
  "url": "https://my-page.shareyourhtml.com",
  "password_protected": true
}

Error responses


Error response (422 Unprocessable Entity)

{
  "errors": {
    "base": ["slug has already been taken"]
  }
}

Validation errors (slug taken, slug format, empty body, content too large) all come back as 422 with an errors object.


Page Memory

Every hosted page has a persistent key-value store. Data is scoped to the page and shared across all visitors. No setup required — it just works.

window.syh — in-page helper

window.syh is injected automatically into every hosted page. All methods return Promises.

// Read a value — returns undefined if the key doesn't exist
const count = await syh.get("likes");

// Write any JSON-serializable value
await syh.set("likes", 42);
await syh.set("data", { name: "Alice", score: 100 });

// Increment a number — creates at 0 if missing, returns the new value
const n = await syh.increment("likes");       // +1
const n = await syh.increment("likes", 5);    // custom amount
const n = await syh.increment("likes", -1);   // decrement

// Delete a key — returns false if not found
await syh.delete("likes");

// List all keys (metadata only — no values)
const info = await syh.list();
// { keys: [{key, byte_size, updated_at}], total_keys, used_bytes, max_bytes }

REST endpoints

The store is accessible via HTTP from within the page's origin (https://<slug>.shareyourhtml.com).

GET    /__store               # list all keys (metadata, no values)
GET    /__store/:key          # read a value
PUT    /__store/:key          # write a value  →  body: {"value": <any JSON>}
POST   /__store/:key/increment # increment     →  body: {"amount": 1}
DELETE /__store/:key          # delete a key

Limits

Example: like button

<button id="btn">Loading...</button>
<script>
  const btn = document.getElementById("btn");
  syh.get("likes").then(n => btn.textContent = `Like (${n ?? 0})`);
  btn.addEventListener("click", async () => {
    const n = await syh.increment("likes");
    btn.textContent = `Like (${n})`;
  });
</script>
Security notes. Store data is scoped to the page — one page cannot read another's store. Password-protected pages require the viewer to unlock before the store is accessible. Data is public to all visitors of the page — do not store secrets or personal information.