# Success and errors Set redirects for form success and failure, handle JSON responses in JavaScript forms, and read every Form Plume submission error code. What happens after someone submits your form depends on how the form was sent. - A plain HTML form **always navigates to another page**. - A JavaScript form that asks for JSON **stays on your page** unless your code redirects it. ## Plain HTML forms always redirect A normal browser submission receives a `303` redirect from Form Plume: ```html
``` You choose where that redirect goes in the form's **Settings** under **What to do on success?** and **What to do on failure?** ### When the submission succeeds You can choose one of these options in the dashboard. | Setting | What the visitor sees | | --- | --- | | Hosted thank-you page | Form Plume's default confirmation page | | Redirect to URL | A page on your own website | The hosted page is the default. [View an example thank-you page](/thanks/demo). ### When the submission fails You can choose one of these options in the dashboard. | Setting | What the visitor sees | | --- | --- | | Hosted error page | Form Plume's default error page | | Same redirect as success | The custom URL already configured for success | | Redirect to URL | A separate error page on your website | [View an example error page](/error/demo?fp_error=validation_failed). Form Plume adds `fp_error` to custom failure URLs so your page can decide what to show: ```text https://example.com/form-error?fp_error=validation_failed ``` ## Can I customize the hosted pages? No. The hosted thank-you and error pages use Form Plume's standard title, message, and branding. They do not display submitted values. Use **Redirect to URL** when you need your own design, copy, tracking scripts, navigation, or next steps. You build and host that page, then paste its absolute `https://` URL into the form settings. ## Override the destination from one form The saved dashboard settings apply to every submission. [Reserved fields](/docs/forms/special-fields) can override them for one HTML form: ```html ``` The order is: 1. A valid `_redirect` or `_error_redirect` field in the request 2. The destination saved in the form settings 3. The Form Plume hosted page Use dashboard settings when every copy of the form should behave the same way. Use reserved fields only when separate forms or landing pages need separate destinations. ## JavaScript forms do not redirect automatically Send `Accept: application/json` when your page will handle the result: ```js const response = await fetch(endpoint, { method: "POST", headers: { Accept: "application/json" }, body: new FormData(form), }); const result = await response.json(); if (!response.ok) { showError(result.errors?._form ?? "The form could not be submitted."); return; } if (result.next) { window.location.assign(result.next); } else { showSuccess("Your message was sent."); } ``` On success, Form Plume returns: ```json { "ok": true, "id": "submission_id", "next": "https://example.com/thank-you" } ``` `next` contains the configured custom success URL, or `null` when the form uses the hosted page. Your JavaScript decides whether to follow it or show an inline message. On failure, Form Plume returns the correct HTTP status and an error body: ```json { "ok": false, "error": "validation_failed", "errors": { "_form": "The submission could not be accepted." } } ``` Always check `response.ok`. A completed network request is not necessarily a successful submission. ## Error codes | Code | Status | What it means | | --- | --- | --- | | `not_found` | 404 | The endpoint does not match a form | | `form_inactive` | 410 | The form has been disabled | | `unauthorized` | 401 | A private form did not receive a valid access key | | `origin_not_allowed` | 403 | The browser origin is not allowed | | `rate_limited` | 429 | Too many submissions arrived too quickly | | `email_rejected` | 422 | An email address failed the configured hygiene rules | | `captcha_failed` | 403 | A required CAPTCHA token did not verify | | `uploads_unavailable` | 503 | File storage is unavailable | | `too_many_files` | 413 | The submission contains too many files | | `invalid_file` | 400 | A file was empty, unreadable, or invalid | | `file_too_large` | 413 | A file exceeds the configured limit | | `unsupported_type` | 415 | The file type is not allowed | | `storage_quota_exceeded` | 402 | The account has reached its storage limit | | `validation_failed` | 400 or 422 | The payload or a protected control was invalid | | `payload_too_large` | 413 | The submission exceeds the field or payload limit | | `internal_error` | 500 | Form Plume could not process the request safely | A `429` response also includes `Retry-After`. Wait for that period before allowing another attempt.