Assinatura eletrônica
Assinatura eletrônica
create de flow o recusa até a abertura. O contrato de resposta abaixo é o que o backend já emite, para você planejar a integração.O módulo assinatura transforma a verificação aprovada em assinatura eletrônica avançada do documento que você indicar. Você cria a sessão com o hash SHA-256 do documento; o titular passa pela verificação de identidade completa (documento, face match e prova de vida, que o flow exige junto); e, se a verificação aprovar, a plataforma emite o dossiê de assinatura: um manifesto que amarra o hash do documento à verificação aprovada e ao instante, assinado com a chave Ed25519 da plataforma. O documento em si nunca é enviado: você continua guardando os bytes, e o hash não revela o conteúdo.
// criação de sessão com o bloco assinatura (obrigatório quando o flow tem o módulo)
POST /v1/verification-sessions
{ "flow_id": "flow_...", "reference_id": "contrato-8841",
"assinatura": { "document_sha256": "f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2" } }Por link, um a um ou em lote. O link de verificação hospedado aceita o mesmo bloco assinatura em POST /v1/verification-links, e o hash fica fixo no link desde a emissão. No painel, uma planilha com reference_id e document_sha256 por linha gera um link por linha; o arquivo com os links sai uma única vez. Quem avisa o signatário é você. Para acompanhar cada etapa, o webhook do flow recebe verification_link.claimed quando o signatário abre o link e começa a verificação (um aviso por link, com link_id, session_id e o seu reference_id), e verification.completed com o dossiê quando ele assina.
// assinatura no check_details: o dossiê completo
{ "module": "assinatura", "passed": true, "outcome": "approved",
"data": { "assinatura": {
"signed": true,
"document_sha256": "f2ca1bb6...cc26fd2", // o hash que você mandou na criação
"algorithm": "Ed25519",
"key_id": "1f60c078f27b", // identifica a chave da plataforma
"public_key": "SGVsbG8t...", // chave pública, base64 (32 bytes)
"signed_at": "2026-09-07T12:00:00.000Z",
"manifest_json": "{\"v\":1,\"type\":\"unifokal/assinatura-avancada@1\",...}",
"signature": "kqYw3...==" } } } // assinatura do manifest_json, base64Qualquer pessoa confere o dossiê, sem nos consultar. A âncora é a lista de chaves públicas da UNIFOKAL logo abaixo: a chave que viaja no dossiê (public_key, com o key_id) só vale se for igual a uma chave da lista, já em vigor no instante signed_at. A assinatura cobre exatamente os bytes UTF-8 de manifest_json (use a string literal recebida, nunca uma re-serialização sua: outra ordem de campos muda os bytes). Depois, o document_sha256 do manifesto tem de ser o SHA-256 do seu contrato: se qualquer byte do documento mudar depois, o hash muda e o dossiê deixa de casar com ele. É essa a detecção de alteração posterior que a lei exige.
// chaves públicas da assinatura (Ed25519, 32 bytes em base64). A âncora é ESTA lista: // a chave que viaja no dossiê só vale se for igual a uma destas, já em vigor em signed_at. ASSINATURA_PUBLIC_KEYS = [] // A chave de produção entra nesta lista antes da abertura da venda.
// Node 20+ (só node:crypto, sem rede)
const { createPublicKey, verify, createHash } = require("node:crypto");
const SPKI = Buffer.from("302a300506032b6570032100", "hex");
function confereDossie(dossie, contrato, pinadas) {
const k = pinadas.find((p) => p.key_id === dossie.key_id && p.public_key === dossie.public_key &&
p.environment === "production" && dossie.signed_at >= p.not_before);
if (!k) return false; // chave fora da lista: o dossiê não foi emitido pela UNIFOKAL
const chave = createPublicKey({ key: Buffer.concat([SPKI, Buffer.from(k.public_key, "base64")]), format: "der", type: "spki" });
if (!verify(null, Buffer.from(dossie.manifest_json, "utf8"), chave, Buffer.from(dossie.signature, "base64"))) return false;
const m = JSON.parse(dossie.manifest_json);
return m.type === "unifokal/assinatura-avancada@1" && m.decision === "approved" &&
m.signed_at === dossie.signed_at && m.document_sha256 === dossie.document_sha256 &&
m.document_sha256 === createHash("sha256").update(contrato).digest("hex");
}Consignado do trabalhador. Desde 25 de julho de 2025, as instituições consignatárias devem adotar verificação biométrica da identidade do trabalhador nas operações de crédito consignado feitas por plataforma digital (Lei 10.820/2003, art. 2º-I, incluído pela Lei 15.179/2025), com prova de vida (Decreto 12.564/2025, art. 2º, I). O contrato digital pode ser firmado por assinatura qualificada ou por assinatura avançada, e a avançada precisa cumprir, junto com a Lei 14.063, dois requisitos: autenticação biométrica com prova de vida no ato da assinatura e geração de evidências técnicas que comprovem a autenticação e a integridade do ato, utilizáveis em processo administrativo ou judicial (Lei 10.820, art. 2º-I, § 3º, I e II; Decreto 12.564, art. 3º, II, alíneas a e b). Os dois valem para quem contrata daqui em diante por assinatura avançada que não estava homologada em 25 de julho de 2025: o § 4º do mesmo artigo considera adequadas também a avançada já homologada pelo Poder Executivo federal ou pelo Poder Judiciário naquela data e a assinatura digital nos termos do regulamento (Decreto 12.564, art. 3º, III).
O módulo entrega as duas coisas no mesmo fluxo: a verificação com documento, face match e prova de vida acontece no ato em que o trabalhador assina, e o dossiê que amarra o hash do contrato à identidade verificada e ao instante é a evidência técnica, que qualquer pessoa confere com a chave pública publicada pela UNIFOKAL, sem nos consultar. A guarda do dossiê é da consignatária: ele chega inteiro no webhook para você arquivar pelo prazo do seu contrato. Não emitimos assinatura eletrônica qualificada.
Quando não cobra. O dossiê só existe se a verificação aprovar. Verificação recusada ou em revisão devolve "signed": false com o motivo nomeado (verification_not_approved) e o módulo sai do preço daquela verificação. O bloco assinatura da criação é obrigatório quando o flow contém o módulo (422 assinatura_document_required) e recusado quando não contém (422 assinatura_not_supported): nunca aceito e ignorado em silêncio. O link hospedado não leva o documento: a emissão de link para um flow com o módulo é recusada com o mesmo 422 assinatura_document_required, e a sessão desse flow nasce pela API.
Pronto para integrar? A chave de sandbox sai no painel, logo depois do cadastro. Criar conta grátis