OTP na Assinatura: E-mail, SMS e a Escolha do Canal pelo Signatário via API
O código de uso único (OTP) é o degrau mais usado acima do clique simples: ele prova que quem está assinando tem acesso a um canal que pertence ao signatário, seja a caixa de e-mail, seja o número de celular. Este guia explica como a API da SignDocs Brasil entrega o OTP, quais perfis o exigem, como deixar o signatário escolher o canal na própria página de assinatura com otpChannelSelectable, o que acontece no reenvio e o que fica registrado como evidência.
Tudo o que está descrito aqui é o comportamento atual do fluxo hospedado e dos endpoints, incluindo os limites que você vai encontrar em produção: validade de 10 minutos por código e intervalo mínimo de 60 segundos entre reenvios. Se você ainda está escolhendo o nível de autenticação para cada tipo de documento, comece pelo panorama em autenticação multimétodo e volte aqui para os detalhes do OTP.
Quais perfis usam OTP
O OTP não é um recurso avulso: ele é uma etapa que alguns perfis de política (policy.profile) incluem na sequência de assinatura. Dois perfis o exigem:
| Perfil | Etapas executadas | O que o OTP adiciona |
|---|---|---|
CLICK_PLUS_OTP |
Aceite por clique, envio do código, verificação do código | Posse do canal (e-mail ou celular) além do consentimento |
BIOMETRIC_PLUS_OTP |
Prova de vida, comparação facial, envio do código, verificação do código | Posse do canal somada à verificação de que há uma pessoa real com aquele rosto |
Nos demais perfis (CLICK_ONLY, BIOMETRIC, BIOMETRIC_DOCUMENT_FALLBACK, BIOMETRIC_SERPRO, BIOMETRIC_SERPRO_AUTO_FALLBACK, DIGITAL_CERTIFICATE) não há etapa de código. A escolha é por signatário, no momento da criação da sessão ou de cada sessão de um envelope, então o mesmo documento pode ter um signatário com OTP e outro com certificado digital.
Como o código é entregue
Quando o signatário chega à etapa de OTP na página hospedada, a plataforma gera um código e o envia por um dos dois canais suportados:
- E-mail, para o endereço informado em
signer.emailna criação da sessão. É o canal padrão e está sempre disponível quando existe e-mail. - SMS, para o telefone informado no cadastro do signatário, quando habilitado no contrato. O SMS depende de duas condições: o signatário ter um número de celular registrado na sessão e o envio por SMS estar ativado para a sua credencial. Sem uma das duas, o canal simplesmente não aparece.
WhatsApp não é canal de OTP. O que muitas integrações fazem é entregar o link de assinatura pelo WhatsApp e deixar o OTP correr por e-mail ou SMS; são coisas diferentes, e a segunda é a que conta como fator de autenticação registrado.
Validade e reenvio. Cada código vale por 10 minutos. O signatário pode pedir um novo código na própria página, mas o reenvio respeita um intervalo mínimo de 60 segundos: uma solicitação antes disso recebe 409 com a mensagem "Aguarde Ns antes de reenviar", em que N é o tempo restante. Esses limites são fixos da plataforma e não precisam de configuração.
Deixando o signatário escolher o canal
Por padrão, a plataforma escolhe o canal com base no que existe no cadastro do signatário. Há casos, porém, em que quem sabe qual canal funciona melhor é a própria pessoa: o e-mail corporativo com filtro agressivo de spam, o celular sem sinal no interior, o número antigo que ainda consta no cadastro. Para isso existe o campo signer.otpChannelSelectable.
Quando ele é true na criação da sessão, a página hospedada exibe um seletor de canal antes de enviar o código. O seletor só aparece se houver pelo menos dois canais disponíveis para aquele signatário: e-mail (quando há e-mail) e SMS (quando há telefone e o SMS está habilitado no contrato). Com um único canal disponível, o campo não tem efeito e o código segue pelo canal existente.
A resposta é a mesma de qualquer sessão: sessionId, transactionId, status: "ACTIVE", a url da página hospedada, o clientSecret e o expiresAt. O link entregue ao signatário continua sendo url?cs=clientSecret. O que muda é só a experiência na página: a pessoa vê "receber o código por e-mail" ou "por SMS", escolhe, e o código sai pelo canal escolhido.
Trocando de canal no reenvio
A escolha não é definitiva. Se o código não chegou pelo e-mail, o signatário pode pedir o reenvio e, no mesmo gesto, mudar para o SMS (ou o contrário). A troca no reenvio só é aceita quando a sessão foi criada com otpChannelSelectable: true; em sessões sem esse campo, o reenvio repete o canal original. O intervalo de 60 segundos vale igualmente para a troca.
Em envelopes, o campo vai no corpo de cada POST /v1/envelopes/{id}/sessions, dentro de signer, junto do signerIndex. Isso permite, por exemplo, oferecer a escolha ao cliente final e fixar o e-mail para o representante da sua empresa.
O fluxo completo, do ponto de vista do signatário
Vale percorrer o caminho inteiro uma vez, porque é ele que o seu suporte vai precisar explicar quando alguém ligar dizendo que "o código não veio". Com CLICK_PLUS_OTP e o seletor ativo, a sequência na página hospedada é esta:
- Abertura do link. O signatário abre
url?cs=clientSecretno navegador do celular ou do computador. Não há conta nem senha: o link é a porta de entrada, e é por isso que ele deve ser entregue por um canal em que a pessoa já esteja identificada. - Confirmação de identidade declarada. A página mostra o nome do signatário e pede a confirmação de que é ele. Em seguida vem o aceite dos termos de uso do signatário e do tratamento de dados.
- Leitura e aceite do documento. O PDF é exibido; o signatário rola até o fim e clica em concordar. Esse é o consentimento em si, registrado com data, hora, IP e dispositivo.
- Escolha do canal. Com o seletor ativo e dois canais disponíveis, a página pergunta por onde enviar o código. Sem seletor, o envio vai direto pelo canal existente.
- Código e verificação. O signatário digita o código de uso único recebido. Acertou dentro dos 10 minutos: a etapa fecha e a assinatura é concluída. Errou ou o código expirou: pede outro, respeitando o intervalo de 60 segundos, podendo trocar o canal.
- Conclusão. A plataforma finaliza a transação, dispara
SIGNING_SESSION.COMPLETEDpara o seu webhook e, se houverreturnUrl, redireciona o signatário para lá comsession_idanexado. O redirecionamento é conveniência de navegação; a prova de que a assinatura aconteceu é o webhook ou a consulta emGET /v1/transactions/{id}.
Para o seu sistema, o que importa desse roteiro é que o OTP acontece depois do aceite do documento e antes da conclusão. Um signatário que abriu o link, leu e concordou, mas não completou o código, deixa a sessão em ACTIVE e a transação em andamento; nada foi assinado ainda, e o webhook de conclusão não é disparado. É nesse ponto que reenviar o convite (POST /v1/signing-sessions/{id}/resend-invite) faz sentido, se a pessoa perdeu o link.
Quando faz sentido ligar o seletor
O seletor é uma decisão de conversão, não de segurança: os dois canais têm o mesmo peso como evidência de posse. Ligue quando:
- O público assina majoritariamente pelo celular e o e-mail é secundário (vendas B2C, serviços, locação).
- Você já registra telefone e e-mail no cadastro e não quer apostar em qual está atualizado.
- Há histórico de códigos "que não chegaram" e o suporte gasta tempo com isso.
Mantenha desligado quando o seu processo exige que o código vá por um canal específico por política interna (por exemplo, sempre o e-mail corporativo registrado no contrato) ou quando você mesmo informa apenas um canal e prefere que a página não ofereça uma escolha que não existe.
O que fica registrado como evidência
A etapa de OTP grava, na trilha de auditoria da transação, o que um terceiro precisaria para reconstruir o que aconteceu:
| Registro | Conteúdo |
|---|---|
| Início da etapa | Evento STEP.STARTED da etapa de envio do código, com data e hora em UTC |
| Canal utilizado | E-mail ou SMS, incluindo o canal escolhido quando o seletor estava ativo |
| Verificação | Resultado da conferência do código (STEP.COMPLETED ou STEP.FAILED), com data e hora |
| Contexto do signatário | IP, geolocalização, user-agent e carimbos de data e hora em UTC, como em toda etapa |
O código em si não é evidência e não aparece na trilha depois de usado; o que vale é o par "código enviado para este canal, código correto informado neste instante, a partir deste dispositivo". Ao final da assinatura, tudo isso compõe o pacote de evidências .p7m da transação (GET /v1/transactions/{id}/evidence), documentado em evidence pack .p7m. Os eventos STEP.* chegam ao seu webhook se você os assinou; o catálogo está em webhooks e eventos.
Tratando os erros mais comuns
- 409 no reenvio. É o intervalo de 60 segundos. A página hospedada já mostra a contagem; se a sua integração dispara reenvios pelo próprio fluxo, respeite a mensagem "Aguarde Ns" em vez de repetir a chamada.
- Código expirado. Passados 10 minutos, o código informado é rejeitado. O signatário pede um novo; a sessão continua ativa até o
expiresAt(72 horas por padrão), então expirar um código não invalida o link. - Seletor não aparece. Quase sempre é um canal só disponível: falta o telefone no cadastro ou o SMS não está habilitado no contrato. Confira os dois antes de abrir chamado.
- E-mail "não chegou". Verifique a caixa de spam e o endereço em
signer.email. Se o seletor estiver ativo, a troca para SMS resolve na hora, sem nova sessão.
Os códigos de erro e o formato RFC 7807 das respostas estão em códigos de erro e tratamento de falhas; os tropeços de integração que vemos com mais frequência, em erros comuns.
Quando o OTP não basta
O OTP responde a uma pergunta precisa: quem assinou tinha acesso ao canal do signatário? Ele não responde quem é a pessoa. Um celular clonado por SIM swap ou uma caixa de e-mail invadida recebem o código normalmente, e a evidência apontaria para a vítima. Por isso o OTP é a escolha certa para aceites, termos e contratos de risco moderado, e insuficiente sozinho quando o custo de assinar com a pessoa errada é alto.
Nesses casos, suba um degrau: BIOMETRIC_PLUS_OTP mantém o código e acrescenta prova de vida e comparação facial; os perfis com SERPRO cruzam o rosto com as bases governamentais; DIGITAL_CERTIFICATE usa o certificado ICP-Brasil do signatário (A1 diretamente na página; A3 por meio do assinador SignDocs). A comparação entre todos os degraus, com o que cada um registra, está em autenticação multimétodo.
Testando no sandbox
No ambiente de homologação (api-hml.signdocs.com.br, gratuito e sem cartão), o fluxo de OTP é o mesmo de produção, o que permite validar o seletor de canal, o intervalo de reenvio e a expiração do código com dados de teste. Crie uma sessão CLICK_PLUS_OTP com otpChannelSelectable: true, abra o link, escolha o canal, deixe o código expirar de propósito e confirme que o reenvio antes de 60 segundos devolve 409. Depois assine os eventos STEP.* num webhook de teste e confira o que chega. O roteiro completo de testes está em testar a integração no sandbox e no CI.
Perguntas Frequentes
Quais perfis da API exigem OTP?
Dois: CLICK_PLUS_OTP (aceite por clique seguido do envio e da verificação do código) e BIOMETRIC_PLUS_OTP (prova de vida e comparação facial seguidas do código). Nos demais perfis não há etapa de OTP. O perfil é definido por signatário em policy.profile, na criação da sessão ou de cada sessão do envelope, então um mesmo documento pode combinar um signatário com OTP e outro com certificado digital ou biometria. O panorama de todos os perfis está em autenticação multimétodo.
Por quais canais o código pode ser enviado?
Por e-mail, para o endereço informado em signer.email, e por SMS, para o telefone registrado no cadastro do signatário, quando o envio por SMS está habilitado no contrato. O SMS depende dessas duas condições ao mesmo tempo; faltando uma, o canal não é oferecido. WhatsApp não é canal de OTP: ele pode transportar o link de assinatura, mas o código segue por e-mail ou SMS, e é esse envio que fica registrado como fator de autenticação na trilha de auditoria.
O que faz o campo otpChannelSelectable?
Quando signer.otpChannelSelectable é true na criação da sessão, a página hospedada exibe um seletor para o signatário escolher entre e-mail e SMS antes de receber o código. O seletor só aparece se houver pelo menos dois canais disponíveis para aquela pessoa. A escolha é feita no aceite e pode ser trocada no reenvio, sem criar nova sessão. Em envelopes, o campo vai dentro de signer em cada POST /v1/envelopes/{id}/sessions, o que permite oferecer a escolha a um signatário e fixar o canal para outro.
Por quanto tempo o código vale e com que frequência posso reenviar?
Cada código vale por 10 minutos. O reenvio respeita um intervalo mínimo de 60 segundos: uma solicitação antes disso recebe 409 com a mensagem "Aguarde Ns antes de reenviar". Um código expirado não invalida o link: a sessão continua ativa até o expiresAt (72 horas por padrão) e o signatário simplesmente pede um novo código. Esses limites são fixos da plataforma e valem igualmente em homologação e em produção.
O que fica registrado como evidência da etapa de OTP?
O início da etapa de envio (STEP.STARTED), o canal utilizado (e-mail ou SMS, incluindo o escolhido pelo signatário quando o seletor estava ativo), o resultado da verificação do código (STEP.COMPLETED ou STEP.FAILED) e o contexto do signatário: IP, geolocalização, user-agent e carimbos de data e hora em UTC. O código em si não é armazenado como evidência depois de usado. Tudo isso compõe o pacote de evidências .p7m da transação, disponível em GET /v1/transactions/{id}/evidence.
OTP é suficiente para qualquer documento?
Não. O OTP prova posse de um canal, não a identidade da pessoa: um celular clonado ou um e-mail invadido recebem o código normalmente. Para aceites, termos e contratos de risco moderado ele equilibra bem conversão e evidência. Quando o custo de assinar com a pessoa errada é alto, suba um degrau: BIOMETRIC_PLUS_OTP acrescenta prova de vida e comparação facial, os perfis com SERPRO cruzam o rosto com bases governamentais e DIGITAL_CERTIFICATE usa o certificado ICP-Brasil do signatário (A1 na página; A3 por meio do assinador SignDocs).
Teste o OTP com escolha de canal no sandbox
Crie uma sessão CLICK_PLUS_OTP com otpChannelSelectable no ambiente de homologação gratuito, veja o seletor na página hospedada e confira o que chega no seu webhook. Para SMS em produção e volumes, o time comercial dimensiona o plano sob medida.
Criar credenciais de homologação Fale com o time comercial