Guias de Desenvolvimento

Política e Conformidade

Signing Sessions

Sessão de Confiança

Modelos de Solução

Guias dos SDKs

Onboarding Digital de Colaboradores com Assinatura Eletrônica — Modelo de Solução

Transforme o processo de admissão em uma jornada 100% digital: candidato aprovado, contrato de trabalho enviado, assinado por colaborador e empresa com validade jurídica fundada na MP 2.200-2/2001, e evidência arquivada automaticamente no seu sistema de RH — tudo em horas, não em dias. O fluxo respeita a LGPD no tratamento dos dados do candidato e, quando o cenário exigir, aceita assinatura com certificado ICP-Brasil. O resultado de negócio: admissão digital sem impressão, sem motoboy e sem candidato desistindo enquanto o papel circula.

Público-alvo: times de tecnologia que atendem RH/People Ops — desenvolvedores integrando ATS, HRIS ou portal interno de admissão — e responsáveis por departamento pessoal que querem um processo de admissão automatizado.


⚡ Caminho de 15 minutos

  1. Obtenha credenciais HML no painel admin ou por contato@signdocs.com.br.
  2. Troque client_id + client_secret por um access_token em POST /oauth2/token.
  3. Crie um envelope SEQUENTIAL com totalSigners: 2 e o PDF do contrato de trabalho em POST /v1/envelopes.
  4. Adicione o colaborador (signerIndex 1) e o representante da empresa (signerIndex 2) com perfil CLICK_PLUS_OTP via POST /v1/envelopes/{envelopeId}/sessions.
  5. Assine pelos dois em HML (o código OTP vem em sandbox.otpCode), receba ENVELOPE.ALL_SIGNED e baixe o PDF com carimbo combinado + o pacote de evidências — contrato assinado e arquivado.

1. O problema de negócio

O onboarding digital de funcionários costuma travar exatamente no momento mais sensível: entre o "você foi aprovado" e o primeiro dia de trabalho. No processo em papel, o RH imprime o contrato de trabalho e o kit admissional, agenda a vinda do candidato (ou paga courier), confere assinaturas página a página, digitaliza tudo e arquiva em pastas físicas ou num drive sem trilha de auditoria. Cada admissão consome horas do departamento pessoal — e cada dia de espera aumenta o risco de o candidato aceitar outra proposta. Em admissões remotas, o papel simplesmente inviabiliza o prazo.

Com assinatura eletrônica de contrato de trabalho via API, o fluxo vira um processo de admissão automatizado: o ATS marca o candidato como aprovado, seu backend gera o envelope com o contrato, o colaborador assina pelo celular confirmando um código OTP recebido por e-mail ou SMS, a empresa contra-assina, e um webhook arquiva o PDF carimbado e o pacote de evidências no dossiê digital do colaborador. O que levava de 3 a 10 dias passa a caber no mesmo dia da aprovação.

Além da velocidade, a admissão digital entrega rastreabilidade: cada assinatura gera uma trilha de auditoria com timestamp ISO do servidor, hash SHA-256 do documento e um pacote de evidências assinado com certificado ICP-Brasil — material pronto para uma eventual fiscalização trabalhista ou disputa judicial.

Este guia vs. geração do contrato — aqui o foco é a jornada de admissão ponta a ponta (aprovação → assinatura → arquivamento, incluindo o kit admissional). Se o seu gargalo é gerar o contrato automaticamente a partir de um template com os dados do candidato, comece por Contrato de Trabalho automatizado — os dois guias se complementam.

2. Arquitetura do fluxo

ATS / Sistema de RH                           SignDocs Brasil
        │
Candidato aprovado
        │
        ├──> POST /v1/envelopes (SEQUENTIAL, totalSigners: 2) ──> envelopeId
        │
        ├──> add session 1 (colaborador, CLICK_PLUS_OTP) ──> url1 + clientSecret1
        ├──> add session 2 (empresa/RH,  CLICK_PLUS_OTP) ──> url2 + clientSecret2
        │
