FocusSign
Referência de integração

Documentação da API

Base: https://focussign.com.br/api

01

Autenticação

Toda chamada de integração usa uma chave de API por tenant, enviada como Bearer token. Não há OAuth — é uma chave estática gerada uma vez e guardada no seu sistema.

Header obrigatório

Authorization: Bearer fs_live_7f2a9c...

A chave é gerada em Configurações → Integrações → API/Webhooks → Rotacionar chave. Ela aparece uma única vez, no instante da geração — depois disso só o prefixo mascarado fica visível. Rotacionar invalida a chave anterior imediatamente.

nota

Uma requisição autenticada por chave é atribuída a um usuário sintético do tenant, não a uma pessoa — notificações internas sobre documentos criados por essa chave não aparecem para ninguém logado no painel. Comportamento esperado para uma integração via API.

02

Criar documento para assinatura

Envia o PDF e a lista de signatários. Cada signatário cadastrado recebe automaticamente o convite pelo canal escolhido — e a resposta já devolve o link de assinatura de cada um, caso prefira disparar você mesmo.

POST
/api/assinaturasmultipart/form-data · autenticado
CampoTipoObrigatórioDescrição
filearquivo (PDF)simDocumento original a assinar.
nomestringsimNome do documento, ex. "Holerite Setembro/2026 - João Silva".
signatariosstring (JSON)simArray serializado — ver campos na seção 03.
mensagemstringopcionalRecado exibido ao signatário antes de assinar.
prazoEmstring (ISO date)opcionalPrazo do link. Sem isso, usa o padrão da plataforma.
sequencial"true"opcionalSó envie o campo quando for sequencial — cada signatário só recebe o convite após o anterior assinar.

Exemplo · curl

curl -X POST https://focussign.com.br/api/assinaturas \
  -H "Authorization: Bearer fs_live_7f2a9c..." \
  -F "nome=Holerite Setembro/2026 - João Silva" \
  -F 'signatarios=[{"nome":"João Silva","email":"joao@empresa.com","telefone":"11988887777","documento":"12345678900","metodo":"whatsapp"}]' \
  -F "file=@holerite-joao-setembro.pdf;type=application/pdf"

Resposta · 201 Created

{
  "id": "87c74195-abff-44f7-827b-ff024a495ddd",
  "signatarios": [
    {
      "signatarioId": "37658091-44f9-4bca-8328-64ea0c2b42b4",
      "nome": "João Silva",
      "email": "joao@empresa.com",
      "telefone": "11988887777",
      "metodo": "whatsapp",
      "link": "https://focussign.com.br/assinar/xsElwooQRId1..."
    }
  ]
}
disponível desde 07/09/2026

signatarios[].link só existe nesta resposta. O token que sustenta o link é hasheado no banco logo em seguida — essa é a única janela em que ele é legível. Se você quer enviar o link pelo seu próprio canal de WhatsApp, capture-o já nesta chamada.

03

Cadastro de signatário

Cada item do array "signatarios" aceita os campos abaixo. "nome" e "email" sempre obrigatórios; "telefone" só quando o canal é WhatsApp.

CampoTipoObrigatórioDescrição
nomestringsimNome completo exibido na tela de assinatura e no certificado.
emailstringsimUsado sempre para o código de verificação (OTP), independente do canal do convite.
telefonestringse metodo=whatsappDDD + número, com ou sem 55 na frente — o código do país é completado automaticamente antes de repassar para a API da Meta.
documentostringopcionalCPF do signatário, incluído no certificado de autenticidade.
papelstringopcionalTexto livre — "Signatário", "Testemunha", etc.
metodoemail · whatsapp · sms · presencialpadrão emailCanal usado para entregar o convite (o código de verificação em si sempre vai por e-mail).
ordemnúmeroopcionalSó importa quando o documento é sequencial.
corrigido 07/09/2026

Antes desta data, "metodo: whatsapp" existia mas não funcionava de verdade — o sistema tentava enviar pela API da Meta usando o e-mail do signatário no lugar do telefone, e nenhum telefone sequer existia no cadastro. Hoje isso é validado na criação: mandar whatsapp sem telefone retorna 400.

04

Webhooks — confirmação de recebimento e assinatura

