Como Testar sua Integração de Assinatura Digital: do Sandbox ao CI

Integração de assinatura é o tipo de código que "funciona na demo" e falha no pior momento: o webhook que chegou duas vezes, o retry que criou duas sessões, o PDF que passou de 10 MB numa sexta-feira. Este guia monta a estratégia de teste em camadas — mocks para a sua lógica, sandbox para o contrato, smoke test para o pipeline — com os instrumentos específicos da SignDocs: o webhook de teste com payload assinado sob demanda, a idempotência como aliada do CI e o TTL de 7 dias como faxineiro gratuito.

A pirâmide: mock embaixo, sandbox em cima

Camada Contra o quê Quando roda Valida
Unitários Mock do SDK/cliente HTTP A cada commit, em milissegundos A sua lógica: montagem do payload, tratamento de estados e erros
Integração Sandbox real (api-hml.signdocs.com.br) Por PR ou na suíte noturna O contrato: payloads aceitos, respostas parseadas, erros RFC 7807 tratados
Smoke Sandbox real, caminho crítico No pipeline, antes do deploy Token → criar sessão → consultar → webhook de teste

Os dois extremos falham de formas opostas: mockar tudo esconde drift de contrato (a API evolui e seus mocks mentem com confiança); bater na rede em todo teste unitário deixa a suíte lenta, instável e dependente de credenciais. Cada camada no seu lugar.

O smoke test que vale a pena (4 chamadas)

# smoke.sh — roda no pipeline antes do deploy # 1. Token (valida credenciais + conectividade) TOKEN=$(curl -sf -X POST https://api-hml.signdocs.com.br/oauth2/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=client_credentials" \ -d "client_id=$SIGNDOCS_HML_CLIENT_ID" \ -d "client_secret=$SIGNDOCS_HML_CLIENT_SECRET" | jq -r .access_token) # 2. Criar sessão mínima (CLICK_ONLY + PDF de 1 página) # X-Idempotency-Key = ID do build: retry do pipeline não duplica RESP=$(curl -sf -X POST https://api-hml.signdocs.com.br/v1/signing-sessions \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -H "X-Idempotency-Key: smoke-$CI_BUILD_ID" \ -d "{ \"purpose\": \"DOCUMENT_SIGNATURE\", \"policy\": { \"profile\": \"CLICK_ONLY\" }, \"signer\": { \"name\": \"Teste CI\", \"email\": \"ci@teste.exemplo\", \"cpf\": \"12345678901\" }, \"document\": { \"content\": \"$PDF_MINIMO_B64\", \"filename\": \"smoke.pdf\" } }") TX=$(echo "$RESP" | jq -r .transactionId) # 3. Consultar (valida leitura + parsing) curl -sf https://api-hml.signdocs.com.br/v1/transactions/$TX \ -H "Authorization: Bearer $TOKEN" | jq -e '.status == "IN_PROGRESS" or .status == "CREATED" or .status == "DOCUMENT_UPLOADED"' # 4. Webhook de teste: payload ASSINADO chega ao seu endpoint curl -sf -X POST https://api-hml.signdocs.com.br/v1/webhooks/$WEBHOOK_ID/test \ -H "Authorization: Bearer $TOKEN" echo "smoke OK"

Quatro chamadas, segundos de execução, e o deploy só passa se credenciais, contrato de criação, leitura e a tubulação do webhook estiverem vivos. O X-Idempotency-Key amarrado ao ID do build é o detalhe que importa: o retry automático do pipeline reaproveita a resposta em vez de criar uma segunda sessão.

Testando o webhook: tubulação e lógica são testes diferentes

A tubulação — DNS, TLS, roteamento, verificação de assinatura, resposta 200 — se prova com o endpoint de teste: POST /v1/webhooks/{webhookId}/test envia um evento ao seu endpoint assinado com o HMAC real do seu segredo. Sem criar sessão, sem esperar ninguém assinar.

A lógica — o que o handler faz com cada evento — se prova offline, com fixtures: capture payloads reais do sandbox e teste o handler como função, cobrindo os casos que produção vai lhe entregar:

  • Assinatura HMAC inválida → 401, nada processado;
  • Timestamp fora da tolerância (replay) → rejeitado;
  • Evento duplicado (mesmo id) → ignorado com 200 — reentregas acontecem;
  • Tipo de evento desconhecido → 200 sem efeito (a API ganha eventos novos; seu handler não pode quebrar);
  • O caminho feliz de cada tipo que você trata (SIGNING_SESSION.COMPLETED, TRANSACTION.EXPIRED...).

O receptor de referência está em webhooks e eventos da API.

