Examples
Small, self-contained frontends over this host's live API — each is one file, and view-source is the tutorial. More will land here over time. Full shapes, errors and limits: API reference.
Public feed reader →
Anonymous
GET /v1/posts, keyset pagination, playable post
pages, comments, and visibility holes. No account needed.
Serial editor →
Upload an audio serial episode by episode, order it (filenames sort
numerically, so ep2 lands before ep10), and save it as one post — the order
you see IS post_items.seq. Publishes both halves: every
episode's content row and the post, because visibility is decided per
content and not inherited. Needs an account.
Serial player →
Plays a serial post straight through: auto-advance at the end of each
episode, a contents list, and it resumes where you left off. Anonymous —
<audio> points at /v1/contents/{id}/file, so
seeking rides Range and a repeat play is a 304. No account needed.
Knowledge-base search →
知识库检索: pick a category (历史 today), ask in plain words, read the
matching passages from the classics and history books behind it — each with
its book, years and places, and 「看上下文」 for the paragraphs around it.
Free, no account needed.
Account →
Login/registration, balance & ledger (credits), email
verification, and minting referral codes — the whole account surface.
Generate studio →
Generate audio from a caption, preview the candidate variants (playable,
with waveforms), and commit the one you like into your library. Needs an account.
Image studio →
Draw a picture, redraw it, or turn a photo into an illustration — with an
assistant that writes the prompt in the chosen style's own dialect (each backend
style publishes its own manual, and writing the wrong one fails silently). One
picture per job, ~40s. Needs an account.
Multitrack studio →
Generate tracks, arrange them into a post, download or inspect each lane
(read-only tool_defined_content_meta), and hear a monitoring
mix — N lanes summed live from a recipe in annotations + post.meta.
No new bytes; the mix is deterministic. Needs an account.
Novel desk →
短篇 → 小说: one short piece teaches the three moves, then 库 → 书 → 章
opens up — one sentence and a cap start a book, the four story elements are
agreed once, then the queue signs chapter after chapter to the cap and
shelves each on landing. A command bar with its own record replaces the chat
window. Delivered or free — a chapter that never lands is
refunded. Needs an account. The
design brief is what the book side
was built from.
Novel reader →
The other half, on purpose: contents, chapter, and search across a
whole book — and not one control that could generate anything. Keeps
your place, marks what you finished, and search lands you on the paragraph.
?book=<run_id> opens straight into a book (the desk's
「读 ↗」 does exactly that). Needs an account.
By hand — curl & a minimal JS client
1 · Read the public feed (no account)
curl -s https://hygpo.com/v1/posts | jq .
# → {"items":[{...post summaries, no items field...}], "next":""}
curl -s https://hygpo.com/v1/posts/<post-id> | jq .
# → the post with hydrated items; items you may not see are
# {"seq":n,"content":null} — a hole, not an error.
2 · Register (needs a referral code) and log in
curl -s https://hygpo.com/v1/users -H 'Content-Type: application/json' \
-d '{"referral_code":"<code>","email":"[email protected]","password":"correct horse"}'
S=$(curl -s https://hygpo.com/v1/sessions -H 'Content-Type: application/json' \
-d '{"email":"[email protected]","password":"correct horse"}' | jq -r .session_token)
3 · Upload audio, arrange it into a post, publish
CID=$(curl -s https://hygpo.com/v1/contents -H "Authorization: Bearer $S" \
-F kind=audio -F caption="my track" -F [email protected] | jq -r .id)
PID=$(curl -s https://hygpo.com/v1/posts -H "Authorization: Bearer $S" \
-H 'Content-Type: application/json' -d '{
"caption": "My song",
"body": "liner notes — the server never reads this",
"meta": {"layout": "track-editor"},
"items": [
{"content_id": "'$CID'", "annotation": {"role": "vocal", "gain": 0.8}},
{"content_id": "'$CID'", "annotation": {"role": "full-mix"}}
]}' | jq -r .id)
curl -s -X PATCH https://hygpo.com/v1/posts/$PID -H "Authorization: Bearer $S" \
-H 'Content-Type: application/json' \
-d '{"status":"published","visibility":"public"}'
Note role, gain, layout are your
vocabulary — the server stores them opaquely. A different frontend can arrange
the same contents with entirely different annotations.
4 · Session refresh (single-use rotation)
# session tokens live 15 minutes; on a 401, rotate:
curl -s https://hygpo.com/v1/sessions/refresh -H 'Content-Type: application/json' \
-d '{"refresh_token":"<stored refresh token>"}'
# → NEW session_token + NEW refresh_token. The old refresh token is dead;
# reusing it revokes the whole family (you must log in again).
5 · Minimal JavaScript client
const B = ''; // same origin
async function api(path, opts = {}, sess) {
const headers = { ...(opts.headers || {}) };
if (sess) headers.Authorization = 'Bearer ' + sess.session_token;
let r = await fetch(B + path, { ...opts, headers });
if (r.status === 401 && sess?.refresh_token) { // rotate once, retry once
// NB: if you fire requests in parallel, share ONE refresh between them —
// rotating the same token twice reads as theft and logs you out everywhere.
const rr = await fetch(B + '/v1/sessions/refresh', {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refresh_token: sess.refresh_token }) });
if (!rr.ok) throw new Error('session expired');
Object.assign(sess, await rr.json()); // new pair
headers.Authorization = 'Bearer ' + sess.session_token;
r = await fetch(B + path, { ...opts, headers });
}
const body = await r.json().catch(() => ({}));
if (!r.ok) throw new Error(body.error || r.status);
return body;
}
// login
const sess = await api('/v1/sessions', { method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password }) });
// upload (multipart — do NOT set Content-Type yourself)
const fd = new FormData();
fd.append('kind', 'audio'); fd.append('caption', 'my track');
fd.append('file', fileInput.files[0]);
const content = await api('/v1/contents', { method: 'POST', body: fd }, sess);
// paginate the public feed
let cursor = '';
do {
const page = await api(`/v1/posts?limit=20&after=${cursor}`);
page.items.forEach(renderSummary);
cursor = page.next;
} while (cursor);
What to build
The reference's §1 core concepts explains the
essence/organization split that makes frontends interchangeable. Good first
projects: a gallery over public image posts; a track player over audio posts
reading your own annotation vocabulary; an uploader + drafts desk
for your own library.