Responses and error codes
A 200 means the lead is stored. It does not mean it is delivered. Every answer the form address gives, and every refusal code.
What a 200 means
FormParcel answers only after the lead is written to its database and has a receipt ID. Delivery to the Google Sheet runs after that, on its own, so the answer can reach you before the row reaches the Sheet.
deliveryStatus "pending" leaves the lead here. "delivered" means every destination confirmed within the 2-second window.deliveryStatus says how far delivery got in the 2 seconds FormParcel waits before it answers:
"delivered": every enabled destination confirmed in time, and no Sheet column mapping was waiting for review."pending": the lead is stored and delivery carries on. Its receipt shows how it ends.
Both are success. Show the visitor your thank-you message either way, and never send the same lead again.
Request and response
Ask for JSON with Accept: application/json. A script, a server or curl gets JSON even without it.
Example form address. Use yours from the dashboard.
curl -X POST "https://f.formparcel.live/f/f_k7QmXp2aVb9sTn4cLw8RhE" \
-H "Accept: application/json" \
-d "name=Priya Sharma" \
-d "[email protected]" \
-d "message=Do you have Saturday appointments?"{
"accepted": true,
"deliveryStatus": "pending",
"submissionId": "sub_m1x8k2q4_Zk3v..."
}A curl post like this one carries no bot-check proof, so its lead waits in your Spam folder. It shows the answer; to test delivery, use Send a test lead in the dashboard. See Bot check.
- acceptedboolean
- Always
trueon a 200. - deliveryStatus"delivered" or "pending"
- How far delivery got before the answer. See What a 200 means.
- submissionIdstring, starts with sub_
- The receipt ID. FormParcel also writes it into the
_submission_idcolumn (column A) of the lead’s Sheet row, so you can find the row from the receipt.
Which answer you get
A browser that submits a plain HTML form gets a page or a redirect. Everything else gets JSON, for success and for refusals alike.
| Request | Status | Body |
|---|---|---|
| fetch, XHR, curl or a server; the lead is accepted. A post without the bot check gets the same answer and waits in Spam | 200 | JSON with accepted, deliveryStatus and submissionId |
| A browser form post with a trusted _next or _redirect | 303 | Empty. Location is your thank-you page. |
| A browser form post with no trusted redirect | 200 | A short page headed "Your message was sent". No receipt ID is shown to the visitor. |
| A script request with the trap field filled | 204 | Empty. Nothing is stored and there is no receipt. |
A request counts as a browser form post only when it accepts text/html, its Sec-Fetch-Mode is missing or navigate, and it did not ask for JSON.
Status and error codes
A refusal stores nothing and makes no receipt. The JSON body has code, error and "success": false; refusals marked “No code” leave code out. Each code links to its entry further down this page.
| Status | When it happens | Code | Retry |
|---|---|---|---|
| Fix the request 400 413 415 422 | |||
| 400 | The JSON cannot be parsed | INVALID_JSON | No |
| 400 | The body is malformed, or the JSON is not a key-value object | INVALID_BODY | No |
| 400 | A top-level JSON key appears twice | DUPLICATE_FIELD | No |
| 400 | More than 50 fields | TOO_MANY_FIELDS | No |
| 400 | A field name is over 64 characters | FIELD_NAME_TOO_LONG | No |
| 400 | A field value is over 4,096 characters | FIELD_VALUE_TOO_LONG | No |
| 400 | JSON nested deeper than 4 levels | PAYLOAD_TOO_DEEP | No |
| 400 | A number that is not finite, such as 1e400 | NON_FINITE_NUMBER | No |
| 400 | A multipart body contains a file | FILE_UPLOAD_NOT_SUPPORTED | No |
| 400 | No field holds readable content | EMPTY_SUBMISSION | No |
| 413 | The body is over 16 KB | PAYLOAD_TOO_LARGE | No |
| 415 | Not form-encoded, multipart or JSON | UNSUPPORTED_MEDIA_TYPE | No |
| 415 | A JSON or multipart body that is not UTF-8 | UNSUPPORTED_CHARSET | No |
| 422 | A field named like a password, one-time code or card detail | PROHIBITED_FIELD | No |
| Form settings 400 403 404 | |||
| 400 | The form has no enabled destination yet | No code: Form not ready | No |
| 403 | The form is paused | No code: Form paused | No |
| 403 | The page is not on the form's allowed origins | No code: Origin not allowed | No |
| 404 | No form has this ID | No code: Form not found | No |
| Spam check 403 | |||
| 403 | Turnstile is on and the token did not pass | SPAM_CHECK_FAILED | With a fresh token |
| Slow down 429 | |||
| 429 | Too many requests from one client, across all forms | CLIENT_RATE_LIMITED | After Retry-After |
| 429 | Too many requests from one client to this form | FORM_RATE_LIMITED | After Retry-After |
| 429 | One client's hourly limit in the workspace | CLIENT_HOURLY_LIMIT | After Retry-After |
| 429 | The form's hourly cap on accepted leads | FORM_HOURLY_LIMIT | After Retry-After |
| 429 | The workspace's daily cap, on a busy form | WORKSPACE_DAILY_LIMIT | After Retry-After |
| Plan limit 429 | |||
| 429 | The submission would be held as spam, and the workspace's Spam folder is full for the month. Nothing is stored and there is no receipt. | SPAM_FOLDER_FULL | Not this month as it is |
| 429 | The workspace has used three times its monthly leads. Nothing is stored and there is no receipt. | PLAN_LIMIT_REACHED | Not this month |
| Our side 500 503 | |||
| 500 | The lead could not be stored | No code: Lead not saved | Once |
| 503 | The form lookup failed. Sends Retry-After: 5. | SERVICE_UNAVAILABLE | After 5 s |
| Wrong method 405 | |||
| 405 | A GET or HEAD request; the answer carries Allow: POST, OPTIONS. Other methods (PUT, PATCH, DELETE) get 405 with an empty body and no Allow header. | No code: Method not allowed | Use POST |
error text is written for people and can change. Branch on the HTTP status first, then on code.{
"success": false,
"error": "Rate limit exceeded. Please try again later.",
"code": "FORM_RATE_LIMITED"
}When to retry
- 200: never send the lead again, whatever
deliveryStatussays. It is stored; a second post makes a second lead with its own receipt ID. - 429: wait the seconds in
Retry-After, then try once more. Not forPLAN_LIMIT_REACHED, which has noRetry-After. - 500 or 503: try once more. A 503 asks you to wait 5 seconds.
- 403
SPAM_CHECK_FAILED: ask the visitor to complete the spam check, then send it with the fresh token. - Any other 4xx: do not retry. Fix the request or the form’s settings.
Every refusal
One entry for each refusal, with what the visitor sees when a browser form post is refused. The anchor of each entry is the code in lower case with dashes, or the name shown for a refusal that sends no code.
Fix the request400 413 415 422
400INVALID_JSON
- When
- The JSON cannot be parsed.
- Retry
- No. The same body fails the same way.
- Visitor
- A browser form post shows "Your message could not be sent".
- What to do
- Send valid JSON, or send the form as a form post.
400INVALID_BODY
- When
- The body is malformed, or the JSON is not a key-value object.
- Retry
- No. The same body fails the same way.
- Visitor
- A browser form post shows "Your message could not be sent".
- What to do
- Send a form post, or a JSON object of field names and values. An array or a bare value is refused.
400DUPLICATE_FIELD
- When
- A top-level JSON key appears twice.
- Retry
- No. The same body fails the same way.
- Visitor
- A browser form post shows "Your message could not be sent".
- What to do
- Send each top-level key once.
400TOO_MANY_FIELDS
- When
- More than 50 fields.
- Retry
- No. The same body fails the same way.
- Visitor
- A browser form post shows "Your message could not be sent".
- What to do
- Send at most 50 fields.
400FIELD_NAME_TOO_LONG
- When
- A field name is over 64 characters.
- Retry
- No. The same body fails the same way.
- Visitor
- A browser form post shows "Your message could not be sent".
- What to do
- Keep each field name to 64 characters or fewer.
400FIELD_VALUE_TOO_LONG
- When
- A field value is over 4,096 characters.
- Retry
- No. The same body fails the same way.
- Visitor
- A browser form post shows "Your message could not be sent".
- What to do
- Keep each value to 4,096 characters or fewer.
400PAYLOAD_TOO_DEEP
- When
- JSON nested deeper than 4 levels.
- Retry
- No. The same body fails the same way.
- Visitor
- A browser form post shows "Your message could not be sent".
- What to do
- Flatten the JSON to at most 4 levels in total.
400NON_FINITE_NUMBER
- When
- A number that is not finite, such as 1e400.
- Retry
- No. The same body fails the same way.
- Visitor
- A browser form post shows "Your message could not be sent".
- What to do
- Send a finite number, or send the value as text.
400FILE_UPLOAD_NOT_SUPPORTED
- When
- A multipart body contains a file.
- Retry
- No. The same body fails the same way.
- Visitor
- A browser form post shows "Your message could not be sent".
- What to do
- Take the file input out of the form. FormParcel does not take file uploads.
400EMPTY_SUBMISSION
- When
- No field holds readable content.
- Retry
- No. Nothing is stored and there is no receipt.
- Visitor
- A browser form post shows "Your message was empty".
- What to do
- Make sure at least one field has a value and every field has a name attribute. A field without a name is not sent.
413PAYLOAD_TOO_LARGE
- When
- The body is over 16 KB.
- Retry
- No. The same body fails the same way.
- Visitor
- A browser form post shows "Your message is too long".
- What to do
- Send 16 KB or less.
415UNSUPPORTED_MEDIA_TYPE
- When
- Not form-encoded, multipart or JSON.
- Retry
- No. The same body fails the same way.
- Visitor
- A browser form post shows "Your message could not be sent".
- What to do
- Send the body as application/x-www-form-urlencoded, multipart/form-data or application/json.
415UNSUPPORTED_CHARSET
- When
- A JSON or multipart body that is not UTF-8.
- Retry
- No. The same body fails the same way.
- Visitor
- A browser form post shows "Your message could not be sent".
- What to do
- Send the body as UTF-8.
422PROHIBITED_FIELD
- When
- A field named like a password, one-time code or card detail.
- Retry
- No. Nothing is stored and there is no receipt.
- Visitor
- A browser form post shows "This form cannot take that information".
- What to do
- Take that field out of the form. FormParcel does not accept passwords, one-time codes or card details.
Form settings400 403 404
400Form not readyNo code
- When
- The form has no enabled destination yet.
- Retry
- No. The owner finishes the form's setup first.
- Visitor
- A browser form post shows "This form is not ready yet".
- What to do
- The owner connects a destination to the form in the dashboard. A form accepts leads once it has somewhere to deliver them.
403Form pausedNo code
- When
- The form is paused.
- Retry
- No. The owner resumes the form first.
- Visitor
- A browser form post shows "This form is not accepting messages right now".
- What to do
- The owner resumes the form in the dashboard.
403Origin not allowedNo code
- When
- The page is not on the form's allowed origins.
- Retry
- No. Post from an allowed page, or add the site to the form's allowed origins.
- Visitor
- A browser form post shows "This form cannot be used from here".
- What to do
- Add the page's site to the form's allowed origins, or post from a page that is already on the list.
404Form not foundNo code
- When
- No form has this ID.
- Retry
- No. Check the address.
- Visitor
- A browser form post shows "We could not find this form".
- What to do
- Copy the form address again from the dashboard.
Spam check403
403SPAM_CHECK_FAILED
- When
- Turnstile is on and the token did not pass.
- Retry
- Yes, once the visitor passes the check, with the fresh token the widget gives.
- Visitor
- A browser form post shows "Please complete the spam check and try again".
- What to do
- Ask the visitor to complete the check, then send the post again with the new token.
Slow down429
429CLIENT_RATE_LIMITED
- When
- Too many requests from one client, across all forms.
- Retry
- Wait the seconds in Retry-After, then send once more.
- Visitor
- A browser form post shows "Please try again in a moment".
- What to do
- Wait the seconds in Retry-After, then send once more.
429FORM_RATE_LIMITED
- When
- Too many requests from one client to this form.
- Retry
- Wait the seconds in Retry-After, then send once more.
- Visitor
- A browser form post shows "Please try again in a moment".
- What to do
- Wait the seconds in Retry-After, then send once more.
429CLIENT_HOURLY_LIMIT
- When
- One client's hourly limit in the workspace.
- Retry
- Wait the seconds in Retry-After, then send once more.
- Visitor
- A browser form post shows "Please try again in a moment".
- What to do
- Wait the seconds in Retry-After, then send once more.
429FORM_HOURLY_LIMIT
- When
- The form's hourly cap on accepted leads.
- Retry
- Wait the seconds in Retry-After, then send once more.
- Visitor
- A browser form post shows "Please try again in a moment".
- What to do
- Wait the seconds in Retry-After, then send once more.
429WORKSPACE_DAILY_LIMIT
- When
- The workspace's daily cap, on a busy form.
- Retry
- Wait the seconds in Retry-After, then send once more.
- Visitor
- A browser form post shows "Please try again in a moment".
- What to do
- Wait the seconds in Retry-After, then send once more.
Plan limit429
429SPAM_FOLDER_FULL
- When
- The submission would be held as spam, and the workspace's Spam folder is full for the month. Nothing is stored and there is no receipt.
- Retry
- Not as it is. A submission that passes every check (with the bot check, from a new sender, with new content) is still accepted.
- Visitor
- A browser form post shows "This form cannot take more messages this month".
- What to do
- Add the bot check script to the form's pages. The owner reviews the Spam folder; it empties at the next UTC month.
429PLAN_LIMIT_REACHED
- When
- The workspace has used three times its monthly leads. Nothing is stored and there is no receipt.
- Retry
- Not this month. There is no Retry-After header.
- Visitor
- A browser form post shows "This form cannot take more messages this month".
- What to do
- The owner upgrades the plan, or waits for the next UTC month.
Our side500 503
500Lead not savedNo code
- When
- The lead could not be stored.
- Retry
- Yes, once. The lead was not accepted.
- Visitor
- A browser form post shows "Something went wrong on our side".
- What to do
- Send the post again once. If it keeps failing, tell us the time of the request.
503SERVICE_UNAVAILABLE
- When
- The form lookup failed. Sends Retry-After: 5.
- Retry
- Yes, after 5 seconds. The lead was not accepted.
- Visitor
- A browser form post shows "Something went wrong on our side".
- What to do
- Send the post again after 5 seconds.
Wrong method405
405Method not allowedNo code
- When
- A GET or HEAD request; the answer carries Allow: POST, OPTIONS. Other methods (PUT, PATCH, DELETE) get 405 with an empty body and no Allow header.
- Retry
- Send a POST instead.
- Visitor
- A browser form post shows "This is a form address".
- What to do
- Send a POST. OPTIONS answers the CORS preflight.