Webhooks (JSON)
Uma regra de Webhook envia (POST) cada resposta correspondente como JSON para uma URL que você informa. Use-a para alimentar um CRM, uma ferramenta de planilhas, o seu próprio servidor ou uma plataforma de automação como Zapier, Make ou n8n.
Crie uma regra de webhook
- Clique em + Nova regra e escolha Webhook
- Quando: mantenha Toda resposta, ou escolha Somente após aprovação / Quando rejeitada e defina um aprovador. Adicione condições em Somente se para enviar apenas as respostas correspondentes
- Para: cole a URL do seu destino (somente HTTPS). Não há etapa Mensagem: a regra envia um payload JSON fixo. Ver payload, abaixo da URL, mostra o payload com as perguntas do seu formulário, pronto para copiar
- Clique em Criar regra e copie o segredo de assinatura exibido uma única vez (veja abaixo)

Enviar teste envia um payload de exemplo, assinado, ao destino e mostra o status HTTP retornado. As URLs salvas são armazenadas criptografadas e exibidas mascaradas; clique em Substituir para colar uma nova.
O payload
Cada requisição é um POST, Content-Type: application/json, com este corpo:
{
"version": 1,
"event": "submitted",
"form": { "id": "1AbC...", "name": "Workshop sign-up" },
"response": {
"id": "a3f1...",
"submittedAt": "2026-01-31T09:30:00.000Z",
"respondentEmail": "respondent@example.com",
"answers": [
{ "questionId": "q1", "title": "Your name", "value": "Ada Lovelace" },
{ "questionId": "q3", "title": "Department", "value": "Ops" }
]
},
"rule": { "id": "rule id", "name": "Zapier: new lead" }
}
eventé um desubmitted,approved,rejected; ele também vai no cabeçalhoX-Skyfield-Eventresponse.respondentEmailénull, a menos que o formulário colete endereços de e-mailanswers[].valueé sempre uma string; respostas de caixas de seleção são unidas com,rule.iderule.nameidentificam a regra que disparou;nameénullquando a regra não tem nome- Em
approvederejected, é incluído umapproval: { "decision": "approved", "decidedBy": "Dana" }extra.decidedByé o nome que o aprovador digitou na página de aprovação; se não houver, o e-mail do aprovador, ounull
version permanece 1 enquanto o formato acima for estável. Novos campos podem ser adicionados; nenhum é removido ou renomeado sem uma mudança de versão.
Verificando a assinatura
Toda requisição traz um cabeçalho X-Skyfield-Signature: sha256=<hex>, o HMAC-SHA256 do corpo bruto da requisição com a chave sendo o segredo de assinatura da regra. Verifique-o antes de confiar em uma requisição.

O segredo (whsec_...) é exibido uma vez, logo depois do salvamento que dá à regra sua primeira URL de webhook. Copie-o nesse momento; ele não pode ser exibido de novo. Substituir a URL depois mantém o mesmo segredo. Se você o perder, abra a regra, clique em Novo segredo de assinatura e salve: o novo segredo é exibido uma vez e o antigo para de funcionar imediatamente.
Calcule o HMAC sobre os bytes do corpo exatamente como recebidos. Fazer o parse e reserializar o JSON antes altera os espaços em branco e quebra a comparação.
Node.js
import { createHmac, timingSafeEqual } from 'node:crypto'
// rawBody: string or Buffer of the request body, before any JSON parsing
function verify(rawBody, header, secret) {
const expected = 'sha256=' + createHmac('sha256', secret).update(rawBody).digest('hex')
const a = Buffer.from(expected)
const b = Buffer.from(header ?? '')
return a.length === b.length && timingSafeEqual(a, b)
}
// Express example: use express.raw() so req.body is the untouched bytes
app.post('/hook', express.raw({ type: 'application/json' }), (req, res) => {
if (!verify(req.body, req.get('X-Skyfield-Signature'), process.env.SKYFIELD_SECRET))
return res.status(401).end()
const payload = JSON.parse(req.body)
res.status(200).end()
})
Python
import hmac, hashlib
def verify(raw_body: bytes, header: str, secret: str) -> bool:
digest = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest("sha256=" + digest, header or "")
# Flask example
@app.post("/hook")
def hook():
if not verify(request.get_data(), request.headers.get("X-Skyfield-Signature"), SECRET):
return "", 401
payload = request.get_json()
return "", 200
Responda com qualquer status 2xx. O corpo é ignorado.
Zapier, Make, n8n
Os três aceitam um webhook JSON genérico:
- Zapier: gatilho Webhooks by Zapier, evento Catch Hook (ou Catch Raw Hook para verificar a assinatura por conta própria). Cole na regra a URL que o Zapier mostra
- Make: adicione um módulo Webhooks, Custom webhook, e copie a URL dele
- n8n: adicione um nó Webhook, método POST, e use a URL de produção dele
Envie um teste pela regra e depois mapeie os campos de response.answers na plataforma. O payload de exemplo usa respostas fictícias, então todos os campos estão presentes.
Entrega e limites
- O destino precisa estar acessível na internet pública via HTTPS. Endereços privados e locais são rejeitados ao salvar
- Redirecionamentos não são seguidos: use a URL final
- O destino tem 5 segundos para responder. Um tempo esgotado ou uma resposta 5xx é repetido uma vez
- Uma resposta 404 ou 410 significa que o destino não existe mais: a regra é pausada e você recebe um e-mail. Cole uma nova URL na regra para retomar
- A página Histórico lista cada entrega com o status HTTP que o seu destino retornou
- Uma regra de webhook pausada ou desativada não bloqueia outras regras do formulário
Bom saber
- Uma regra de webhook respeita o Enviar quando, então um destino pode receber uma decisão de aprovação em vez de todo envio. Veja Enviar Quando
- Para enviar apenas respostas verificadas, defina o Enviar quando da regra como Somente após aprovação e escolha um aprovador. Veja Aprovação. O payload passa a trazer
approval.decision - Alterar canal… move uma regra de webhook para E-mail ou para um canal de chat; informe o novo destino ali. Ao voltar para Webhook, a URL precisa ser colada de novo
- As regras de webhook precisam de uma licença ativa. O período de teste gratuito conta. Veja o que precisa de licença
