Guias de Desenvolvimento

Signing Sessions

Guias dos SDKs

Verificação Biométrica (BIOMETRIC)

O perfil BIOMETRIC adiciona prova de vida (liveness) e comparação facial (match) antes do aceite. Garante que a pessoa que está assinando é quem diz ser.

Etapas geradas: BIOMETRIC_LIVENESS, BIOMETRIC_MATCH, CLICK_ACCEPT


Passo 1: Criar transação

const tx = await client.transactions.create({
  purpose: 'DOCUMENT_SIGNATURE',
  policy: { profile: 'BIOMETRIC' },
  signer: {
    name: 'João Silva',
    email: 'joao@example.com',
    userExternalId: 'user-001',
  },
  document: {
    content: pdfBase64,
    filename: 'contrato.pdf',
  },
});
tx = client.transactions.create(CreateTransactionRequest(
    purpose='DOCUMENT_SIGNATURE',
    policy=Policy(profile='BIOMETRIC'),
    signer=Signer(name='João Silva', email='joao@example.com', user_external_id='user-001'),
    document=InlineDocument(content=pdf_base64, filename='contrato.pdf'),
))
tx, _ := client.Transactions.Create(ctx, &signdocs.CreateTransactionRequest{
    Purpose: signdocs.TransactionPurposeDocumentSignature,
    Policy:  signdocs.Policy{Profile: signdocs.PolicyProfileBiometric},
    Signer: signdocs.Signer{
        Name: "João Silva", Email: "joao@example.com", UserExternalID: "user-001",
    },
    Document: &signdocs.DocumentInline{Content: pdfBase64, Filename: "contrato.pdf"},
})
CreateTransactionRequest request = new CreateTransactionRequest();
request.purpose = "DOCUMENT_SIGNATURE";
request.policy = new Policy("BIOMETRIC");
request.signer = new Signer("João Silva", "joao@example.com", "user-001");
request.document = new CreateTransactionRequest.InlineDocument(pdfBase64, "contrato.pdf");

Transaction tx = client.transactions().create(request);
$tx = $client->transactions->create(new CreateTransactionRequest(
    purpose: 'DOCUMENT_SIGNATURE',
    policy: new Policy(profile: 'BIOMETRIC'),
    signer: new Signer(name: 'João Silva', email: 'joao@example.com', userExternalId: 'user-001'),
    document: ['content' => $pdfBase64, 'filename' => 'contrato.pdf'],
));

Passo 2: Listar etapas

Ordem Tipo Descrição
1 BIOMETRIC_LIVENESS Prova de vida — verifica que é uma pessoa real
2 BIOMETRIC_MATCH Comparação facial — verifica identidade
3 CLICK_ACCEPT Aceite por clique
steps = list(transactionId)
// steps[0].type = BIOMETRIC_LIVENESS
// steps[1].type = BIOMETRIC_MATCH
// steps[2].type = CLICK_ACCEPT

Passo 3: Iniciar BIOMETRIC_LIVENESS

Dois modos de captura disponíveis:

Modo Descrição Retorno
BANK_APP Captura via app nativo (SDK mobile) livenessSessionId
HOSTED_PAGE Página web hospedada pela SignDocsBrasil hostedUrl
const livenessStart = await client.steps.start(tx.transactionId, steps[0].stepId, {
  captureMode: 'HOSTED_PAGE',
});
console.log(livenessStart.hostedUrl);       // URL da página de captura
// ou, com BANK_APP:
// console.log(livenessStart.livenessSessionId);
from signdocs_brasil.models import StartStepRequest

liveness_start = client.steps.start(
    tx.transaction_id, steps[0].step_id,
    StartStepRequest(capture_mode='HOSTED_PAGE'),
)
print(liveness_start.hosted_url)
livenessStart, _ := client.Steps.Start(ctx, tx.TransactionID, steps[0].StepID,
    &signdocs.StartStepRequest{CaptureMode: signdocs.CaptureModeHostedPage})
fmt.Println(livenessStart.HostedURL)
StartStepResponse livenessStart = client.steps().start(
    tx.transactionId, steps.get(0).stepId,
    new StartStepRequest("HOSTED_PAGE"));
System.out.println(livenessStart.hostedUrl);
$livenessStart = $client->steps->start($tx->transactionId, $steps[0]->stepId,
    new StartStepRequest(captureMode: 'HOSTED_PAGE'));
echo $livenessStart->hostedUrl;

Passo 4: Completar BIOMETRIC_LIVENESS

Após a captura (seja via página hospedada ou app), complete a etapa com o livenessSessionId.

