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, opening a post,
and rendering visibility holes. ~60 lines, no account needed.
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.
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.
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
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.