# Como funciona

> Cada verificação pela qual um envio passa, em ordem, e o que cada uma pode retornar.

Cada envio para `/f/<formId>` passa pelo mesmo pipeline. As verificações baratas rodam primeiro, então um flood ou um formulário desconhecido custa quase nada. A primeira verificação que falhar define a resposta.

O pipeline, em ordem:

1. Proteção contra flood por IP: no máximo 600 envios por minuto de um mesmo IP, somando todos os formulários, antes de o formulário ser buscado. Falha com `429 rate_limited`.
2. Busca do formulário: formulários desconhecidos, excluídos e desativados falham com `404 not_found`.
3. Limites de taxa do formulário: o preset do formulário, contado por IP de visitante e por formulário. Falha com `429 rate_limited`.
4. Formulários pausados falham com `403 form_paused`.
5. Parsing do corpo: urlencoded, multipart ou JSON, com no máximo 256 KB. Falha com `415`, `400 invalid_body`, `413 payload_too_large`, `422 too_deep` ou `422 files_not_supported`.
6. Chave de API, quando um header `Authorization` é enviado. Falha com `403 forbidden` ou `403 origin_not_allowed`.
7. Domínios permitidos: um envio de outro site é armazenado como spam, ou falha com `403 origin_not_allowed`.
8. Verificação humana: falha com `403 challenge_required` ou `403 captcha_failed`. Envios de formulário pelo navegador recebem uma página de verificação.
9. Validação de campos: falha com `422 validation_failed`.
10. Pontuação de spam: uma pontuação de 5 ou mais é armazenada como spam, mas ainda recebe resposta de sucesso.
11. Idempotência: uma chave repetida repete a primeira resposta, ou falha com `409` ou `422`.
12. Uso mensal: muito acima do limite falha com `429 quota_exceeded`.
13. Armazenamento: `201` com o id do envio, ou um redirecionamento `303` para envios pelo navegador. Em seguida vêm os webhooks, os e-mails de notificação e a atualização ao vivo do painel.

## O que cada etapa faz

### Limites de taxa antes de tudo

Os limites de taxa rodam antes de o corpo ser lido. A proteção contra flood (600 por minuto por IP) roda antes até da busca do formulário, então um flood nunca chega ao banco de dados. As regras do próprio formulário rodam logo depois da busca. Requisições rejeitadas não consomem a cota. Os números exatos estão em [Limites de taxa](https://ikiform.com/pt-br/docs/rate-limits.md).

### Parsing

O corpo é lido como urlencoded, multipart ou JSON. O texto é decodificado como UTF-8 e normalizado para NFC, CRLF vira LF e caracteres de controle são removidos. Nomes que começam com `_` são instruções reservadas, como `_redirect` e `_subject`, e nunca são armazenados como respostas. Veja [Formulários HTML](https://ikiform.com/pt-br/docs/html.md#reserved-fields).

### Quem enviou

Um header `Authorization: Bearer` é opcional. Uma chave secreta (`ik_sk_`) com o escopo `submissions:write` pula a verificação de domínios permitidos e a verificação humana do Ikiform. Uma chave publicável (`ik_pub_`) só funciona a partir dos domínios listados na chave. Sem chave, o envio é avaliado pelo seu `Origin`.

### Spam

Spam nunca é um erro. Um envio que falha na política de domínios permitidos no modo spam, ou que pontua 5 ou mais, é armazenado com status `spam` e recebe a mesma resposta de sucesso de um envio real, então os bots não aprendem nada. Spam não dispara webhooks nem e-mails e não conta no uso. Veja [Proteção contra spam](https://ikiform.com/pt-br/docs/spam.md).

### Armazenar e entregar

O envio, suas entregas de webhook e seu e-mail de notificação são gravados em um único lote no banco de dados e depois entregues a uma fila. A entrega de webhooks e os e-mails nunca deixam a resposta mais lenta, e um envio nunca é armazenado sem as suas entregas.

## JSON ou redirecionamento

O mesmo endpoint responde navegadores com páginas e código com JSON. O Ikiform decide por requisição:

| Requisição | Resposta |
| --- | --- |
| `Accept` inclui `application/json` | JSON |
| O corpo é JSON | JSON |
| `Sec-Fetch-Mode: navigate` (um envio normal de formulário) | Redirecionamento ou página hospedada |
| Qualquer outro `Sec-Fetch-Mode`, como `cors` vindo de `fetch` | JSON |
| Sem `Sec-Fetch-Mode`, e `Accept` inclui `text/html` | Redirecionamento ou página hospedada |
| Qualquer outra coisa, como curl | JSON |

No modo JSON, sucesso é `201 { "ok": true, "id": "sub_..." }`. No modo página, sucesso é um redirecionamento `303`, e os erros mostram uma página de erro hospedada que lista os problemas de cada campo pelo rótulo.

## Depois que um envio é armazenado

| O quê | Quando | Detalhes |
| --- | --- | --- |
| Webhooks | Segundos depois, com novas tentativas por cerca de 3 dias | [Webhooks](https://ikiform.com/pt-br/docs/webhooks.md) |
| E-mail de notificação | Segundos depois, se as notificações estiverem ativas no formulário | Limitado a 50 e-mails por formulário por hora (10 para workspaces com menos de 7 dias), depois um resumo por hora |
| Painel | Na hora, ao vivo | Spam aparece no filtro de spam |
| API REST | Na hora | [API REST](https://ikiform.com/pt-br/docs/api.md) |

> Formulários cujos envios contêm campos com nomes de senha, cartão ou frase-semente são sinalizados, e seus e-mails de notificação ficam retidos para revisão. Não colete credenciais com um backend de formulário.

## Ids

| Id | Formato | Observações |
| --- | --- | --- |
| Formulário | `frm_xxxxxxxxxxxxxxxx` | `frm_` mais 16 caracteres aleatórios. Público: ele aparece na URL do action do seu formulário. |
| Envio | `sub_01k7v2c9t3e8m5q4x6z0a1b2c3` | `sub_` mais 26 caracteres, ordenados por tempo. |
| Entrega de webhook | `dlv_...` | Enviado como `webhook-id`; continua o mesmo entre as novas tentativas. |
| Requisição | `req_...` | Toda resposta tem um header `X-Request-Id`. Informe-o quando entrar em contato com o suporte. |

**201** (`Sucesso em JSON`)

```json
{ "ok": true, "id": "sub_01k7v2c9t3e8m5q4x6z0a1b2c3" }
```

**303** (`Sucesso no navegador`)

```http
HTTP/1.1 303 See Other
Location: https://example.com/thanks
X-Request-Id: req_01k7v2c9t3e8m5q4x6z0a1b2c3
```