Colaborador assina (aceite + OTP) ─────> SIGNING_SESSION.COMPLETED ──┐
Empresa assina (liberada após o 1º) ───> SIGNING_SESSION.COMPLETED ──┤ webhooks
        │                                                            │
        │                                ENVELOPE.ALL_SIGNED ────────┘
        │
Arquivar no dossiê do colaborador:
carimbo combinado (PDF) + evidence pack (.p7m)

Por que envelope, e não outra primitiva?

Primitiva Uso neste cenário
Envelope (POST /v1/envelopes) O contrato de trabalho tem 2 signatários sobre o mesmo documento (colaborador + empresa). O envelope coordena a ordem, consolida o status e gera um PDF final com carimbo combinado.
Sessão de assinatura (POST /v1/signing-sessions) Termos do kit admissional que só o colaborador assina (confidencialidade, política de equipamentos, opção de vale-transporte). 1 signatário = 1 sessão, mais simples que envelope.
Sessão de confiança (POST /v1/trust-sessions) Aceites sem documento, como o consentimento LGPD para tratamento dos dados do candidato. Veja consentimento com sessão de confiança.

Por que SEQUENTIAL com o colaborador primeiro? Três razões práticas. Primeira: o gargalo da admissão é o candidato — dispare o link no momento do aceite da proposta e deixe o prazo de expiração correr para ele, não para o RH. Segunda: a empresa só formaliza depois que o colaborador aceitou; se o candidato desistir, você cancela o envelope sem nunca ter um contrato assinado unilateralmente pela empresa circulando. Terceira: a assinatura da empresa vira a etapa natural de conferência final do departamento pessoal antes do registro. Se a sua política interna exigir o inverso (empresa assina primeiro para o candidato receber um contrato já firmado), basta trocar os valores de signerIndex — a API aceita qualquer ordem.

3. Pré-requisitos

🟠 HML vs Produção — desenvolva sempre em HML (https://api-hml.signdocs.com.br, com hífen). Credenciais HML não consomem cota do plano, os dados expiram em 7 dias e o código OTP volta na própria resposta (sandbox.otpCode) para você testar sem e-mail/SMS reais.

4. Autenticação OAuth2

A API usa OAuth2 client_credentials (servidor-a-servidor). Troque suas credenciais por um token de acesso:

export SIGNDOCS_BASE_URL="https://api-hml.signdocs.com.br"

ACCESS_TOKEN=$(curl -s -X POST "$SIGNDOCS_BASE_URL/oauth2/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials&client_id=$SIGNDOCS_CLIENT_ID&client_secret=$SIGNDOCS_CLIENT_SECRET" \
  | jq -r '.access_token')

Com SDK, a autenticação é automática na criação do cliente:

import { SignDocsBrasilClient } from '@signdocs-brasil/api';

const client = new SignDocsBrasilClient({
  clientId: process.env.SIGNDOCS_CLIENT_ID!,
  clientSecret: process.env.SIGNDOCS_CLIENT_SECRET!,
  baseUrl: process.env.SIGNDOCS_BASE_URL, // https://api-hml.signdocs.com.br
});
import os
from signdocs_brasil import SignDocsBrasilClient, ClientConfig

client = SignDocsBrasilClient(ClientConfig(
    client_id=os.environ['SIGNDOCS_CLIENT_ID'],
    client_secret=os.environ['SIGNDOCS_CLIENT_SECRET'],
    base_url=os.environ.get('SIGNDOCS_BASE_URL', 'https://api-hml.signdocs.com.br'),
))

Detalhes de renovação e cache de token no guia de autenticação com SDK.

5. Criar o envelope do contrato de trabalho

Crie o envelope em modo SEQUENTIAL com 2 signatários. Use metadata para amarrar o envelope ao registro de admissão no seu ATS/HRIS — esses pares chave-valor voltam nos webhooks e nas consultas, dispensando tabela de-para no seu lado. expiresInMinutes: 4320 dá 3 dias para o fluxo completar (o padrão é 1440 = 24h).

PDF_BASE64=$(base64 -w0 contrato-trabalho.pdf)

curl -s -X POST "$SIGNDOCS_BASE_URL/v1/envelopes" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "signingMode": "SEQUENTIAL",
    "totalSigners": 2,
    "document": { "content": "'$PDF_BASE64'", "filename": "contrato-trabalho.pdf" },
    "metadata": {
      "admissaoId": "adm-2026-0142",
      "candidatoId": "cand-889",
      "documento": "contrato-trabalho"
    },
    "owner": { "name": "RH Empresa Exemplo", "email": "rh@empresaexemplo.com.br" },
    "returnUrl": "https://rh.empresaexemplo.com.br/admissao/adm-2026-0142/ok",
    "locale": "pt-BR",
    "expiresInMinutes": 4320
  }'
