# Solución de problemas

> Soluciones para errores de CORS, orígenes que no coinciden, challenge_required, errores 429, campos desconocidos y errores de cuota.

Empieza por la respuesta. Cada respuesta de Ikiform tiene una cabecera `X-Request-Id` y, en los errores, un `error.code` estable. Este curl muestra ambos, desde el mismo origen desde el que enviaría tu sitio:

`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"}'
```

¿Ves errores `5xx` o timeouts del propio Ikiform? Revisa primero [status.ikiform.com](https://status.ikiform.com) por si hay incidentes en curso.

## El navegador dice que CORS bloqueó la petición

El endpoint de envíos permite cualquier origen, así que un fallo de CORS real suele significar que la petición nunca llegó a Ikiform, o que fue a una URL equivocada.

- Comprueba que la URL es `https://ikiform.com/f/<formId>` con el id `frm_` completo, por ejemplo `frm_xxxxxxxxxxxxxxxx`, y sin ruta adicional al final.
- Estás llamando a `/api/v1` desde un navegador. La API REST rechaza los navegadores por diseño; llámala desde tu servidor.
- Un bloqueador de anuncios, una extensión de privacidad o un proxy corporativo bloqueó la petición. Prueba en una ventana privada sin extensiones.
- La propia `Content-Security-Policy` de tu sitio la bloquea. Añade `https://ikiform.com` a `connect-src`, y a `form-action` para los envíos HTML.

Comprueba el preflight directamente; debería responder `204` y devolver tu origen:

`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"
```

## Los envíos llegan a spam con origin_mismatch

El formulario tiene dominios permitidos y el envío vino de otro lugar. El panel muestra `origin_mismatch` entre los motivos de spam.

- Añade todos los dominios desde los que se sirve el formulario, incluidos `www`, staging y los dominios de vista previa. Los subdominios de un dominio de la lista ya coinciden.
- Añade `localhost` mientras desarrollas en local.
- Los envíos desde tu propio servidor no llevan `Origin`. Envía una clave secreta, que se salta la comprobación.
- Si eliges **Reject** en lugar de **Mark as spam**, esos mismos envíos reciben `403 origin_not_allowed`.

## 403 challenge_required

La verificación antispam del formulario está en **Ikiform** y el envío no tenía token de Turnstile.

1. Código del navegador: llama a `challenge(formId)` del SDK justo antes de cada envío y pasa el token a `submit` como `turnstileToken`.
2. Código del servidor: envía `Authorization: Bearer ik_sk_...` con una clave secreta; las claves secretas se saltan la verificación.
3. Los envíos HTML nunca ven este código; reciben la página de verificación. Si lo ves desde un envío de formulario, algo está enviando `Accept: application/json`.
4. ¿Pruebas con curl? Desactiva la verificación en un formulario de prueba, o usa una clave secreta.

`403 captcha_failed` significa que se envió un token pero no pasó la verificación. Los tokens son de un solo uso y caducan a los 300 segundos, así que obtén uno nuevo en cada intento.

## 429 rate_limited

- Lee `Retry-After` y espera esos segundos.
- ¿Pruebas a mano? El preset Standard permite 5 envíos por minuto desde una IP, y 3 en 10 segundos. Cambia el formulario de prueba a Relaxed.
- ¿Envías desde tu servidor en nombre de cada visitante? Todos los envíos comparten la IP de tu servidor. Envía desde el navegador, o elige Relaxed o Custom.
- Muchas personas detrás de la red de una oficina o de un evento también comparten IP. Relaxed permite 20 por minuto.

## 422 con Unknown field

El formulario tiene campos definidos y el envío incluyó un nombre que no está en la definición. `error.fields` lo indica, por ejemplo `{ "website": ["Unknown field \"website\""] }`.

- Añade el campo a la definición o quita el input.
- Cambia el nombre del input para que empiece con `_` si solo es una marca para ti; los nombres reservados se descartan, no se validan.
- Comprueba que el nombre del honeypot coincide con el ajuste **Honeypot field** del formulario.
- Los ids de campo van en snake_case en minúsculas: `firstName` en tu markup no es lo mismo que `first_name` en la definición.

## 429 quota_exceeded

El espacio de trabajo recibió este mes el doble de su límite mensual y deja de aceptar envíos hasta que empiece el mes siguiente o mejore su plan. Consulta [Uso mensual](https://ikiform.com/es/docs/limits.md#monthly-usage).

## Los envíos no aparecen

- Mira en el filtro de spam. El spam recibe una respuesta de éxito normal, así que el visitante no nota la diferencia.
- Comprueba que el formulario no está en pausa y que el id de tu `action` coincide con el del panel.
- Un envío del navegador que muestra la página de error de Ikiform fue rechazado; la página indica el motivo.

## Los webhooks fallan

- `no_matching_signature`: verifica contra el cuerpo sin procesar, antes de cualquier análisis del JSON, y comprueba que copiaste el secreto `whsec_` correcto. Pega una entrega en el [verificador](https://ikiform.com/es/docs/webhooks.md#verifier).
- `timestamp_too_old`: el reloj de tu servidor está desajustado, o estás repitiendo una entrega antigua.
- Timeouts: responde en menos de 15 segundos y haz el trabajo lento después.
- Las redirecciones no se siguen. Usa la URL final, incluida la barra final que espera tu framework.
- El endpoint se desactivó tras 5 días de fallos o un `410`. Arréglalo y vuelve a activarlo desde la página del endpoint.
