Como Integrar Assinatura Digital em Node.js / TypeScript
Integrar assinatura digital em uma aplicação Node.js / TypeScript não precisa ser complicado. Com o SDK oficial da SignDocs Brasil, você sai do zero a um documento assinado com validade jurídica em poucas linhas de código: autentica via OAuth2, cria uma sessão de assinatura, envia ao signatário, recebe o evento de conclusão por webhook e baixa o PDF assinado. Este guia mostra o caminho completo, com snippets idiomáticos em async/await.
O público deste tutorial é o desenvolvedor backend Node que precisa coletar assinaturas eletrônicas ou digitais (ICP-Brasil) dentro do próprio produto — um SaaS, um sistema de RH, uma fintech ou um marketplace. Vamos usar a Assinatura Expressa (POST /v1/signing-sessions) como caminho principal, por ser a forma mais rápida de colocar uma assinatura em produção, e comentar quando faz sentido migrar para a Transaction API de envelopes.
Se você ainda está avaliando a plataforma, vale a leitura do panorama na página da API de assinatura digital e do guia-pilar o que é uma API de assinatura digital. Já quem trabalha com Python ou apenas REST puro pode acompanhar os equivalentes em Python e cURL / REST.
Pré-requisitos
Antes de começar, garanta que você tem o ambiente pronto:
- Node.js 18 ou superior — versões LTS recentes já incluem
fetchecryptonativos, usados nos exemplos. - Uma conta SignDocs com credenciais de homologação — o sandbox é gratuito e self-service (conta PJ); o acesso de produção à API é contratado como plano sob medida. O passo a passo está em como obter sua API key.
- Credenciais de API — um
client_ide umclient_secretpara o fluxo OAuth2 client-credentials. - Acesso ao ambiente de homologação (host
api-hml.signdocs.com.br) para testar sem afetar dados reais.
1. Instalar o SDK oficial TypeScript
A SignDocs mantém SDKs oficiais para TypeScript/Node, Python, Go, Java, PHP e C#/.NET. Para Node, instale o SDK oficial TypeScript da SignDocs via npm (ou o gerenciador de sua preferência):
O pacote é distribuído com tipos TypeScript embutidos, então o autocompletar e a checagem de tipos funcionam imediatamente em editores como VS Code, sem instalar pacotes @types/* adicionais. Em projetos JavaScript puro o SDK funciona da mesma forma — você apenas perde a verificação estática de tipos.
Estrutura mínima do projeto
2. Configurar a autenticação OAuth2 client-credentials
A API SignDocs usa o fluxo OAuth2 client-credentials: sua aplicação troca client_id + client_secret por um token de acesso (bearer JWT) que expira em 15 minutos, assinado com ECDSA (ES256) e com chaves protegidas em KMS. Esse token é então enviado no header Authorization de cada chamada. O SDK cuida dessa troca para você, mas é importante entender o mecanismo — os detalhes completos estão no guia de autenticação OAuth2 da API.
Carregue as credenciais de variáveis de ambiente. Nunca coloque o client_secret em código versionado:
Internamente, o cliente realiza o fluxo client-credentials, armazena o token em memória e o renova automaticamente quando expira. Caso prefira controlar o fluxo manualmente (por exemplo, em REST puro sem o SDK), a troca de token é uma chamada direta:
3. Criar uma sessão de Assinatura Expressa
Com o cliente autenticado, criar uma sessão de assinatura é uma única chamada a POST /v1/signing-sessions. Você define o documento, o signatário e o perfil de assinatura (profile), que determina o nível de exigência probatória.
Anatomia da requisição
A tabela abaixo resume os campos principais do corpo da requisição:
| Campo | Descrição |
|---|---|
document |
O PDF a ser assinado, enviado como base64 no campo content, com filename opcional (até 10 MB). |
signer |
Dados do signatário: nome, e-mail, o userExternalId (o ID dele no seu sistema) e CPF ou CNPJ (sem pontuação) para vinculação de identidade. |
policy.profile |
Perfil de assinatura. Use DIGITAL_CERTIFICATE para exigir certificado ICP-Brasil; CLICK_ONLY, CLICK_PLUS_OTP, BIOMETRIC e BIOMETRIC_PLUS_OTP cobrem os níveis eletrônicos. |
returnUrl |
Para onde o signatário é redirecionado após concluir (opcional). Com owner informado, a SignDocs envia o convite por e-mail; sem ele, você entrega o link. |
| Webhooks | Registrados uma única vez por tenant via POST /v1/webhooks (não por sessão) — é por lá que os eventos do ciclo de vida chegam. |
profile. O valor DIGITAL_SIGN_A1 é um tipo de passo (step.type) que aparece na resposta, não um valor válido de policy.profile. Para exigir certificado digital ICP-Brasil, use DIGITAL_CERTIFICATE — via API, o certificado é A1 (em arquivo); para titulares de token A3, o aplicativo SignDocs oferece o assinador desktop. Enviar DIGITAL_SIGN_A1 como profile resulta em erro 400.
Código: criar a sessão e adicionar o signatário
A resposta inclui o sessionId, a url e o clientSecret. Para o checkout hospedado, monte o link final (url + "?cs=" + clientSecret) e redirecione o usuário ou envie por e-mail. Para a assinatura embarcada (embedded), entregue o clientSecret ao seu front-end e abra o checkout como popup com o SDK @signdocs-brasil/js (SignDocsBrasil.init() + sd.checkout({ clientSecret })) — o que mantém o usuário no seu produto.
signerEmail === senderEmail; caso contrário, apenas entregue o link.
Embedded vs. checkout hospedado
A escolha do modo de entrega depende da experiência desejada. Para aprofundar, veja a página da Assinatura Expressa.
| Modo | Quando usar |
|---|---|
| Checkout hospedado | Quer o caminho mais rápido. A SignDocs hospeda a página de assinatura; você só compartilha a URL. Zero código de front-end. |
| Embedded (SDK / popup) | Quer manter o usuário dentro do seu produto, com sua marca. Exige abrir o checkout no front-end via SDK @signdocs-brasil/js com o clientSecret. |
4. Quando usar a Transaction API (envelopes)
A Assinatura Expressa resolve a maioria dos casos de um signatário. Quando o fluxo envolve múltiplos signatários no mesmo documento, com ordem de assinatura ou um ciclo de vida mais elaborado, a API de envelopes é a escolha certa. Ela está exposta no mesmo SDK:
Os fundamentos do ciclo de vida transacional — estados, transições e finalização — estão detalhados no guia de fluxo transacional da API. Para regras de ordenação entre signatários, consulte ordem de assinatura com múltiplos signatários.
5. Receber o webhook e verificar a assinatura HMAC-SHA256
Em vez de ficar consultando o status repetidamente (polling), o caminho recomendado é receber webhooks: a SignDocs envia um HTTP POST ao seu endpoint a cada evento — SIGNING_SESSION.COMPLETED, TRANSACTION.COMPLETED, STEP.FAILED, entre outros. Cada requisição traz uma assinatura HMAC-SHA256 em um header, que você precisa verificar para garantir que o evento veio mesmo da SignDocs. A arquitetura completa de eventos está no guia de webhooks e eventos da API.
Receptor Express com verificação HMAC
O ponto crítico é preservar o corpo bruto (raw body) da requisição: o HMAC é calculado sobre os bytes exatos recebidos, então qualquer reserialização do JSON quebraria a verificação.
Despachar eventos de forma idempotente
Webhooks têm semântica de entrega pelo menos uma vez: o mesmo evento pode chegar duplicado após um retry. Use o id do evento para deduplicar antes de processar. O payload real é { id, eventType, tenantId, transactionId, timestamp, data }:
Set em memória não basta — use um armazenamento compartilhado (Redis com SET NX, ou uma tabela com chave única no id do evento). Responda 200 OK em segundos e empurre o trabalho pesado para uma fila.
6. Baixar o PDF assinado e o pacote de evidências
Quando a transação é concluída (TRANSACTION.COMPLETED), você recupera os artefatos finais: o PDF assinado no padrão PAdES e o pacote de evidências .p7m — um container PKCS#7/CMS que vincula o hash SHA-256 do documento ao carimbo de hora do servidor (timestamps ISO-8601 registrados pelos servidores da SignDocs) e aos dados de autenticação que comprovam quem assinou, quando e como.
O PDF assinado preserva validade jurídica no Brasil conforme a MP 2.200-2/2001 (ICP-Brasil) e a conformidade com a LGPD. Qualquer parte pode conferir a integridade do documento no verificador público da SignDocs. Para entender a estrutura probatória do .p7m, veja o guia de evidence pack e prova jurídica.
Boas práticas para produção
- Segredos fora do código: carregue
client_secretewebhook_secretde variáveis de ambiente ou de um cofre (AWS Secrets Manager, Vault). Reaproveite o token OAuth2 em memória enquanto válido. - Idempotência sempre: trate cada webhook como possivelmente duplicado. A chave de deduplicação é o
iddo evento. - Comparação timing-safe: valide o HMAC com
crypto.timingSafeEqual, nunca com===direto. - Responda rápido: retorne 200 OK em segundos e processe o evento em uma fila assíncrona; webhooks têm timeout curto.
- Homologação antes de produção: teste tudo em
api-hml.signdocs.com.br; lembre-se do TTL de 7 dias das entidades de sandbox. - Tratamento de erros: a API retorna códigos HTTP semânticos. Implemente retry com backoff em erros 5xx e trate 4xx como problema de requisição.
Perguntas Frequentes
Preciso usar TypeScript para integrar a API de assinatura em Node.js?
Não. O SDK oficial da SignDocs é escrito em TypeScript, mas funciona perfeitamente em projetos JavaScript puro (CommonJS ou ES Modules). O TypeScript apenas oferece autocompletar e checagem de tipos no editor, o que reduz erros de integração. Se preferir não usar o SDK, todas as operações também estão disponíveis via REST puro com fetch ou axios, já que a API é agnóstica de linguagem.
Como armazeno o token OAuth2 com segurança em uma aplicação Node.js?
Nunca coloque o client_secret diretamente no código-fonte nem no repositório. Carregue-o de variáveis de ambiente (process.env) ou de um gerenciador de segredos como AWS Secrets Manager, HashiCorp Vault ou Doppler. O token de acesso (bearer) emitido pelo fluxo client-credentials é de curta duração; mantenha-o apenas em memória, reaproveite-o enquanto for válido e solicite um novo somente quando expirar.
Qual a diferença entre a Assinatura Expressa e a Transaction API no SDK Node?
A Assinatura Expressa (POST /v1/signing-sessions) cria em uma única chamada uma sessão pronta para assinar, retornando a URL de checkout hospedado e o clientSecret para o checkout embutido via SDK JavaScript. É ideal para fluxos rápidos de um signatário. A API de envelopes suporta múltiplos signatários no mesmo documento (até 100), com ordem sequencial ou paralela e o ciclo de vida completo. Ambas estão expostas no mesmo SDK; escolha conforme a complexidade do fluxo.
Como recebo notificações de que o documento foi assinado em Node.js?
Configure um endpoint HTTPS na sua aplicação e registre a URL como webhook. A SignDocs envia um HTTP POST a cada evento (por exemplo SIGNING_SESSION.COMPLETED, TRANSACTION.COMPLETED) com uma assinatura HMAC-SHA256 no header X-SignDocs-Signature. No receptor Express, preserve o corpo bruto da requisição e valide com o helper verifyWebhookSignature do SDK @signdocs-brasil/api (que faz a comparação timing-safe e a checagem anti-replay do timestamp) antes de processar o evento. Responda 200 OK rapidamente e processe de forma assíncrona.
O SDK Node funciona em AWS Lambda e outras arquiteturas serverless?
Sim. O SDK não depende de estado de servidor e funciona em AWS Lambda, Google Cloud Functions, Vercel e Cloudflare Workers compatíveis com Node. Recomenda-se inicializar o cliente fora do handler para reaproveitá-lo entre invocações no mesmo contexto de execução, e cachear o token OAuth2 em memória para evitar pedir um novo token a cada chamada. Considere o cold start ao configurar timeouts de webhook.
Posso testar a integração em homologação antes de ir para produção?
Sim. A SignDocs oferece um ambiente de homologação (sandbox) com host api-hml.signdocs.com.br, usado com credenciais separadas das de produção. Basta apontar a baseUrl do SDK para o host de homologação. Lembre-se de que as entidades criadas em homologação têm TTL de 7 dias, ou seja, expiram automaticamente após esse período — o ambiente é destinado a testes, não a dados persistentes.
Como baixo o PDF assinado com a trilha de evidências em Node.js?
Após o evento TRANSACTION.COMPLETED, use o SDK para recuperar os artefatos finais: client.documents.download(transactionId) devolve URLs temporárias (o PDF carimbado vem em signedUrl), e o pacote de evidências .p7m (container PKCS#7/CMS que vincula o hash SHA-256 do documento ao carimbo de hora do servidor e aos dados de autenticação) é obtido via client.evidence.get + client.verification.downloads. Baixe os arquivos dessas URLs e grave em disco, em um bucket S3 ou envie às partes. O PDF preserva a validade jurídica conforme a MP 2.200-2/2001 e a integridade pode ser conferida no verificador público.
Coloque assinatura digital no seu app Node.js hoje
Do npm install @signdocs-brasil/api ao PDF assinado: o SDK oficial TypeScript da SignDocs cuida de OAuth2, Assinatura Expressa, webhooks HMAC e download de evidências. O sandbox de homologação é gratuito; o acesso à API é um plano sob medida com o time comercial.