import { readFileSync } from 'fs';

const pdfBase64 = readFileSync('contrato-trabalho.pdf').toString('base64');

const envelope = await client.envelopes.create({
  signingMode: 'SEQUENTIAL',
  totalSigners: 2,
  document: { content: pdfBase64, filename: 'contrato-trabalho.pdf' },
  metadata: {
    admissaoId: 'adm-2026-0142',
    candidatoId: 'cand-889',
    documento: 'contrato-trabalho',
  },
  owner: { name: 'RH Empresa Exemplo', email: 'rh@empresaexemplo.com.br' },
  returnUrl: 'https://rh.empresaexemplo.com.br/admissao/adm-2026-0142/ok',
  locale: 'pt-BR',
  expiresInMinutes: 4320,
});
console.log('Envelope ID:', envelope.envelopeId);
import base64
from signdocs_brasil.models import CreateEnvelopeRequest

with open('contrato-trabalho.pdf', 'rb') as f:
    pdf_base64 = base64.b64encode(f.read()).decode()

envelope = client.envelopes.create(CreateEnvelopeRequest(
    signing_mode='SEQUENTIAL',
    total_signers=2,
    document_content=pdf_base64,
    document_filename='contrato-trabalho.pdf',
    metadata={
        'admissaoId': 'adm-2026-0142',
        'candidatoId': 'cand-889',
        'documento': 'contrato-trabalho',
    },
    return_url='https://rh.empresaexemplo.com.br/admissao/adm-2026-0142/ok',
    locale='pt-BR',
    expires_in_minutes=4320,
))
print('Envelope ID:', envelope.envelope_id)

A resposta traz envelopeId, status, o documentHash (SHA-256 do PDF) e expiresAt. Guarde o envelopeId no registro de admissão.

Dica — owner envia os convites por você. Quando a requisição inclui owner.email diferente do e-mail do signatário, a SignDocs envia automaticamente o e-mail de convite a cada signatário e notifica o solicitante a cada conclusão. Se preferir entregar o link pelos seus próprios canais (portal do candidato, WhatsApp via automação), omita owner.

6. Adicionar colaborador e empresa como signatários

Adicione as duas sessões ao envelope. Em modo SEQUENTIAL, signerIndex define a ordem: o colaborador (1) assina primeiro; a sessão da empresa (2) só é liberada depois. O perfil CLICK_PLUS_OTP exige signer.email — ou signer.phone em formato E.164 com otpChannel: "sms" se o colaborador for receber o código por SMS.

# Signatário 1 — colaborador (assina primeiro)
curl -s -X POST "$SIGNDOCS_BASE_URL/v1/envelopes/$ENVELOPE_ID/sessions" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "signer": {
      "name": "João da Silva",
      "cpf": "12345678901",
      "email": "joao.silva@gmail.com",
      "phone": "+5511999998888",
      "otpChannel": "email",
      "userExternalId": "cand-889"
    },
    "policy": { "profile": "CLICK_PLUS_OTP" },
    "purpose": "DOCUMENT_SIGNATURE",
    "signerIndex": 1
  }'

