API & function surface
Read paths use PostgREST‑style endpoints generated from the schema. Write paths and sensitive logic run inside InsForge functions with the service role.
8.1 — Catalogue
GET /artworks
GET /artworks/{slug}
GET /artwork_categories
GET /content_packs
GET /content_packs/{slug}
Every install holds an anonymous session from first launch (see §7.8), so every catalogue read is authenticated by a JWT. There is no “signed‑out” surface. RLS filters all reads through is_published = true; reviewers and admins additionally see drafts.
8.2 — Downloads
POST /functions/get-artwork-download-url
body { "slug": "afro-caribbean-carnival-001" }
returns // free artwork → public CDN URLs
{
"kind": "public",
"manifest": "https://cdn.../manifest.json",
"regions": "https://cdn.../regions.bin.br",
"preview": "https://cdn.../preview.webp",
"thumbnail":"https://cdn.../thumbnail.webp"
}
returns // premium artwork → signed URLs
{
"kind": "signed",
"manifest": "https://cdn.../manifest.json?sig=…",
"regions": "https://cdn.../regions.bin.br?sig=…",
"preview": "https://cdn.../preview.webp?sig=…",
"thumbnail":"https://cdn.../thumbnail.webp?sig=…",
"expiresAt": "2026-05-18T13:00:00Z"
}
Behaviour, in order of evaluation:
- Confirm the artwork exists and is published.
- If
is_premium = false→ returnkind: "public"with un‑signed CDN URLs. Anonymous users succeed at this step. - If
is_premium = true→ requireprofiles.is_anonymous = falseand an active entitlement covering this artwork. Returnkind: "signed"URLs valid for 15 minutes. Anonymous users get a403 sign_in_required; authenticated users without an entitlement get a402 paywall.
Rate‑limited at 60 requests per minute per auth.uid(). Resumed downloads call the endpoint again to receive a fresh signed URL when the prior one expires (see §6.6.2).
8.3 — Progress
GET /user_artwork_progress
POST /functions/sync-progress
body
{
"artworkId": "uuid",
"artworkVersion": 3,
"completedRegions": "",
"completedCount": 412,
"lastSelectedColourId": 7,
"lastPlayedAt": "2026-05-18T12:34:00Z"
}
The function computes the bitset union with the stored value, updates denormalised counters, and returns the merged state so the client can reconcile.
8.4 — Purchases
POST /functions/validate-purchase
GET /entitlements
POST /functions/restore-purchases
POST /functions/store-notification # webhook
The validate‑purchase function calls the Apple App Store Server API (JWT‑signed) or Google Play Developer API as appropriate, persists the receipt to purchase_receipts, and writes the resulting entitlement. The store‑notification webhook handles Apple ASSN v2 and Google RTDN renewal, refund, and revocation events.
8.5 — Admin
POST /functions/admin-create-artwork
POST /functions/admin-update-artwork
POST /functions/admin-publish-artwork
POST /functions/admin-unpublish-artwork
POST /functions/admin-generate-upload-url
POST /functions/admin-request-cultural-review
All admin functions check the caller’s profiles.role = 'admin' claim before proceeding.