Hep.gg Forms
Hosted forms at forms.hep.gg with a public JSON API for reading a form's schema and submitting responses.
Hep.gg Forms
Hep.gg Forms hosts a form at https://forms.hep.gg/<slug> and renders it as a self-contained page with multi-page layouts, per-field validation, captcha, save-and-continue, and owner-configured delivery actions (email, Discord, SMS, HTTP webhook). The same data that drives that page is available as a small public JSON API, so you can read a form's schema and submit responses from your own client or an embedded widget.
Hosts
The public JSON API answers on both hosts:
https://forms.hep.gg(the form's own host; the renderer calls the API same-origin here)https://hep.gg
The examples below use https://forms.hep.gg. The hosted HTML page at https://forms.hep.gg/<slug> is only served on the exact forms.hep.gg host; the root https://forms.hep.gg/ redirects (302) to https://hep.gg.
Authentication
The public endpoints take no API key and no bearer token. There is no public endpoint to create or manage a form; forms are built and published in the Hep.gg dashboard, and the owner controls who can submit through the form's login modes:
- Anonymous - no sign-in. A Cloudflare Turnstile captcha token is mandatory on submit, and one field is designated the email field by the owner.
- Hep.gg account - the submitter must have an active
.hep.ggsession (any hep.gg sign-in). Becauseforms.hep.ggshares the.hep.ggsession cookie, a signed-in visitor is detected automatically. - Discord - same as hep.gg account, but the session must have a linked Discord identity.
- SMS PIN - the submitter verifies a phone number with a one-time code before submitting. See SMS PIN verification.
Which modes a form accepts is published in its schema as login_modes. Read the schema first, then satisfy whichever mode applies.
Response envelope
Every JSON endpoint returns the same envelope.
{ "ok": true, "data": { } }{ "ok": false, "error": "Human-readable message", "code": "optional", "details": { } }Check ok before reading data. The HTTP status carries the category (400 validation/captcha, 401 sign-in required, 403 window/cap, 404 not found, 410 expired, 429 rate limited). See Public API for the full list.
Quickstart
Read a form's schema by slug, then post a submission. This is the smallest working flow for an anonymous form (replace my-form with the form's slug and supply your own field keys).
# 1. Read the schema
curl https://forms.hep.gg/api/v1/forms/public/my-form
# 2. Submit (anonymous form -> Turnstile token required)
curl -X POST https://forms.hep.gg/api/v1/forms/public/my-form/submit \
-H "Content-Type: application/json" \
-d '{
"data": { "your_name": "Ada", "your_email": "ada@example.com" },
"turnstileToken": "<cf-turnstile-response>"
}'const base = "https://forms.hep.gg/api/v1/forms/public/my-form";
// 1. Read the schema
const schema = await fetch(base).then((r) => r.json());
// 2. Submit (anonymous form -> Turnstile token required)
const res = await fetch(`${base}/submit`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
data: { your_name: "Ada", your_email: "ada@example.com" },
turnstileToken: "<cf-turnstile-response>",
}),
}).then((r) => r.json());
console.log(res); // { ok: true, data: { submissionId: "..." } }Where to go next
?embed=1.