# Signatário 2 — representante da empresa (assina após o colaborador)
curl -s -X POST "$SIGNDOCS_BASE_URL/v1/envelopes/$ENVELOPE_ID/sessions" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "signer": {
      "name": "Maria Souza",
      "cpf": "98765432109",
      "email": "maria.souza@empresaexemplo.com.br",
      "userExternalId": "rh-usr-12"
    },
    "policy": { "profile": "CLICK_PLUS_OTP" },
    "purpose": "DOCUMENT_SIGNATURE",
    "signerIndex": 2
  }'
// 1. Colaborador — assina primeiro
const sessaoColaborador = await client.envelopes.addSession(envelope.envelopeId, {
  signer: {
    name: 'João da Silva',
    cpf: '12345678901',
    email: 'joao.silva@gmail.com',
    phone: '+5511999998888',
    otpChannel: 'email',
    userExternalId: 'cand-889',
  },
  policy: { profile: 'CLICK_PLUS_OTP' },
  purpose: 'DOCUMENT_SIGNATURE',
  signerIndex: 1,
});

// 2. Representante da empresa — assina após o colaborador
const sessaoEmpresa = await client.envelopes.addSession(envelope.envelopeId, {
  signer: {
    name: 'Maria Souza',
    cpf: '98765432109',
    email: 'maria.souza@empresaexemplo.com.br',
    userExternalId: 'rh-usr-12',
  },
  policy: { profile: 'CLICK_PLUS_OTP' },
  purpose: 'DOCUMENT_SIGNATURE',
  signerIndex: 2,
});

console.log('URL colaborador:', sessaoColaborador.url);
console.log('URL empresa:', sessaoEmpresa.url);
from signdocs_brasil.models import AddEnvelopeSessionRequest

# 1. Colaborador — assina primeiro
sessao_colaborador = client.envelopes.add_session(envelope.envelope_id, AddEnvelopeSessionRequest(
    signer_name='João da Silva',
    signer_cpf='12345678901',
    signer_email='joao.silva@gmail.com',
    signer_phone='+5511999998888',
    signer_otp_channel='email',
    signer_user_external_id='cand-889',
    policy_profile='CLICK_PLUS_OTP',
    purpose='DOCUMENT_SIGNATURE',
    signer_index=1,
))

# 2. Representante da empresa — assina após o colaborador
sessao_empresa = client.envelopes.add_session(envelope.envelope_id, AddEnvelopeSessionRequest(
    signer_name='Maria Souza',
    signer_cpf='98765432109',
    signer_email='maria.souza@empresaexemplo.com.br',
    signer_user_external_id='rh-usr-12',
    policy_profile='CLICK_PLUS_OTP',
    purpose='DOCUMENT_SIGNATURE',
    signer_index=2,
))

print('URL colaborador:', sessao_colaborador.url)
print('URL empresa:', sessao_empresa.url)

Dica — deixe o colaborador escolher o canal do OTP. Com otpChannelSelectable: true no signer, a tela de assinatura hospedada permite ao signatário alternar entre e-mail e SMS na hora de receber o código — útil quando o candidato preencheu o cadastro com um e-mail que consulta pouco.

Cada sessão retorna url e clientSecret. A url sozinha não abre a tela de assinatura: o link entregue ao signatário é a combinação dos dois:

LINK_COLABORADOR="${SESSION_URL}?cs=${CLIENT_SECRET}"
const linkColaborador = `${sessaoColaborador.url}?cs=${sessaoColaborador.clientSecret}`;
const linkEmpresa = `${sessaoEmpresa.url}?cs=${sessaoEmpresa.clientSecret}`;
link_colaborador = f'{sessao_colaborador.url}?cs={sessao_colaborador.client_secret}'
link_empresa = f'{sessao_empresa.url}?cs={sessao_empresa.client_secret}'

Como o exemplo acima incluiu owner, o convite por e-mail já foi disparado automaticamente para o colaborador (o representante do RH, cujo e-mail difere do owner.email, também recebe o dele). Alternativas de entrega:

⚠️ O clientSecret é de uso único e não pode ser recuperado depois. Persista o link montado (ou entregue-o imediatamente); se perder, cancele a sessão e crie outra. E nunca logue o clientSecret no seu backend.

8. Acompanhar e arquivar a admissão

