Aceitou — Guia rápido para integradores¶
Tudo que você precisa pra começar a usar a API. Tempo estimado pra primeiro documento criado: ~15 min.
A referência completa da API (todos os endpoints, payloads, códigos de erro) está em API Reference. Este guia é o "começo rápido".
1. O que você recebeu¶
Do time Aceitou do seu cliente (entregue por canal seguro, ex: 1Password):
| Item | Exemplo |
|---|---|
| Base URL (produção) | https://api.aceitou.com.br |
| Base URL (sandbox/demo) | https://api-demo.aceitou.com.br |
| API Key | ak_live_xxxxxxxxxxxxxxxxxxxxxxxx |
| Escopos da chave | ex: documents:read, documents:write, webhooks:write |
A chave é secret. Nunca commit, nunca client-side (browser/mobile). Use só no backend, em ambiente seguro. Se vazar, peça pro cliente rotacionar no portal dele (a chave antiga morre na hora).
2. Autenticação¶
Toda chamada leva o header X-Api-Key:
Teste de fumaça (5 segundos): chame GET /api/v1/templates. Resposta com array (mesmo vazio) = chave válida. 401 = chave errada. 403 = chave sem o escopo necessário.
Erros seguem RFC 7807 Problem Details:
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.4",
"title": "Forbidden",
"status": 403,
"detail": "A chave de API não possui o escopo 'documents:write' necessário para este recurso.",
"requiredScope": "documents:write"
}
3. Fluxo típico: criar e mandar um documento pra assinar¶
Quatro chamadas. Mesmo documentId (criado no passo 1) é usado em todos os outros.
3.1 — Criar o documento (rascunho vazio)¶
curl -X POST https://api-demo.aceitou.com.br/api/v1/documents \
-H "X-Api-Key: $KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Contrato de prestação de serviços",
"expirationDays": 30,
"reminderIntervalDays": 3
}'
→ Resposta 201 traz { "id": 12345, ... } — guarde esse id.
3.2 — Anexar o PDF (ou gerar a partir de template)¶
Opção A — Upload de PDF pronto:
curl -X POST https://api-demo.aceitou.com.br/api/v1/documents/12345/documents \
-H "X-Api-Key: $KEY" \
-F "file=@contrato.pdf;type=application/pdf"
Opção B — Gerar a partir de template do cliente (variáveis substituídas no servidor):
curl -X POST https://api-demo.aceitou.com.br/api/v1/documents/12345/documents/from-template \
-H "X-Api-Key: $KEY" \
-H "Content-Type: application/json" \
-d '{
"templateId": 9,
"variables": { "nome": "Maria Silva", "cpf": "111.222.333-44" }
}'
(Use GET /api/v1/templates pra listar os templates disponíveis no tenant.)
3.3 — Adicionar signatários¶
Um POST por signatário:
curl -X POST https://api-demo.aceitou.com.br/api/v1/documents/12345/signers \
-H "X-Api-Key: $KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Maria Silva",
"email": "maria@cliente.com",
"verificationMethod": "email_token",
"signingOrder": 1
}'
verificationMethod:simple(só clique),email_token(OTP por email),sms_token,email_and_smssigningOrder: mesma ordem = paralelo; ordens maiores só recebem convite depois das menores assinarem
3.4 — Disparar pra assinatura¶
→ Envia os emails de convite e emite o webhook document_sent.
Opção — entregar o link sem disparar email (caso você queira mandar pelo seu próprio canal):
curl -X POST https://api-demo.aceitou.com.br/api/v1/documents/12345/send \
-H "X-Api-Key: $KEY" -H "Content-Type: application/json" \
-d '{"notify": false}'
curl https://api-demo.aceitou.com.br/api/v1/documents/12345/signers/<signerId>/signing-link \
-H "X-Api-Key: $KEY"
Devolve a URL completa que cada signatário usa pra assinar.
3.5 — Consultar status / baixar assinado¶
# Status detalhado
curl https://api-demo.aceitou.com.br/api/v1/documents/12345 \
-H "X-Api-Key: $KEY"
# Baixar PDF assinado (depois que todos assinaram)
curl -O -J "https://api-demo.aceitou.com.br/api/v1/documents/12345/download?version=signed" \
-H "X-Api-Key: $KEY"
4. Webhooks (recomendado em vez de polling)¶
4.1 — Cadastrar uma vez¶
curl -X POST https://api-demo.aceitou.com.br/api/v1/webhooks \
-H "X-Api-Key: $KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://seu-app.com/webhooks/aceitou",
"events": ["document_sent", "signer_signed", "document_completed"]
}'
→ Resposta 201 traz { "id": 7, "secret": "..." }. O secret aparece UMA VEZ — guarde junto com a API key.
4.2 — Validar a assinatura HMAC¶
Toda entrega traz três headers:
X-Aceitou-Delivery-Id é o ID único da delivery (igual em todos os retries) — use pra dedup.
Compute HMAC-SHA256(secret, raw_body) em hex lowercase e compare. Sempre use comparação de tempo constante (timingSafeEqual/compare_digest/hash_equals).
Node.js:
import crypto from "node:crypto";
function verify(rawBody, signatureHeader, secret) {
const expected = "sha256=" + crypto
.createHmac("sha256", secret)
.update(rawBody, "utf8")
.digest("hex");
const a = Buffer.from(signatureHeader);
const b = Buffer.from(expected);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
app.post(
"/webhooks/aceitou",
express.raw({ type: "application/json" }),
(req, res) => {
const sig = req.header("X-Aceitou-Signature");
if (!sig || !verify(req.body, sig, process.env.ACEITOU_WEBHOOK_SECRET)) {
return res.status(401).send("invalid signature");
}
// ... processe req.body (Buffer) — faça JSON.parse depois
res.status(200).send();
},
);
Python:
import hmac, hashlib
def verify(raw_body: bytes, signature_header: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(
secret.encode(), raw_body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature_header, expected)
PHP:
function verify($raw_body, $signature_header, $secret) {
$expected = 'sha256=' . hash_hmac('sha256', $raw_body, $secret);
return hash_equals($signature_header, $expected);
}
C# / .NET (ASP.NET Core):
using System.Security.Cryptography;
using System.Text;
app.MapPost("/webhooks/aceitou", async (HttpContext ctx) =>
{
using var ms = new MemoryStream();
await ctx.Request.Body.CopyToAsync(ms);
var raw = ms.ToArray();
var sig = ctx.Request.Headers["X-Aceitou-Signature"].ToString();
var secret = Environment.GetEnvironmentVariable("ACEITOU_WEBHOOK_SECRET")!;
if (!Verify(raw, sig, secret))
return Results.Unauthorized();
// var ev = ctx.Request.Headers["X-Aceitou-Event"].ToString();
// processa raw (byte[]) como JSON...
return Results.Ok();
});
static bool Verify(byte[] rawBody, string signatureHeader, string secret)
{
var hash = HMACSHA256.HashData(Encoding.UTF8.GetBytes(secret), rawBody);
var expected = "sha256=" + Convert.ToHexString(hash).ToLowerInvariant();
return CryptographicOperations.FixedTimeEquals(
Encoding.UTF8.GetBytes(signatureHeader),
Encoding.UTF8.GetBytes(expected));
}
4.3 — Eventos disponíveis¶
| Evento | Quando dispara |
|---|---|
document_sent |
Documento sai de Draft → Sent |
signer_signed |
Cada signatário assina |
document_completed |
Todos os signatários assinaram |
document_rejected |
Um signatário recusa |
document_cancelled |
Dono cancela o envelope |
document_expired |
Expirou antes de todos assinarem |
4.4 — Retry¶
A Aceitou tenta a entrega em 1, 5, 15, 60 e 360 minutos antes de marcar como Failed. Responda HTTP 2xx em até 10s; qualquer outra resposta (incluindo 3xx) conta como falha e dispara retry. O cliente Aceitou consegue forçar replay manual em Configurações → Webhooks → Entregas.
5. Boas práticas¶
- Idempotência: repita o mesmo POST se você não recebeu resposta — o servidor protege contra duplicatas pelo
Idempotency-Key(envie um UUID v4 no header se quiser controle explícito). - Rate limits: 60 requests/min/chave no padrão. Em produção, dimensione com o time da Aceitou se for picos previsíveis.
- Erro 402 (Payment Required): o cliente bateu no limite do plano dele (ex: documentos/mês). Não tente retentar; sinalize pro lado dele.
- Sandbox: use
api-demo.aceitou.com.brdurante desenvolvimento. Mesma chave não funciona em ambos os ambientes — peça uma sandbox separada. - Validar webhook em produção real: configure ngrok/Cloudflare Tunnel no dev, depois HTTPS público em homologação. A Aceitou só entrega em HTTPS.
6. Quando algo dá errado¶
| Sintoma | Provavelmente é |
|---|---|
401 em toda chamada |
Chave errada / no header errado (não é Authorization, é X-Api-Key) |
403 em endpoint específico |
Falta escopo na chave — peça pro cliente expandir |
402 |
Limite de plano atingido |
422 document.invalid_status |
Operação inválida pro status atual (ex: enviar um já enviado) |
404 em /documents/{id} |
Documento não existe ou pertence a outro tenant — confira o id |
| Webhook não chega | Veja Configurações → Webhooks → Entregas no portal: status code recebido, body de resposta, número de tentativas |
Em caso de dúvida, contato preferencial: canal Slack compartilhado entre os times técnicos (combine com o admin que entregou a chave).