Evento: Resposta de formulário registrada (FORM_RESPONSE_ADDED)
Dispara quando uma resposta de formulário de um candidato é registrada — por exemplo, um questionário de triagem ou um formulário personalizado.
Novo nos webhooks? Veja a visão geral para o conceito (registrar uma vez, receber sempre que a ação ocorre).
Criando o webhook
Registre um webhook para o evento FORM_RESPONSE_ADDED (Criar webhook):
curl -X POST https://api.inhire.app/integrations/webhooks \
-H "Authorization: Bearer SEU_ACCESS_TOKEN" \
-H "X-Tenant: suaempresa" \
-H "Content-Type: application/json" \
-d '{
"name": "Resposta de formulário",
"event": "FORM_RESPONSE_ADDED",
"url": "https://seu-sistema.com/webhooks/inhire/formulario",
"headers": { "Authorization": "Bearer UM_SEGREDO_SEU" }
}'
A partir daí, o InHire chamará a sua URL sempre que este evento ocorrer. Para filtrar quais
ocorrências recebe, adicione rules (ver abaixo).
Payload
{
"tenantId": "suaempresa",
"jobId": "5dfd3a1e-a5c3-4e53-a3f4-cdb4e311d315",
"talentId": "b1c2d3e4-f5a6-7890-bcde-1234567890ab",
"type": "subscription",
"title": "Triagem técnica",
"vendor": "typeform",
"typeformId": "abc123",
"formResponseId": "abc123",
"passed": true,
"correctQuestionsCount": 8,
"autoCorrectionResult": {},
"answers": [
{
"question": {
"id": "Q1abc",
"ref": "anos-experiencia",
"type": "short_text",
"title": "Quantos anos de experiência você tem?"
},
"answer": {
"field": { "id": "Q1abc", "type": "short_text" },
"type": "text",
"text": "5 anos"
}
},
{
"question": {
"id": "Q2def",
"ref": "conhece-sql",
"type": "multiple_choice",
"title": "Você conhece SQL?"
},
"answer": {
"field": { "id": "Q2def", "type": "multiple_choice" },
"type": "choices",
"choices": [
{ "ref": "c1", "label": "Sim", "selected": true, "weight": 10, "correct": true },
{ "ref": "c2", "label": "Não", "selected": false, "weight": 0, "correct": false }
]
}
}
]
}
| Campo | Descrição |
|---|---|
jobId / talentId | Vaga e talento associados à resposta |
type | Tipo do formulário |
title | Título do formulário |
passed | Indica se o candidato foi aprovado na correção automática |
correctQuestionsCount | Número de questões corretas |
answers | Perguntas e respostas já relacionadas — cada item tem question e answer (ver abaixo) |
autoCorrectionResult | Detalhe da correção automática, quando aplicável |
As perguntas e as respostas já vêm no payload, dentro de answers. Cada item tem:
question: a pergunta (id,ref,type,titlee, em questões de múltipla escolha,properties.choices).answer: a resposta. O formato depende dotype:- texto/número/etc.: campo direto, ex.:
answer.text,answer.number,answer.email. - múltipla escolha (
type: "choices"): arrayanswer.choicescomlabel,selected,weightecorrectpor alternativa.
- texto/número/etc.: campo direto, ex.:
Itens sem answer significam perguntas que o candidato não respondeu. Você não
precisa chamar a API para obter as perguntas — elas já estão aqui.
Quando usar
- Avançar ou reprovar automaticamente um candidato com base no resultado (
passed). - Registrar a nota do questionário em um sistema externo.
- Notificar o recrutador quando um candidato passa de um corte mínimo.
Filtrando com rules
// Apenas respostas aprovadas
{ "passed": { "operator": "=", "value": true } }
Exemplo: lendo as respostas e buscando o candidato
As perguntas e respostas já vêm no payload em answers — basta iterar. O jobId e o
talentId permitem buscar os dados completos do talento e da candidatura na API:
import express from "express";
import axios from "axios";
const app = express();
app.use(express.json());
// Cliente autenticado da API do InHire (use um service account — ver guia de Autenticação)
const inhire = axios.create({
baseURL: "https://api.inhire.app",
headers: {
Authorization: `Bearer ${process.env.INHIRE_TOKEN}`,
"X-Tenant": "suaempresa",
},
});
// Extrai o valor de uma resposta conforme o tipo
function valorDaResposta(answer) {
if (!answer) return null; // pergunta não respondida
if (answer.type === "choices") {
return answer.choices.filter(c => c.selected).map(c => c.label);
}
return answer.text ?? answer.number ?? answer.email ?? answer.boolean ?? answer.date;
}
app.post("/webhooks/inhire/formulario", async (req, res) => {
// Valide a origem usando o header secreto configurado no webhook
if (req.headers.authorization !== "Bearer UM_SEGREDO_SEU") {
return res.sendStatus(401);
}
res.sendStatus(200); // responda rápido e processe de forma assíncrona
const { jobId, talentId, title, passed, answers } = req.body;
// 1. Lê as perguntas e respostas direto do payload
for (const item of answers) {
console.log(`${item.question.title}: ${JSON.stringify(valorDaResposta(item.answer))}`);
}
// 2. Busca os dados completos do talento e da candidatura
const [{ data: talento }, { data: candidatura }] = await Promise.all([
inhire.get(`/talents/${talentId}`), // o talento
inhire.get(`/job-talents/${jobId}/talents/${talentId}`), // o talento na vaga (candidatura)
]);
console.log(`${talento.name} ${passed ? "passou" : "não passou"} no formulário "${title}"`);
// ...sua lógica aqui (ex.: avançar/reprovar a candidatura)
});
app.listen(3000);
Endpoints usados: Obter talento e Obter candidaturas de um talento.