AssinAPI

Receitas de integração

Assinar contrato depois do cadastro

Ao concluir o cadastro do cliente, gere o contrato e envie para assinatura automaticamente.

Arquitetura: Seu backend (evento "usuário cadastrado") → POST /signature-requests → e-mail com link → webhook envelope.completed → libera acesso.

  1. No handler de cadastro, gere o PDF do contrato.
  2. Chame POST /signature-requests com o PDF em base64 e os dados do cliente.
  3. Salve o envelopeId no registro do cliente (externalId = ID do cliente).
  4. No webhook envelope.completed, marque o contrato como assinado.

Endpoint: POST /v1/signature-requests · Webhook: envelope.completed

typescript
const req = await assinapi.signatureRequests.create({
  title: 'Contrato de adesão',
  file: contratoPdf,
  filename: 'contrato.pdf',
  signer: { name: user.name, email: user.email, cpf: user.cpf },
  externalId: user.id,
});
await db.users.update(user.id, { assinapiEnvelopeId: req.id });

Gerar contrato e enviar para assinatura

Monte o PDF a partir de um template no seu sistema e envie com ordem de assinatura (empresa → cliente).

Arquitetura: Template → PDF (seu backend) → POST /envelopes + /documents + /signers (signingOrder) + /send.

  1. Gere o PDF.
  2. Crie o envelope com signingOrderEnabled: true.
  3. Adicione a empresa (signingOrder 1) e o cliente (signingOrder 2).
  4. Envie: o cliente só recebe o convite depois que a empresa assinar.

Endpoint: POST /v1/envelopes · /documents · /signers · /send · Webhook: signer.signed, envelope.completed

typescript
const env = await assinapi.envelopes.create({ title: 'Contrato', signingOrderEnabled: true });
await assinapi.envelopes.addDocument(env.id, { file: pdf, filename: 'contrato.pdf' });
await assinapi.envelopes.addSigner(env.id, { name: 'Empresa', email: 'juridico@empresa.com', cpf: cpfRepresentante, signingOrder: 1 });
await assinapi.envelopes.addSigner(env.id, { name: cliente.nome, email: cliente.email, cpf: cliente.cpf, signingOrder: 2 });
await assinapi.envelopes.send(env.id);

Enviar contrato automaticamente pelo n8n

Novo registro no CRM/planilha dispara o envio para assinatura.

Arquitetura: Trigger (CRM/Sheets) → HTTP Request (POST /signature-requests) → Webhook node recebe envelope.completed.

  1. Crie a credencial Header Auth com Authorization = Bearer <chave>.
  2. Adicione um HTTP Request com POST /signature-requests (PDF em base64).
  3. Crie um Webhook node e cadastre a URL em POST /webhooks.
  4. Valide o HMAC em um Code node antes de agir.

Endpoint: POST /v1/signature-requests · Webhook: envelope.completed

typescript
// Code node (n8n) — validar HMAC
const crypto = require('crypto');
const h = $input.first().json.headers;
const raw = JSON.stringify($input.first().json.body); // prefira 1 nas opções do Webhook
const expected = 'v1=' + crypto.createHmac('sha256', $env.ASSINAPI_WEBHOOK_SECRET).update(h['x-event-id'] + '.' + h['x-timestamp'] + '.' + raw).digest('hex');
if (expected !== h['x-signature']) throw new Error('Assinatura inválida');
return $input.all();

Assinar contrato criado no Lovable

App Lovable com Supabase: o frontend pede, a Edge Function assina a chamada.

Arquitetura: React (Lovable) → supabase.functions.invoke("assinapi-send") → Edge Function (ASSINAPI_SECRET_KEY em Secrets) → AssinAPI.

  1. Guarde ASSINAPI_SECRET_KEY em Supabase → Edge Functions → Secrets.
  2. Crie a função assinapi-send que chama POST /signature-requests.
  3. No frontend, chame a função com os dados do contrato.
  4. Use o gerador "Integrar com IA" para obter o prompt pronto para o Lovable.

Endpoint: POST /v1/signature-requests · Webhook: envelope.completed

typescript
// Frontend (Lovable) — sem secret!
const { data, error } = await supabase.functions.invoke('assinapi-send', {
  body: { contractId, signer: { name, email, cpf } },
});

Receber PDF assinado no Supabase

No envelope.completed, baixe o PDF final e o certificado para o Supabase Storage.

Arquitetura: Webhook → Edge Function → GET /envelopes/{id}/evidence → download → Storage (bucket privado).

  1. Receba e valide o webhook.
  2. Chame GET /envelopes/{id}/evidence.
  3. Baixe downloads.documents[].final e downloads.certificate (URLs expiram em minutos).
  4. Salve no bucket privado e registre os hashes.

Endpoint: GET /v1/envelopes/{id}/evidence · Webhook: envelope.completed

typescript
const ev = await fetch(`${BASE}/envelopes/${envelopeId}/evidence`, { headers: { Authorization: `Bearer ${KEY}` } }).then((r) => r.json());
const pdf = await fetch(ev.downloads.documents[0].final).then((r) => r.arrayBuffer());
await supabase.storage.from('contratos').upload(`${envelopeId}.pdf`, pdf, { contentType: 'application/pdf' });

Atualizar status no Bubble após assinatura

Backend workflow do Bubble recebe o webhook e atualiza o Thing do contrato.

Arquitetura: AssinAPI webhook → Bubble Backend Workflow (API workflow) → Make changes to Contract.

  1. Habilite "This app exposes a Workflow API".
  2. Crie o API workflow "assinapi_completed" que recebe o JSON.
  3. Cadastre a URL do workflow em POST /webhooks.
  4. Para validar o HMAC, use um backend intermediário (Cloudflare Worker/Supabase) ou o plugin de crypto do Bubble.

Endpoint: POST /v1/webhooks · Webhook: envelope.completed

typescript
URL do workflow:
https://seuapp.bubbleapps.io/api/1.1/wf/assinapi_completed

Eventos: envelope.completed, signer.signed

Enviar WhatsApp após assinatura

Envie o link de assinatura pelo WhatsApp em vez de e-mail e avise quando concluir.

Arquitetura: POST /send com notify:false → signingLinks → sua API de WhatsApp. Webhook envelope.completed → mensagem de confirmação.

  1. Envie o envelope com { "notify": false }.
  2. Pegue signingLinks[].signingUrl da resposta e envie pelo seu provedor de WhatsApp.
  3. Ao receber envelope.completed, envie a confirmação com o verifyUrl.

Endpoint: POST /v1/envelopes/{id}/send · Webhook: envelope.completed

typescript
const sent = await assinapi.envelopes.send(envelopeId, { notify: false });
for (const link of sent.signingLinks) {
  await whatsapp.send(telefoneDo(link.signerId), `Olá ${link.name}! Assine aqui: ${link.signingUrl}`);
}