# Troubleshooting

> Fixes for CORS errors, origin mismatches, challenge_required, 429s, unknown fields and quota errors.

Start with the response. Every answer from Ikiform has an `X-Request-Id` header and, for errors, a stable `error.code`. This curl shows both, from the same origin your site would send:

`Terminal`:

```bash
curl -i https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Origin: https://example.com" \
  -d '{"email":"ada@example.com"}'
```

Seeing `5xx` errors or timeouts from Ikiform itself? Check [status.ikiform.com](https://status.ikiform.com) for current incidents first.

## The browser says CORS blocked the request

The submission endpoint allows every origin, so a real CORS failure usually means the request never reached Ikiform, or went to the wrong URL.

- Check the URL is `https://ikiform.com/f/<formId>` with the full `frm_` id, for example `frm_xxxxxxxxxxxxxxxx`, and no trailing path.
- You are calling `/api/v1` from a browser. The REST API refuses browsers by design; call it from your server.
- An ad blocker, privacy extension or corporate proxy blocked the request. Try a private window without extensions.
- Your site's own `Content-Security-Policy` blocks it. Add `https://ikiform.com` to `connect-src`, and to `form-action` for plain HTML posts.

Check the preflight directly; it should answer `204` with your origin echoed back:

`Terminal`:

```bash
curl -i -X OPTIONS https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx \
  -H "Origin: https://example.com" \
  -H "Access-Control-Request-Method: POST" \
  -H "Access-Control-Request-Headers: content-type"
```

## Submissions land in spam with origin_mismatch

The form has allowed domains and the post came from somewhere else. The dashboard shows `origin_mismatch` among the spam reasons.

- Add every domain the form is served from, including `www`, staging and preview domains. Subdomains of a listed domain already match.
- Add `localhost` while developing locally.
- Posts from your own server carry no `Origin`. Send a secret key, which skips the check.
- With **Reject** chosen instead of **Mark as spam**, the same posts get `403 origin_not_allowed`.

## 403 challenge_required

The form's spam check is set to **Ikiform** and the post had no Turnstile token.

1. Browser code: call `challenge(formId)` from the SDK right before each submit, and pass the token to `submit` as `turnstileToken`.
2. Server code: send `Authorization: Bearer ik_sk_...` with a secret key; secret keys skip the check.
3. Plain HTML posts never see this code; they get the check page instead. If you see it from a form post, something is sending `Accept: application/json`.
4. Testing with curl? Turn the check off for a test form, or use a secret key.

`403 captcha_failed` means a token was sent but didn't verify. Tokens are single use and expire after 300 seconds, so get a new one for every attempt.

## 429 rate_limited

- Read `Retry-After` and wait that many seconds.
- Testing by hand? The Standard preset allows 5 posts a minute from one IP, and 3 in 10 seconds. Switch a test form to Relaxed.
- Posting from your server for every visitor? All posts share your server's IP. Post from the browser, or choose Relaxed or Custom.
- Many people behind one office or event network share an IP too. Relaxed allows 20 a minute.

## 422 with Unknown field

The form has fields defined and the post sent a name that isn't in the definition. `error.fields` names it, for example `{ "website": ["Unknown field \"website\""] }`.

- Add the field to the definition, or remove the input.
- Rename the input to start with `_` if it is only a marker for you; reserved names are dropped, not validated.
- Check that the honeypot name matches the form's **Honeypot field** setting.
- Field ids are lowercase snake_case: `firstName` in your markup is not the same as `first_name` in the definition.

## 429 quota_exceeded

The workspace received 2 times its monthly limit this month and stops accepting submissions until the next month starts or the workspace upgrades. See [Monthly usage](https://ikiform.com/docs/limits.md#monthly-usage).

## Submissions don't show up

- Look under the spam filter. Spam gets a normal success response, so the visitor can't tell.
- Check the form isn't paused, and that the id in your `action` matches the dashboard.
- A browser post that shows Ikiform's error page was rejected; the page lists the reason.

## Webhooks fail

- `no_matching_signature`: verify against the raw body, before any JSON parsing, and check you copied the right `whsec_` secret. Paste a delivery into the [verifier](https://ikiform.com/docs/webhooks.md#verifier).
- `timestamp_too_old`: your server clock is off, or you are replaying an old delivery.
- Timeouts: answer within 15 seconds and do slow work afterwards.
- Redirects aren't followed. Use the final URL, including the trailing slash your framework expects.
- The endpoint was disabled after 5 days of failures or a `410`. Fix it, then turn it back on from the endpoint page.