Enquanto o fluxo corre, consulte o envelope para alimentar a linha do tempo da admissão no seu sistema de RH (em produção, prefira webhooks — próxima seção):

curl -s "$SIGNDOCS_BASE_URL/v1/envelopes/$ENVELOPE_ID" \
  -H "Authorization: Bearer $ACCESS_TOKEN"

Quando todos assinarem, gere o carimbo combinado (PDF final com as duas assinaturas) e baixe o pacote de evidências para o dossiê digital do colaborador:

# PDF final com carimbo combinado
curl -s -X POST "$SIGNDOCS_BASE_URL/v1/envelopes/$ENVELOPE_ID/combined-stamp" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
# → { "downloadUrl": "...", "signerCount": 2 }
import { writeFileSync } from 'fs';

let detail = await client.envelopes.get(envelope.envelopeId);
while (detail.status !== 'COMPLETED') {
  console.log(`Progresso: ${detail.completedSessions}/${detail.totalSigners}`);
  await new Promise(r => setTimeout(r, 5000));
  detail = await client.envelopes.get(envelope.envelopeId);
}

const stamp = await client.envelopes.combinedStamp(envelope.envelopeId);
const res = await fetch(stamp.downloadUrl);
writeFileSync('contrato-trabalho-assinado.pdf', Buffer.from(await res.arrayBuffer()));
console.log('Contrato assinado arquivado.');
import time
from pathlib import Path
import httpx

detail = client.envelopes.get(envelope.envelope_id)
while detail.status != 'COMPLETED':
    print(f'Progresso: {detail.completed_sessions}/{detail.total_signers}')
    time.sleep(5)
    detail = client.envelopes.get(envelope.envelope_id)

stamp = client.envelopes.combined_stamp(envelope.envelope_id)
pdf = httpx.get(stamp.download_url).content
Path('contrato-trabalho-assinado.pdf').write_bytes(pdf)
print('Contrato assinado arquivado.')

Cada sessão concluída também expõe um evidenceId. O pacote de evidências é um JSON assinado em PKCS#7/CMS (.p7m) com certificado ICP-Brasil A1, contendo a trilha de auditoria, timestamps ISO do servidor e o hash SHA-256 do documento. Arquive o .p7m junto do PDF no dossiê; qualquer pessoa pode conferi-lo depois via GET /v1/verify/{evidenceId} ou POST /v1/verify/document.

9. O kit admissional: múltiplos termos

Uma admissão raramente é só o contrato de trabalho. O kit admissional típico inclui termo de confidencialidade, política de uso de equipamentos, acordo de teletrabalho, opção de vale-transporte e o consentimento LGPD. Hoje, cada documento é um envelope ou sessão separado — não há envelope multi-documento. Na prática isso é simples de orquestrar:

Use a mesma chave metadata.admissaoId em todos os envelopes e sessões da admissão. Ao receber cada webhook, seu handler agrupa tudo pelo admissaoId e marca a admissão como completa quando todos os itens do kit estiverem assinados — o "envelope lógico" fica no seu domínio.

Dica — dispare primeiro só o contrato e libere o restante do kit no webhook de conclusão dele. O candidato encara um documento por vez (menos abandono) e você não gasta sessões de termos acessórios com quem desistiu no contrato principal.


Webhooks: reagindo à conclusão

Registre um webhook para não depender de polling. Para o onboarding, dois eventos importam:

Evento Papel no fluxo de admissão
SIGNING_SESSION.COMPLETED Progresso: atualize a linha do tempo no RH ("colaborador assinou, aguardando empresa") e dispare o próximo item do kit.
ENVELOPE.ALL_SIGNED Conclusão: gere o carimbo combinado, baixe o .p7m e arquive tudo no dossiê digital do colaborador.
curl -s -X POST "$SIGNDOCS_BASE_URL/v1/webhooks" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://rh.empresaexemplo.com.br/webhooks/signdocs",
    "events": ["SIGNING_SESSION.COMPLETED", "ENVELOPE.ALL_SIGNED", "ENVELOPE.EXPIRED"]
  }'