As regras da casa no sandbox

  • Dados fictícios, sempre: nomes, e-mails e CPFs de teste — dado pessoal real não pertence a ambiente de desenvolvimento, e e-mail real em teste dispara convite real. Use endereços que você controla.
  • Nenhum ID fixo de execuções passadas: o TTL de 7 dias apaga tudo — e testes que dependem de estado antigo são frágeis em qualquer API. Todo teste cria o que consome; o sandbox faz o teardown por você.
  • Cenário de expiração sem esperar 7 dias: crie a sessão com expiresInMinutes curto e aguarde a expiração dentro do teste.
  • Erros de propósito: teste também o que deve falhar — perfil inexistente, PDF corrompido, DIGITAL_SIGN_A1 como profile (400 garantido) — e valide que seu código trata os erros RFC 7807 pelo code, não pela mensagem. O catálogo está em códigos de erro e falhas.
  • Credenciais de HML no cofre do CI: separadas das de produção, injetadas como variáveis — nunca no repositório.
O que o sandbox não prova — e é melhor saber antes do go-live: biometria real (roda simulada em homologação; valide na ativação da conta de produção), retenção durável (TTL de 7 dias ≠ guarda de longo prazo), efeito jurídico (assinatura de teste não vale como documento) e o seu volume real (cotas se dimensionam no contrato). O checklist de ida à produção cobre a transição.

Perguntas Frequentes

Preciso mockar a API de assinatura nos meus testes?

Nas camadas certas, sim; em todas, não. A estratégia que funciona tem três andares: testes unitários mockam o SDK/cliente HTTP (rápidos, rodam a cada commit, validam a SUA lógica); testes de integração batem no sandbox real (api-hml.signdocs.com.br) e validam o contrato — payload aceito, resposta parseada, erros tratados; e um smoke test no pipeline valida o caminho crítico de ponta a ponta antes do deploy. Mockar tudo esconde drift de contrato; bater na API real em todo teste unitário deixa a suíte lenta e dependente de rede. O equilíbrio é mock embaixo, sandbox em cima.

Como testo meu handler de webhook sem esperar alguém assinar?

Dois instrumentos. O primeiro é o endpoint de teste da API: POST /v1/webhooks/{webhookId}/test dispara um evento de teste ao seu endpoint registrado, assinado com HMAC de verdade — valida o caminho completo (recepção, verificação de assinatura, resposta) sem criar sessão nenhuma. O segundo é a suíte local: guarde payloads reais capturados no sandbox como fixtures e teste o handler como função pura — assinatura válida, assinatura inválida, timestamp velho (replay), evento duplicado (idempotência), evento de tipo desconhecido. O primeiro prova a tubulação; o segundo, a lógica.

O TTL de 7 dias do sandbox quebra meus testes?

Só se os testes dependerem de entidades antigas — e essa dependência é um mau cheiro de teste de qualquer forma. A regra prática: todo teste cria o que precisa (uma sessão nova custa uma chamada) e nenhum teste referencia IDs fixos de execuções passadas. O TTL vira até um aliado: o sandbox se limpa sozinho, sem rotina de teardown. Para os raros cenários que exigem estado antigo (por exemplo, testar seu tratamento de transação expirada), crie a sessão com expiresInMinutes curto e espere a expiração dentro do próprio teste.

Posso usar dados de clientes reais nos testes de homologação?

Não use. O sandbox é ambiente de teste: use nomes, e-mails e CPFs fictícios (geradores de CPF válido para teste existem aos montes). Além da higiene LGPD óbvia — dado pessoal real não pertence a ambiente de desenvolvimento —, e-mails reais em teste disparam convites reais para caixas de entrada reais. Crie um domínio de e-mail de teste ou use endereços que você controla. A exceção honesta: no teste de aceitação final, com o time de negócio, use os dados do próprio testador — que sabe que está testando.

O que colocar no smoke test do pipeline de CI?

O caminho que, se quebrar, para o seu negócio — e só ele: (1) obter token OAuth2 (valida credenciais e conectividade); (2) criar uma sessão com um PDF mínimo e perfil CLICK_ONLY (valida o contrato de criação); (3) consultar GET /v1/transactions/{id} (valida leitura e parsing); (4) opcionalmente, disparar o webhook de teste e conferir que seu endpoint respondeu 200. Quatro chamadas, alguns segundos, roda a cada deploy. Use X-Idempotency-Key com o ID do build para que retries do pipeline não criem lixo duplicado. Testes de cenário completos ficam na suíte noturna, não no gate de deploy.

O que NÃO dá para validar no sandbox?

Quatro coisas, e é melhor saber antes: (1) biometria real — no sandbox os fluxos biométricos rodam em modo simulado por padrão; valide o fluxo end-to-end com biometria real na ativação da conta de produção; (2) retenção durável — o TTL de 7 dias significa que o sandbox nunca testa a guarda de longo prazo; (3) efeito jurídico — nenhuma assinatura de homologação vale como documento real, então o teste de aceitação jurídica é sempre um documento piloto em produção; (4) o seu volume real — cotas e comportamento sob carga se dimensionam no contrato de produção. O plano sob medida cobre esses quatro na transição.

Monte sua suíte contra o sandbox — hoje

Credenciais de homologação gratuitas, webhook de teste com payload assinado sob demanda e um sandbox que se limpa sozinho. Seu pipeline agradece.

Criar credenciais de homologação Falar com o time comercial