É assim que você sabe, sem consultar nada, que o documento foi aberto e assinado. Configure a URL uma vez; a partir daí toda mudança de estado é entregue via POST.

POST
/api/webhooksautenticado · configuração única

Registrar sua URL

curl -X POST https://focussign.com.br/api/webhooks \
  -H "Authorization: Bearer fs_live_7f2a9c..." \
  -H "Content-Type: application/json" \
  -d '{"url":"https://seusistema.com.br/webhooks/focussign","eventos":"documento.visualizado,documento.assinado,documento.concluido"}'
EventoQuando disparadados
documento.enviadodocumento criado e convites enviados{documentoId, nome}
documento.visualizadosignatário abriu o link pela 1ª vez{documentoId, signatarioId}
documento.assinadoesse signatário específico assinou{documentoId, signatarioId}
documento.concluidotodos os signatários assinaram{documentoId, nome, hashVerificacao}
documento.recusadosignatário recusou assinar{documentoId, signatarioId, motivo}

Para comprovar que o destinatário recebeu e assinou, os dois que importam são documento.visualizado e documento.assinado.

POST recebido na sua URL

Headers:
  X-Focus-Sign-Event: documento.assinado
  X-Focus-Sign-Signature: sha256=e3b0c44298fc1c14...

Body:
{
  "evento": "documento.assinado",
  "dados": { "documentoId": "87c74195...", "signatarioId": "37658091..." },
  "criadoEm": "2026-09-07T03:16:50.179Z"
}

Verificar a assinatura HMAC · Node.js

const crypto = require("node:crypto");

function valido(corpoRaw, assinaturaHeader, secret) {
  const esperado = "sha256=" + crypto
    .createHmac("sha256", secret)
    .update(corpoRaw)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(assinaturaHeader),
    Buffer.from(esperado)
  );
}
limitação

Entrega em memória, não é uma fila durável: até 3 tentativas (backoff de 5s e 10s) e timeout de 10s por tentativa. Se o processo reiniciar no meio de um retry, aquela entrega se perde silenciosamente. Para um caso crítico como comprovação de recebimento, reconcilie periodicamente via GET /assinaturas/:id em vez de confiar só no webhook.

06

Consultar status do documento

Consulta pontual do estado atual e do histórico de eventos.

GET
/api/assinaturas/:idautenticado

Resposta · 200

{
  "id": "87c74195-abff-44f7-827b-ff024a495ddd",
  "nome": "Holerite Setembro/2026 - João Silva",
  "status": "assinado",
  "signatarios": [
    {
      "nome": "João Silva",
      "status": "assinado",
      "assinadoEm": "2026-09-07T14:02:11.000Z",
      "ip": "189.45.12.203"
    }
  ],
  "hashVerificacao": "a7f79670-98d5..."
}

status do documento: rascunho · aguardando · assinado · recusado · expirado · cancelado. status por signatário: pendente · visualizado · assinado · recusado.

07

Limitações atuais

Para não ter surpresa integrando: o que existe hoje, exatamente como existe.

config necessária

O envio automático de convite por WhatsApp (feito pelo Focus Sign, com metodo: whatsapp) depende do tenant ter uma conta Meta Business/WhatsApp Cloud API própria configurada em Configurações → Integrações. Sem isso, o convite cai em log interno e ninguém recebe nada — o link ainda vem certo na resposta da API, então seu sistema pode enviá-lo por conta própria independente disso.

sem fila durável

Webhooks são entregues em memória (seção 04) — reconcilie periodicamente via GET /assinaturas/:id se a confirmação de recebimento for crítica para o seu fluxo.

sem doc pública completa

Esta página cobre o que a integração de assinaturas precisa hoje; endpoints de gestão interna (pastas, clientes, modelos etc.) não fazem parte deste escopo.

08

Referência rápida

Todos os endpoints desta página, em uma tabela.

EndpointUso
POST
/api/assinaturas
Cria documento + signatários, devolve os links de assinatura
POST
/api/webhooks
Registra a URL de callback (feito uma vez)
GET
/api/assinaturas/:id
Status atual + histórico de eventos do documento
GET
/api/assinaturas/:id/pdf
PDF assinado, autenticado
GET
/verificar/:hash/pdf
PDF assinado, público, via hash do certificado