Inclua ENVELOPE.EXPIRED para tratar o caso do candidato que nunca assinou — notifique o recrutador antes que a vaga esfrie. Todo payload chega assinado com HMAC-SHA256 (headers X-SignDocs-Signature e X-SignDocs-Timestamp); valide a assinatura antes de processar e responda 200 rápido. Especificação completa, verificação HMAC e política de reentrega em webhooks; handlers prontos nos SDKs.

⚠️ A URL do webhook precisa ser pública e HTTPS. URLs localhost ou de IP privado são bloqueadas na borda (403). Em desenvolvimento, use um túnel (ngrok, Cloudflare Tunnel) ou webhook.site.

Escolhendo o perfil de política

Perfil Como o colaborador assina Quando usar na admissão
CLICK_ONLY Um clique de aceite Termos acessórios de baixo risco (ex.: política de uso de equipamentos).
CLICK_PLUS_OTP Aceite + código OTP por e-mail ou SMS Recomendado para o contrato de trabalho e o kit admissional.
BIOMETRIC_PLUS_OTP Verificação facial + OTP Cargos sensíveis, alto volume de admissão remota com risco de fraude de identidade, ou exigência do jurídico.
DIGITAL_CERTIFICATE Certificado digital ICP-Brasil (e-CPF) Quando a política interna exige ICP-Brasil — na prática, mais comum para o representante da empresa que já possui e-CPF/e-CNPJ.

CLICK_PLUS_OTP é o default recomendado porque adiciona a posse de um canal verificado (a caixa de e-mail ou o número de celular que o próprio candidato informou no recrutamento) por cima do aceite, sem exigir que o recém-contratado tenha certificado digital ou passe por captura facial — atrito mínimo com prova de autoria substancialmente melhor que o clique puro. Quando subir de nível: se a admissão é 100% remota e você nunca encontrará o colaborador presencialmente, ou se o cargo dá acesso a dados/valores sensíveis desde o primeiro dia, use BIOMETRIC_PLUS_OTP para o contrato principal (exige signer.cpf). Os perfis podem ser diferentes por signatário no mesmo envelope — por exemplo, colaborador com BIOMETRIC_PLUS_OTP e empresa com DIGITAL_CERTIFICATE. Fundamentos jurídicos de cada nível em perfis de assinatura e níveis legais.

Caminho sem código

Agente de IA com o servidor MCP. O servidor MCP da SignDocs (@signdocs-brasil/mcp-server) expõe as operações da API — criar envelope, adicionar signatários, registrar webhook, baixar evidência — como ferramentas para agentes de IA (Claude e outros clientes MCP). Um agente conectado ao MCP consegue automatizar a ponta mais manual do processo de admissão: ler o e-mail ou a ficha do candidato aprovado, extrair nome, CPF, e-mail e celular, montar o envelope sequencial do contrato e disparar os convites — com o RH apenas revisando antes do envio. Configure com suas credenciais HML primeiro e promova a produção depois de validar o fluxo.

n8n. Para o pipeline completo "aprovado no ATS → contrato gerado → assinatura", importe o template n8n que gera o contrato a partir de um template Google Docs com os dados do candidato e cria o fluxo de assinatura na SignDocs. Detalhes do node em integração n8n. Para entregar o link por WhatsApp/Telegram, há também o template n8n de entrega.

Zapier. Conecte gatilhos do seu ATS (BambooHR, Gupy via webhook, Google Forms) à ação de criação de envelope e reaja aos eventos de conclusão para atualizar planilhas e avisar o Slack do RH — veja integração Zapier.

Make. Cenários equivalentes com os módulos de envelope e o trigger instantâneo de eventos — veja integração Make.

Erros comuns

1. OTP sem canal: signer.email ausente com CLICK_PLUS_OTP

{
  "type": "https://api.signdocs.com.br/errors/bad-request",
  "title": "Bad Request",
  "status": 400,
  "detail": "signer.email é obrigatório para etapas OTP (ou informe signer.phone com otpChannel=sms)."
}

