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."
}
}
Status Code What it means How to fix
400 validation_error The 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.
400 honeypot_triggered A 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.
400 spam_detected Server-side spam screening rejected the message. Review the submitted content, field names, and automation behavior.
400 too_many_fields The submission included too many fields. Remove unnecessary inputs before submitting.
400 too_many_files More than one non-empty attachment was submitted. Use one file input with one selected file.
400 file_too_large An attachment exceeded 4 MB. Upload a smaller file.
400 payload_too_large The submitted text or attachment payload was too large. Reduce field content or attachment size.
402 usage_limit_reached The account has reached its submission usage limit. Review usage in html.contact and upgrade or wait for the next period when applicable.
403 origin_missing No 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.
403 domain_not_allowed The 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.
403 form_inactive The form is paused or otherwise not accepting submissions. Resume the form in html.contact.
404 form_not_found The public form key is missing or invalid. Replace the placeholder with the real hc_pub_ key from your form. For /submit, include form_key.
409 idempotency_conflict The same explicit idempotency key was reused with different submitted content. Retry the same logical submission with identical content, or use a new idempotency key after changing the payload.
429 rate_limited Too many submissions arrived in the current rate-limit window. Wait and retry later. If this happens during testing, slow down repeated requests.
500 attachment_store_failed The 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.
500 storage_failed The submission could not be durably stored. Retry once. If it keeps happening, contact support.
503 storage_failed Submission 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.