Tema
Início rápido
Da criação da chave à primeira chamada. Você vai precisar de uma conta no Edusati com permissão de Integrações na empresa em que quer integrar.
1. Crie uma chave de API
No painel do Edusati:
- Vá em Integrações › Chaves de API
- Clique em Nova chave
- Dê um nome que diga de onde ela será usada (
ERP da matriz,Zapier,Backup noturno) - Marque apenas os escopos que a integração precisa — veja Autenticação
- Copie o token
O token aparece uma única vez
Não há como recuperá-lo depois. Guarde-o no cofre de segredos da sua aplicação antes de fechar a janela. Se perder, revogue a chave e crie outra — não existe "reexibir".
O token tem esta forma:
edu_a1b2c3d4e5f60718_9f8e7d6c5b4a39281706f5e4d3c2b1a0...2. Confirme que a chave funciona
bash
curl -H "Authorization: Bearer $EDUSATI_KEY" \
https://api.edusati.com/v1/mejson
{
"success": true,
"data": {
"company": { "id": "c0ffee00-…", "name": "Colégio Aurora", "slug": "colegio-aurora" },
"apiKey": {
"id": "a1b2c3d4-…",
"name": "ERP da matriz",
"scopes": ["surveys:read", "reports:read", "invites:write", "invites:send"],
"rateLimitPerMin": 60
}
}
}GET /v1/me não exige escopo nenhum — só uma chave válida. É o teste de fumaça da sua configuração, e também a forma de descobrir com qual empresa a chave fala: isso vem da própria chave, nunca de um parâmetro.
Se voltar 401, confira Erros › Autenticação.
3. Liste os formulários
bash
curl -H "Authorization: Bearer $EDUSATI_KEY" \
"https://api.edusati.com/v1/forms?limit=5"json
{
"success": true,
"data": [
{
"id": "f1a2b3c4-…",
"name": "Pesquisa de satisfação — Julho",
"slug": "satisfacao-julho",
"isPublic": true,
"isClosed": false,
"requiresInvite": false,
"questionCount": 8,
"responseCount": 1243,
"createdAt": "2026-07-01T12:00:00.000Z",
"updatedAt": "2026-07-28T09:14:02.000Z"
}
],
"meta": { "page": 1, "limit": 5, "total": 12, "totalPages": 3 }
}Guarde o id do formulário que interessa — quase todas as outras rotas partem dele.
4. Leia as respostas
bash
curl -H "Authorization: Bearer $EDUSATI_KEY" \
"https://api.edusati.com/v1/forms/$FORM/responses?include=answers&limit=2"json
{
"success": true,
"data": [
{
"id": "r1a2b3c4-…",
"formId": "f1a2b3c4-…",
"respondent": { "name": "Ana Prado", "email": "ana@exemplo.com", "phone": null, "externalId": "MAT-4471" },
"answers": {
"q_nps": 9,
"q_comentario": "Atendimento muito rápido",
"q_turno": "opt_manha"
},
"completedAt": "2026-07-28T13:45:11.980Z",
"createdAt": "2026-07-28T13:45:12.001Z"
}
],
"meta": { "limit": 2, "total": 1243, "hasMore": true, "nextCursor": "MjAyNi0wNy0yOFQxMzo0…" }
}Três coisas para notar:
answerssó vem cominclude=answers. O padrão é a projeção magra, porque o caminho normal é varrer milhares de respostas e o payload completo pesa.- As chaves de
answerssão ids de pergunta. Para transformá-las em enunciados, busque a estrutura:GET /v1/forms/{id}trazcontent.sections[].questions[]. Veja Interpretando as respostas. - Esta lista pagina por cursor, não por
page. Detalhes em Paginação.
5. Crie e envie um convite
Convite é um link pessoal, associado a um contato. Criar e enviar são passos separados — dá para criar o convite e distribuir o link por conta própria, sem usar nosso envio.
bash
# Cria (não envia). Devolve a `url` do link pessoal.
curl -X POST -H "Authorization: Bearer $EDUSATI_KEY" -H 'content-type: application/json' \
-d '{"name":"Ana Prado","email":"ana@exemplo.com","externalId":"MAT-4471"}' \
"https://api.edusati.com/v1/forms/$FORM/invites"json
{
"success": true,
"data": {
"id": "i1a2b3c4-…",
"token": "Xk3nP9qR",
"url": "https://form.edusati.com/i/Xk3nP9qR",
"status": "created",
"effectiveStatus": "created",
"email": "ana@exemplo.com",
"externalId": "MAT-4471"
}
}bash
# Envia por e-mail (consome quota mensal da empresa)
curl -X POST -H "Authorization: Bearer $EDUSATI_KEY" -H 'content-type: application/json' \
-d "{\"channel\":\"email\",\"inviteIds\":[\"$INVITE_ID\"]}" \
"https://api.edusati.com/v1/forms/$FORM/invites/send"json
{ "success": true, "data": { "batchId": "b1a2…", "queued": 1, "skipped": [] } }200 significa "enfileirado", não "entregue"
O envio é assíncrono. O resultado real chega pelos eventos invite.sent, invite.delivered e invite.failed — veja Webhooks.
E sempre percorra skipped[]: convite sem e-mail, já respondido, expirado ou com o endereço suprimido é pulado sem virar erro. Um queued: 0 com skipped cheio é uma resposta de sucesso que não enviou nada.
Interpretando as respostas
As chaves de answers são ids de pergunta. Busque a estrutura uma vez e monte o mapa:
bash
curl -H "Authorization: Bearer $EDUSATI_KEY" \
"https://api.edusati.com/v1/forms/$FORM"json
{
"success": true,
"data": {
"id": "f1a2b3c4-…",
"name": "Pesquisa de satisfação — Julho",
"content": {
"sections": [
{
"id": "s1",
"name": "Atendimento",
"questions": [
{ "id": "q_nps", "name": "Você nos recomendaria?", "type": "NPS", "mandatory": true },
{ "id": "q_turno", "name": "Qual turno?", "type": "RADIO", "options": [
{ "id": "opt_manha", "name": "Manhã", "order": 0 },
{ "id": "opt_tarde", "name": "Tarde", "order": 1 }
]}
]
}
]
}
}
}O formato do valor depende do type:
| Tipo | Valor em answers |
|---|---|
TEXT, PARAGRAPH, DATE, TIME, DATETIME | string |
NUMBER, RANGE, NPS, STAR | number |
BOOLEAN | boolean |
RADIO, SELECT | id da opção (string) |
CHECKBOX | array de ids |
RANKING | array de ids, em ordem de preferência |
MATRIX | objeto { [rowId]: columnId } |
FILE | array de { fileId, name, size, mime } |
Pergunta ausente ≠ pergunta em branco
Se uma pergunta foi ocultada por lógica condicional ou estava numa seção pulada, a chave simplesmente não aparece em answers. Trate ausência como "não se aplica", não como "não respondeu".
Próximos passos
- Autenticação — escopos, limite de requisições, rotação de chave
- Paginação — o laço correto para varrer coleções grandes
- Webhooks — pare de consultar em laço e receba os eventos
- Referência completa — todos os endpoints e schemas
- Coleção Postman — importe e teste sem escrever código