Every error response uses the same envelope, so you can handle failures uniformly.
The envelope
json
{
"error": {
"code": "origin_not_allowed",
"message": "Origin https://evil.example is not allowed for this form. Allowed: https://example.com",
"docs_url": "https://lanes.sh/docs/forms/securing-your-endpoints"
}
}Branch on the stable code, not on the human-readable message. Messages are written to be self-correcting: where it helps, they include the value that failed and what was expected, so an agent can often fix the call from the message alone.
Provisioning errors
| Code | Status | Fix |
|---|---|---|
disposable_email | 422 | Use a real, non-disposable recipient address. |
pending_claim_exists | 429 | An unclaimed form for that email already exists. Claim or reuse it. |
Submission errors
| Code | Status | Fix |
|---|---|---|
form_not_found | 404 | Check the form_id in the URL. |
unsupported_content_type | 415 | Set a Content-Type (application/json, form-urlencoded, or multipart). |
files_not_supported | 415 | Remove file parts. Uploads are not supported in v1. |
invalid_body | 400 | Send a JSON object of field values, not an array or scalar. |
missing_required_fields | 422 | The response lists the missing fields. Provide them. |
payload_too_large | 413 | Keep the body under 64 KB. |
submission_rate_limited | 429 | Back off. The limit is 10 per minute per IP. |
unclaimed_submission_cap | 429 | The form hit 25 stored submissions. It must be claimed to accept more. |
Security errors
| Code | Status | Fix |
|---|---|---|
origin_not_allowed | 403 | Add the origin to the form's allowed_origins. |
preflight_origin_required | 400 | The CORS preflight sent no Origin. |
api_key_required | 401 | The form is in api_key mode. Send Authorization: Bearer lfk_.... |
invalid_api_key | 401 | The key is unknown or revoked. Create a new one. |
api_key_limit_reached | 429 | A workspace allows 10 active keys. Revoke an unused one. |
api_key_not_found | 404 | The key id does not belong to this workspace. |
Delivery errors
| Code | Status | Fix |
|---|---|---|
action_not_available | 422 | Webhook and custom (non-Lanes) storage are not live yet. Use email plus Lanes storage. |
State-gate responses (410) are returned when a form is frozen or deleted; see Provisioning.
Next: API reference.