ID do formulário

JavaScript e fetch

O endpoint de envio em detalhe: formatos de corpo, headers, CORS, respostas e idempotência.

Qualquer código que consiga fazer uma requisição HTTP pode enviar para o Ikiform. Envie JSON, FormData ou dados urlencoded para https://ikiform.com/f/<formId> e leia uma resposta JSON. O SDK encapsula isso em uma função, mas é opcional. Para uma configuração passo a passo em uma stack específica, veja Guias por plataforma.

Com fetch

const response = await fetch("https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx", {
  method: "POST",
  headers: { "Content-Type": "application/json", Accept: "application/json" },
  body: JSON.stringify({
    name: "Ada Lovelace",
    email: "ada@example.com",
    message: "Hello",
  }),
});

const result = await response.json();
if (!result.ok) console.error(result.error.code, result.error.fields);

Experimente

ID do formulário
Campos
Corpo
Chave de idempotência
curl https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx \
  -H "Content-Type: application/json" \
  -d '{"name":"Ada Lovelace","email":"ada@example.com","message":"Hello from the Ikiform docs."}'

Digite o ID do seu formulário para enviar isto como uma requisição real.

Endpoints

MétodoCaminhoO que faz
POST/f/<formId>Cria um envio
OPTIONS/f/<formId>Preflight de CORS, sempre 204
GET/f/<formId>/schemaA definição pública de campos do formulário, veja shadcn/ui
GET/f/<formId>/thanksA página de agradecimento hospedada
GET/f/<formId>/challengeO frame de verificação humana do Ikiform, usado pelo SDK

Abrir o próprio /f/<formId> em uma aba do navegador é um GET, que responde 404 not_found. Isso é esperado: o endpoint só aceita envios.

Formatos de corpo

Content-TypeFormatoObservações
application/json e tipos +jsonUm objeto JSONOs valores podem ser strings, números, booleanos, arrays e objetos, com no máximo 3 níveis de aninhamento contando o objeto de topo
application/x-www-form-urlencodedPares de nome e valorNomes repetidos e name[] viram arrays
multipart/form-dataPares de nome e valorIgual a urlencoded; arquivos de verdade são recusados
Qualquer outro415 unsupported_media_type

O corpo precisa ser UTF-8. Um charset diferente de utf-8 recebe 415 unsupported_charset, e bytes que não são UTF-8 válido recebem o mesmo código. Um array JSON ou um corpo malformado recebe 400 invalid_body.

Headers

Headers da requisição

HeaderObrigatórioEfeito
Content-TypeSimEscolhe o parser do corpo, veja acima
AcceptNãoapplication/json força uma resposta JSON, veja JSON ou redirecionamento
Idempotency-KeyNãoTorna as novas tentativas seguras, até 255 caracteres, veja Idempotência
AuthorizationNãoBearer ik_sk_... ou Bearer ik_pub_..., veja A partir de um servidor
Origin, RefererEnviados pelos navegadoresComparados aos domínios permitidos do formulário

Headers da resposta

HeaderQuandoValor
X-Request-IdToda respostareq_..., repetido como request_id nos corpos de erro
Retry-After429Segundos até o próximo envio ser permitido
Location303 sucesso no navegadorSeu redirecionamento ou a página de agradecimento hospedada
Access-Control-Allow-OriginQuando a requisição tem um OriginA própria origem da requisição
Access-Control-Expose-HeadersCom CORSX-Request-Id, Retry-After, para o código no navegador conseguir ler os dois
Cache-ControlSucessono-store

CORS

O endpoint de envio aceita envios cross-origin de qualquer site. Preflights sempre dão certo e devolvem a origem da requisição. Nenhum cookie ou credencial é usado, então não é o CORS que protege seu formulário: são os domínios permitidos. Com domínios permitidos definidos, um envio de outro site é armazenado como spam ou recusado, conforme a configuração do formulário. Veja Domínios permitidos.

Preflight
OPTIONS /f/frm_xxxxxxxxxxxxxxxx HTTP/1.1
Origin: https://example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Accept, Idempotency-Key, Authorization
Access-Control-Max-Age: 86400
Vary: Origin
A API REST em /api/v1 é diferente: ela não envia headers de CORS e responde preflights do navegador com 405, então uma chave secreta nunca pode ser usada a partir de uma página web.

Respostas

Sucesso é 201 com o id do novo envio. Os erros usam o mesmo envelope em todo lugar, com erros de campo indexados pelo id do campo quando a validação falha. Todos os códigos estão em Erros.

{ "ok": true, "id": "sub_01k7v2c9t3e8m5q4x6z0a1b2c3" }
Um envio pontuado como spam ainda recebe 201. Spam é armazenado à parte e nunca chega aos seus webhooks nem à sua caixa de entrada.

Idempotência

Envie um header Idempotency-Key, ou um campo _idempotency, para tornar as novas tentativas seguras. As chaves têm até 255 caracteres e valem por formulário durante 24 horas. O header vence quando os dois são enviados.

Nova tentativa comResultado
A mesma chave e os mesmos camposA primeira resposta é repetida. Nenhum segundo envio é criado.
A mesma chave e campos diferentes422 idempotency_mismatch
A mesma chave enquanto a primeira requisição ainda está rodando409 idempotency_in_progress

Requisições que falham antes de o envio ser armazenado, como erros de validação, não guardam a chave, então você pode corrigir os dados e tentar de novo com a mesma chave. Um loop seguro de novas tentativas:

retry.js
const key = crypto.randomUUID();

async function send(attempt = 1) {
  const response = await fetch("https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx", {
    method: "POST",
    headers: { "Content-Type": "application/json", "Idempotency-Key": key },
    body: JSON.stringify({ email: "ada@example.com" }),
  }).catch(() => null);
  if (response && response.status < 500 && response.status !== 429) return response.json();
  if (attempt === 3) throw new Error("Ikiform is unreachable");
  const wait = Number(response?.headers.get("Retry-After")) || attempt * 2;
  await new Promise((resolve) => setTimeout(resolve, wait * 1000));
  return send(attempt + 1);
}

Guias por plataforma

Frameworks

Geradores de sites estáticos

Criadores de sites