Ir para o conteúdo

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:

curl https://api-demo.aceitou.com.br/api/v1/templates \
  -H "X-Api-Key: ak_live_xxxxxxxxxxxx"

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_sms
  • signingOrder: mesma ordem = paralelo; ordens maiores só recebem convite depois das menores assinarem

3.4 — Disparar pra assinatura

curl -X POST https://api-demo.aceitou.com.br/api/v1/documents/12345/send \
  -H "X-Api-Key: $KEY"

→ 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-Signature: sha256=<hex>
X-Aceitou-Event: document_sent
X-Aceitou-Delivery-Id: 1234567890

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 DraftSent
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.br durante 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).