const livenessResult = await client.steps.complete(tx.transactionId, steps[0].stepId, {
  livenessSessionId: livenessStart.livenessSessionId,
});
// livenessResult.result.liveness.confidence = 0.98
from signdocs_brasil.models import CompleteLivenessRequest

liveness_result = client.steps.complete(
    tx.transaction_id, steps[0].step_id,
    CompleteLivenessRequest(liveness_session_id=liveness_start.liveness_session_id),
)
livenessResult, _ := client.Steps.Complete(ctx, tx.TransactionID, steps[0].StepID,
    &signdocs.CompleteLivenessRequest{LivenessSessionID: livenessStart.LivenessSessionID})
Step livenessResult = client.steps().complete(tx.transactionId, steps.get(0).stepId,
    Map.of("livenessSessionId", livenessStart.livenessSessionId));
$livenessResult = $client->steps->complete($tx->transactionId, $steps[0]->stepId,
    ['livenessSessionId' => $livenessStart->livenessSessionId]);

Passo 5: Completar BIOMETRIC_MATCH

A comparação facial verifica se o rosto capturado na prova de vida corresponde à imagem de referência. Duas opções:

  1. Com imagem de referência — envie a foto base64 do documento de identidade
  2. Com enrollment — se o usuário já possui cadastro biométrico, a imagem registrada é usada automaticamente

Opção 1: Com imagem de referência

const matchResult = await client.steps.complete(tx.transactionId, steps[1].stepId, {
  referenceImage: {
    source: 'BASE64_IMAGE',
    data: imageBase64,
  },
});
// matchResult.result.match.similarity = 0.95
// matchResult.result.match.threshold = 0.80
from signdocs_brasil.models import CompleteBiometricMatchRequest, ReferenceImage

match_result = client.steps.complete(
    tx.transaction_id, steps[1].step_id,
    CompleteBiometricMatchRequest(
        reference_image=ReferenceImage(data=image_base64),
    ),
)
matchResult, _ := client.Steps.Complete(ctx, tx.TransactionID, steps[1].StepID,
    &signdocs.CompleteBiometricMatchRequest{
        ReferenceImage: &signdocs.ReferenceImage{Source: "BASE64_IMAGE", Data: imageBase64},
    })
Step matchResult = client.steps().complete(tx.transactionId, steps.get(1).stepId,
    Map.of("referenceImage", Map.of("source", "BASE64_IMAGE", "data", imageBase64)));
$matchResult = $client->steps->complete($tx->transactionId, $steps[1]->stepId, [
    'referenceImage' => ['source' => 'BASE64_IMAGE', 'data' => $imageBase64],
]);

Opção 2: Com enrollment prévio

Se o signatário já possui enrollment biométrico, basta completar sem enviar referenceImage:

// Todas as linguagens: complete sem referenceImage
client.steps.complete(txId, matchStepId, {})

Passo 6: Completar CLICK_ACCEPT

Mesmo padrão da assinatura simples.

await client.steps.start(tx.transactionId, steps[2].stepId);
await client.steps.complete(tx.transactionId, steps[2].stepId, { accepted: true });
client.steps.start(tx.transaction_id, steps[2].step_id)
client.steps.complete(tx.transaction_id, steps[2].step_id, CompleteClickRequest(accepted=True))
client.Steps.Start(ctx, tx.TransactionID, steps[2].StepID, nil)
client.Steps.Complete(ctx, tx.TransactionID, steps[2].StepID,
    &signdocs.CompleteClickRequest{Accepted: true})
client.steps().start(tx.transactionId, steps.get(2).stepId);
client.steps().complete(tx.transactionId, steps.get(2).stepId, Map.of("accepted", true));
$client->steps->start($tx->transactionId, $steps[2]->stepId);
$client->steps->complete($tx->transactionId, $steps[2]->stepId, ['accepted' => true]);

Passo 7: Finalizar e obter evidências

const finalized = await client.transactions.finalize(tx.transactionId);
const evidence = await client.evidence.get(tx.transactionId);
const download = await client.documents.download(tx.transactionId);
finalized = client.transactions.finalize(tx.transaction_id)
evidence = client.evidence.get(tx.transaction_id)
download = client.documents.download(tx.transaction_id)
client.Transactions.Finalize(ctx, tx.TransactionID)
evidence, _ := client.Evidence.Get(ctx, tx.TransactionID)
download, _ := client.Documents.Download(ctx, tx.TransactionID)
client.transactions().finalize(tx.transactionId);
Evidence evidence = client.evidence().get(tx.transactionId);
DownloadResponse download = client.documents().download(tx.transactionId);
$client->transactions->finalize($tx->transactionId);
$evidence = $client->evidence->get($tx->transactionId);
$download = $client->documents->download($tx->transactionId);