Correção: informe signer.email, ou signer.phone em E.164 (+5511999998888) com otpChannel: "sms".

2. signer.cpf/cnpj ausente

{
  "type": "https://api.signdocs.com.br/errors/bad-request",
  "title": "Bad Request",
  "status": 400,
  "detail": "É obrigatório informar pelo menos um entre signer.cpf e signer.cnpj."
}

Correção: todo signatário precisa de cpf (11 dígitos, sem pontuação) ou cnpj (14 dígitos). Para admissão, use o CPF do colaborador.

3. Perfil de política inválido: DIGITAL_SIGN_A1 como policy.profile

{
  "type": "https://api.signdocs.com.br/errors/bad-request",
  "title": "Bad Request",
  "status": 400,
  "detail": "policy.profile inválido. Valores aceitos: CLICK_ONLY, CLICK_PLUS_OTP, BIOMETRIC, BIOMETRIC_PLUS_OTP, DIGITAL_CERTIFICATE, CUSTOM."
}

Correção: DIGITAL_SIGN_A1 é um tipo de etapa que aparece nas respostas, não um perfil de política. Para exigir certificado ICP-Brasil, use policy.profile: "DIGITAL_CERTIFICATE".

4. Link de assinatura "não funciona"

Sintoma: o signatário abre a url e a tela não carrega a sessão. Causa: o link foi entregue sem o clientSecret. Monte sempre url + "?cs=" + clientSecret — e lembre que o clientSecret é de uso único e não pode ser reobtido; se perdido, cancele e recrie a sessão.

5. Webhook devolve 403 no registro

Sintoma: POST /v1/webhooks com URL http://localhost:3000/... ou IP privado retorna 403 na borda (CloudFront), antes de chegar à API. Correção: use uma URL HTTPS pública — em desenvolvimento, um túnel (ngrok/Cloudflare Tunnel) ou webhook.site.

Perguntas frequentes

Contrato de trabalho assinado eletronicamente tem validade jurídica?

Sim. A assinatura eletrônica de contrato de trabalho tem validade fundada na MP 2.200-2/2001, art. 10 §2º, que reconhece assinaturas eletrônicas quando as partes admitem o meio como válido. O pacote de evidências da SignDocs (trilha de auditoria, timestamps do servidor, hash SHA-256, tudo assinado com certificado ICP-Brasil) documenta autoria e integridade. Detalhes por perfil em perfis de assinatura e níveis legais.

Preciso de certificado ICP-Brasil para a admissão digital?

Não. Para contratos de trabalho, o perfil CLICK_PLUS_OTP (assinatura eletrônica com verificação por código) é amplamente utilizado e juridicamente amparado pela MP 2.200-2/2001. O perfil DIGITAL_CERTIFICATE (ICP-Brasil) fica disponível quando a política interna da empresa exigir — inclusive só para o signatário da empresa.

Posso enviar todo o kit admissional em um único envelope?

Hoje não — cada envelope carrega um documento, e cada termo individual do colaborador é uma sessão própria. Crie um envelope/sessão por documento e agrupe todos com a mesma chave metadata.admissaoId; seu webhook consolida o status do kit no sistema de RH (veja a seção "O kit admissional" acima).

O colaborador pode receber o código OTP por SMS em vez de e-mail?

Sim. Informe signer.phone em formato E.164 e otpChannel: "sms". Com otpChannelSelectable: true, o próprio signatário escolhe (e pode trocar) o canal na tela de assinatura.

Você controla com expiresInMinutes na criação do envelope (padrão 1440 = 24h; o exemplo deste guia usa 4320 = 3 dias). Expirado o envelope com assinatura pendente, o evento ENVELOPE.EXPIRED avisa seu sistema para reabrir o fluxo com o candidato.

Como integro com meu ATS ou sistema de RH sem desenvolver tudo?

Três caminhos: o servidor MCP para agentes de IA que orquestram a admissão, o node n8n com o template de contrato via Google Docs, ou os apps Zapier e Make conectando o ATS diretamente ao fluxo de assinatura.

Próximos passos