Contact forms

The one-way SMS, email, and Discord contact endpoints a public profile exposes, with the mandatory Cloudflare Turnstile token and the rate limits that protect them.

Contact forms

A published profile can expose up to three one-way contact forms. A visitor fills one in on the public page and the message is delivered to you, the owner, over SMS, email, or Discord. The visitor never sees your phone number, email address, or Discord channel. These endpoints are meant to be called from the visitor's browser on the public profile, but they are documented here so you can wire them into a custom-built contact form on your own profile.

  • SMS sends with the owner's SMS key and debits their SMS credits.
  • Email sends with the owner's email key and debits their email credits.
  • Discord posts an embed to the owner's configured channel; no credit cost.

Common requirements

Cloudflare Turnstile is mandatory. Every contact POST must include a valid turnstileToken. This replaces an API key: it proves the request came from a real browser, not a script. Render a Turnstile widget on your form and send the token it produces. A missing or failing token is rejected with 400 and the generic error Anti-spam check failed (the same shape as other validation errors, so bots get no hint that Turnstile is running).

Owner setup. Each channel only works once you have set it up in the dashboard:

  • SMS: an enabled SMS key plus a 2FA-verified phone, and a positive sms_credits balance.
  • Email: a verified email address plus an enabled email key, and email credits.
  • Discord: a configured notification channel with the Hep.gg bot present in that channel's server.

If a channel is not set up, the endpoint returns 400 with a message telling the visitor the form is not active. It never reveals which piece is missing.

Rate limits. All three forms enforce the same triple-bucket limit, evaluated before Turnstile so flagrant abuse is cheap to reject:

BucketLimit
Per IP + profile, burst3 per minute
Per IP + profile, daily30 per day
Per owner, daily50/day (SMS), 100/day (email and Discord)

A throttled request returns 429. The per-IP burst bucket also sends a Retry-After header (in seconds).

Response envelope. Success is the standard { "ok": true, "data": { ... } }. Errors are { "ok": false, "error": "<message>" }.

SMS

POSThttps://hep.gg/api/v1/profiles/:profileID/contact/smsPublic
Send a one-way SMS to the profile owner's verified phone.

Sends a text to the owner's verified phone. Each send debits one of the owner's SMS credits, so the per-owner daily cap (50) is the real cost ceiling.

Path parameters
profileID
stringrequired
The profile's ID (profiles.id).
Body fields
message
stringrequired
The message body. Trimmed; truncated to 160 characters.
turnstileToken
stringrequired
A valid Cloudflare Turnstile token.
curl
curl -X POST https://hep.gg/api/v1/profiles/PROFILE_ID/contact/sms \
  -H "Content-Type: application/json" \
  -d '{"message":"Hey, loved your site!","turnstileToken":"TURNSTILE_TOKEN"}'

Responses

StatusMeaning
200{ "ok": true, "data": { "queued": true } }
400Message required, Turnstile failed, or owner has not set up SMS
402Owner is out of SMS credits
404Profile not found, not public, or suspended
429Rate-limited (burst sends Retry-After)
502SMS delivery failed or was unavailable

Email

POSThttps://hep.gg/api/v1/profiles/:profileID/contact/emailPublic
Email the profile owner; visitor's address is set as reply-to.

Emails the owner's verified address through the hep.gg SMTP pipeline. The visitor's email is set as the reply-to so the owner can reply directly; the owner's address is never exposed to the visitor.

Path parameters
profileID
stringrequired
The profile's ID (profiles.id).
Body fields
email
stringrequired
The visitor's email address, used as reply-to. Must be a valid email.
subject
stringoptional
Optional subject. Trimmed; truncated to 120 characters. A default subject is used when omitted.
message
stringrequired
The message body. Trimmed; truncated to 2000 characters.
turnstileToken
stringrequired
A valid Cloudflare Turnstile token.
curl
curl -X POST https://hep.gg/api/v1/profiles/PROFILE_ID/contact/email \
  -H "Content-Type: application/json" \
  -d '{"email":"visitor@example.com","subject":"Hello","message":"Great profile!","turnstileToken":"TURNSTILE_TOKEN"}'

Responses

StatusMeaning
200{ "ok": true, "data": { "queued": <boolean>, "messageId": "<id>" } }
400Invalid email, message required, Turnstile failed, or owner has not set up email
402Owner is out of email credits
404Profile not found, not public, or suspended
429Rate-limited (burst sends Retry-After)

Other rejections from the email pipeline pass through their own status code and error message.

Discord

POSThttps://hep.gg/api/v1/profiles/:profileID/contact/discordPublic
Post a one-way embed into the owner's Discord channel.

Posts a one-way embed into the owner's configured notification channel through the Hep.gg bot. No credit cost; the rate-limit budget is the only abuse cap. The owner must have a channel configured and the Hep.gg bot present in that channel's server.

Path parameters
profileID
stringrequired
The profile's ID (profiles.id).
Body fields
handle
stringoptional
Optional sender name, shown as the embed's "From" field. Trimmed; truncated to 64 characters. Defaults to Anonymous visitor.
message
stringrequired
The message body. Trimmed; truncated to 1000 characters.
turnstileToken
stringrequired
A valid Cloudflare Turnstile token.
curl
curl -X POST https://hep.gg/api/v1/profiles/PROFILE_ID/contact/discord \
  -H "Content-Type: application/json" \
  -d '{"handle":"Jamie","message":"Pinging you on Discord!","turnstileToken":"TURNSTILE_TOKEN"}'

Responses

StatusMeaning
200{ "ok": true, "data": { "queued": true } }
400Message required, Turnstile failed, or owner has not set up Discord
404Profile not found, not public, or suspended
429Rate-limited (burst sends Retry-After)
502Delivery failed