Public API
One HTTP call to publish AI-generated content as a public, shareable web page. Anonymous, rate-limited, CORS-permissive.
Endpoint
POST https://quicky.page/api/v1/publishSend Content-Type: application/json. No API key. No signup. Rate-limited at 30 publishes / 5 minutes / IP. Permissive CORS — call it from curl, a server, a browser, an extension, or an MCP server.
Markdown shape (recommended for agents)
Pass an optional title and a markdown content body. The server converts to qp.v1 blocks for you.
curl -X POST https://quicky.page/api/v1/publish \
-H 'content-type: application/json' \
-d '{
"title": "My AI Summary",
"content": "# Hello\n\nA paragraph with **bold** and a [link](https://example.com).\n\n- one\n- two"
}'Supported markdown subset:
#/##/###headings (deeper collapses to h3)- Paragraphs separated by blank lines
- Unordered (
-,*,+) and ordered (1.) lists **bold**,*italic*,_underline_,`inline code`[label](url)links- Standalone
image lines - Fenced code blocks (
```or~~~, optional language hint) →codeblock - Horizontal rules (
---,___,***) →dividerblock - Blockquotes (
> line) →quoteblock - GitHub-style callouts (
> [!NOTE|TIP|IMPORTANT|WARNING|CAUTION]) →calloutblock. The 5 GitHub tones collapse to qp's 3-tone palette:NOTE→ info,TIP→ success,IMPORTANT/WARNING/CAUTION→ warning.
Tables, footnotes, and inline HTML fall through as plain text — qp.v1's renderer doesn't display them.
Structured shape
Pass an explicit blocks array when you need control over block types (e.g., embeds).
curl -X POST https://quicky.page/api/v1/publish \
-H 'content-type: application/json' \
-d '{
"title": "My AI Summary",
"blocks": [
{ "type": "richtext", "html": "<h2>Subhead</h2><p>Paragraph.</p>" },
{ "type": "image", "url": "https://example.com/diagram.png", "alt": "Diagram" }
]
}'Each block is one of richtext, image, embed, html, callout, quote, divider, timeline, comparison, code, or button. All block content is sanitized server-side; unsafe HTML, scripts, and bad URLs are dropped before storage.
qp.v1 schema
The full block discriminated union and the publish payload envelope:
// qp.v1 — block schema for the publish API.
// Pages are a flat, ordered array of these discriminated-union members.
type Block =
| { type: "richtext"; html: string }
| { type: "image"; url: string; alt?: string }
| {
type: "embed";
embedType: "youtube" | "twitter" | "figma" | "codepen" | "iframe_sandbox";
url: string;
title?: string;
}
| { type: "html"; html: string; safetyMode: "strict_sanitized" }
| {
type: "callout";
tone: "info" | "warning" | "success";
html: string;
}
| { type: "quote"; html: string; attribution?: string }
| { type: "divider" }
| {
type: "timeline";
items: Array<{ label: string; body: string }>;
}
| {
type: "comparison";
left: string;
right: string;
leftLabel?: string;
rightLabel?: string;
}
| {
type: "code";
code: string;
language?: "plaintext" | "ts" | "tsx" | "js" | "jsx" | "json" | "html"
| "css" | "py" | "rb" | "go" | "rust" | "java" | "c" | "cpp"
| "csharp" | "swift" | "kotlin" | "php" | "sh" | "sql"
| "yaml" | "toml" | "xml" | "md" | "diff";
filename?: string;
}
| {
type: "button";
url: string;
label: string;
description?: string;
variant: "filled" | "outline" | "soft";
shape: "rounded" | "pill" | "square";
accent: "theme" | "slate" | "blue" | "green" | "amber"
| "red" | "purple" | "pink";
icon?: string;
};
// Top-level payload when posting blocks directly.
type PageOutput = {
version: "qp.v1";
blocks: Block[];
};Response
{
"id": "abc123",
"url": "https://quicky.page/abc123",
"editUrl": "https://quicky.page/?id=abc123#edit=...", // private edit link; treat as a secret
"editKey": "..." // 24-char raw secret; same key in another form, for programmatic updates
}urlis the public link. Anyone with it can read the page. Safe to share.editUrlis the private edit link in the exact format<base>/?id=<id>#edit=<editKey>— id in the querystring, editKey in the URL fragment (the fragment is never sent to the server, so the secret never appears in access logs or in theRefererheader on outbound clicks). Opens the editor in one click. Anyone with this URL can edit the page — treat as a secret. Give this to the user; do not reconstruct it fromeditKeyyourself.editKeyis the same secret in raw form. Use it as a request-body argument for programmatic updates (POST/api/v1/publishwithid+editKey) or for delete/rename (PATCH/DELETE/api/v1/pages/<id>). There is no recovery if you lose it — just publish a new page.
Updating a page
POST again with id and editKey. The same URL stays live; the new content fully replaces the old. There is no diff, no history, no rollback — Quicky.Page is intentionally not a CMS.
curl -X POST https://quicky.page/api/v1/publish \
-H 'content-type: application/json' \
-d '{
"id": "abc123",
"editKey": "...",
"content": "# New title\n\nUpdated body."
}'Other languages
JavaScript (fetch)
const res = await fetch("https://quicky.page/api/v1/publish", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
title: "My AI Summary",
content: "# Hello\n\nA paragraph.",
}),
});
const { id, url, editUrl, editKey } = await res.json();
console.log(url); // -> https://quicky.page/abc123 (public, share this)
console.log(editUrl); // -> https://quicky.page/?id=abc123#edit=... (private, edit link)Python (requests)
import requests
r = requests.post(
"https://quicky.page/api/v1/publish",
json={
"title": "My AI Summary",
"content": "# Hello\n\nA paragraph.",
},
)
r.raise_for_status()
data = r.json()
print(data["url"]) # -> https://quicky.page/abc123
print(data["editUrl"]) # -> https://quicky.page/?id=abc123#edit=...Errors
| Status | Meaning |
|---|---|
400 | Input couldn't be parsed or no usable content was provided. Body: { "error": "..." }. |
403 | editKey missing or wrong on an update. |
404 | Unknown id on an update. |
429 | Rate limit exceeded. Response includes Retry-After and X-RateLimit-* headers. |
500 | Server error. Retry with backoff. |
Title injection
When you supply title, it becomes a leading <h1>on the page — but only if the body doesn't already start with one. Sending both a title and a markdown content that opens with #won't stack two headings; the explicit one wins.
Reading a page back
GET https://quicky.page/api/v1/pages/<id>Returns the page's content as JSON. Read-only; no editKey required.
Want to publish from inside an AI client? See the MCP server (Claude Desktop, Cursor) or the ChatGPT Custom GPT. Want a one-click publish button in your browser? See the browser extension.