Skip to content

Error Responses

Normal browser form posts receive an HTML success or error page. When you test with curl or a server-side script, request JSON with Accept: application/json or ?format=json.

Terminal window
curl "https://html.contact/f/hc_pub_REPLACE?format=json" \
-H "Accept: application/json" \
-H "Origin: https://example.com" \
-H "Referer: https://example.com/contact" \
--data-urlencode "email=mara@example.com" \
--data-urlencode "message=Hello"

JSON errors use this shape:

{
"ok": false,
"error": {
"code": "domain_not_allowed",
"message": "This form is not allowed on this website."
}
}
StatusCodeWhat it meansHow to fix
400validation_errorThe form payload could not be parsed, a field name was too long, or spam screening rejected a link-heavy message as invalid.Check the form encoding and field names. Keep field names short and avoid spammy/link-heavy content.
400honeypot_triggeredA honeypot field was filled.Keep _gotcha and any _hc_hp_* fields empty for real visitors. Use neutral honeypot names such as _hc_hp_extra; avoid autofill-shaped names such as _hc_hp_company, _hc_hp_name, _hc_hp_email, _hc_hp_phone, _hc_hp_website, or _hc_hp_address. Make sure custom scripts and autofill are not populating honeypot fields.
400spam_detectedServer-side spam screening rejected the message.Review the submitted content, field names, and automation behavior.
400too_many_fieldsThe submission included too many fields.Remove unnecessary inputs before submitting.
400too_many_filesMore than one non-empty attachment was submitted.Use one file input with one selected file.
400file_too_largeAn attachment exceeded 4 MB.Upload a smaller file.
400payload_too_largeThe submitted text or attachment payload was too large.Reduce field content or attachment size.
402usage_limit_reachedThe account has reached its submission usage limit.Review usage in html.contact and upgrade or wait for the next period when applicable.
403origin_missingNo usable browser source header was present, and direct server posts are not enabled for the form.Test from the deployed page, include browser-like source headers in server tests, or enable API submissions only when you intentionally need trusted server/curl posts.
403domain_not_allowedThe browser source hostname did not match the form’s allowed domains.Add the exact hostname that serves the form, such as example.com and www.example.com separately.
403form_inactiveThe form is paused or otherwise not accepting submissions.Resume the form in html.contact.
404form_not_foundThe public form key is missing or invalid.Replace the placeholder with the real hc_pub_ key from your form. For /submit, include form_key.
429rate_limitedToo many submissions arrived in the current rate-limit window.Wait and retry later. If this happens during testing, slow down repeated requests.
500attachment_store_failedThe uploaded attachment could not be stored, so the submission was not accepted.Retry the submission. If it keeps happening, remove the attachment and contact support.
500storage_failedThe submission could not be durably stored.Retry once. If it keeps happening, contact support.
503storage_failedSubmission storage is temporarily unavailable.Wait briefly and retry. Repeated failures should be reported to support.

For JSON tests, a successful submission returns:

{
"ok": true,
"submission_id": "sub_REPLACE",
"email_status": "provider_accepted"
}

email_status may also be not_attempted when the submission was stored but email delivery was not attempted, such as when the recipient is not ready for delivery.

A successful browser post can return a 303 redirect. html.contact considers submitted _redirect first, then the form’s Redirect URL setting.

Redirect URLs must be absolute https:// URLs. For local development, http://localhost:* and http://127.0.0.1:* are also allowed. If the chosen redirect URL is missing or invalid, html.contact returns the normal success response instead of redirecting.

This page focuses on public form submissions. Private API routes use the same general JSON error shape, but private API authentication, scopes, and endpoint-specific responses are documented in the Private API docs.