Guias de Desenvolvimento

Signing Sessions

Guias dos SDKs

Política Customizada (CUSTOM)

O perfil CUSTOM permite definir manualmente quais etapas de verificação serão executadas e em qual ordem. Use quando os perfis pré-definidos não atendem ao seu caso de uso.


Passo 1: Criar transação com etapas customizadas

Defina as etapas desejadas no array customSteps. Elas serão executadas na ordem informada.

const tx = await client.transactions.create({
  purpose: 'DOCUMENT_SIGNATURE',
  policy: {
    profile: 'CUSTOM',
    customSteps: ['BIOMETRIC_LIVENESS', 'BIOMETRIC_MATCH', 'OTP_CHALLENGE', 'OTP_VERIFY'],
  },
  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='CUSTOM',
        custom_steps=['BIOMETRIC_LIVENESS', 'BIOMETRIC_MATCH', 'OTP_CHALLENGE', 'OTP_VERIFY'],
    ),
    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.PolicyProfileCustom,
        CustomSteps: []signdocs.StepType{
            signdocs.StepTypeBiometricLive,
            signdocs.StepTypeBiometricMatch,
            signdocs.StepTypeOTPChallenge,
            signdocs.StepTypeOTPVerify,
        },
    },
    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("CUSTOM",
    List.of("BIOMETRIC_LIVENESS", "BIOMETRIC_MATCH", "OTP_CHALLENGE", "OTP_VERIFY"));
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: 'CUSTOM',
        customSteps: ['BIOMETRIC_LIVENESS', 'BIOMETRIC_MATCH', 'OTP_CHALLENGE', 'OTP_VERIFY'],
    ),
    signer: new Signer(name: 'João Silva', email: 'joao@example.com', userExternalId: 'user-001'),
    document: ['content' => $pdfBase64, 'filename' => 'contrato.pdf'],
));

Passo 2: Executar etapas na ordem

As etapas são geradas na ordem definida em customSteps. Execute cada uma seguindo os padrões documentados nos guias específicos:

Tipo de Etapa Guia de Referência
CLICK_ACCEPT Assinatura Simples
OTP_CHALLENGE / OTP_VERIFY Assinatura com OTP
BIOMETRIC_LIVENESS / BIOMETRIC_MATCH Verificação Biométrica
DIGITAL_SIGN_A1 Certificado Digital A1
const steps = await client.steps.list(tx.transactionId);

for (const step of steps) {
  switch (step.type) {
    case 'BIOMETRIC_LIVENESS': {
      const start = await client.steps.start(tx.transactionId, step.stepId, {
        captureMode: 'HOSTED_PAGE',
      });
      await client.steps.complete(tx.transactionId, step.stepId, {
        livenessSessionId: start.livenessSessionId,
      });
      break;
    }
    case 'BIOMETRIC_MATCH':
      await client.steps.complete(tx.transactionId, step.stepId, {
        referenceImage: { source: 'BASE64_IMAGE', data: imageBase64 },
      });
      break;
    case 'OTP_CHALLENGE':
      await client.steps.start(tx.transactionId, step.stepId);
      break;
    case 'OTP_VERIFY':
      await client.steps.complete(tx.transactionId, step.stepId, { code: otpCode });
      break;
    case 'CLICK_ACCEPT':
      await client.steps.start(tx.transactionId, step.stepId);
      await client.steps.complete(tx.transactionId, step.stepId, { accepted: true });
      break;
  }
}
steps = client.steps.list(tx.transaction_id)

for step in steps:
    if step.type == 'BIOMETRIC_LIVENESS':
        start = client.steps.start(tx.transaction_id, step.step_id,
            StartStepRequest(capture_mode='HOSTED_PAGE'))
        client.steps.complete(tx.transaction_id, step.step_id,
            CompleteLivenessRequest(liveness_session_id=start.liveness_session_id))
    elif step.type == 'BIOMETRIC_MATCH':
        client.steps.complete(tx.transaction_id, step.step_id,
            CompleteBiometricMatchRequest(reference_image=ReferenceImage(data=image_base64)))
    elif step.type == 'OTP_CHALLENGE':
        client.steps.start(tx.transaction_id, step.step_id)
    elif step.type == 'OTP_VERIFY':
        client.steps.complete(tx.transaction_id, step.step_id,
            CompleteOtpRequest(code=otp_code))
    elif step.type == 'CLICK_ACCEPT':
        client.steps.start(tx.transaction_id, step.step_id)
        client.steps.complete(tx.transaction_id, step.step_id,
            CompleteClickRequest(accepted=True))
steps, _ := client.Steps.List(ctx, tx.TransactionID)

for _, step := range steps {
    switch step.Type {
    case signdocs.StepTypeBiometricLive:
        start, _ := client.Steps.Start(ctx, tx.TransactionID, step.StepID,
            &signdocs.StartStepRequest{CaptureMode: signdocs.CaptureModeHostedPage})
        client.Steps.Complete(ctx, tx.TransactionID, step.StepID,
            &signdocs.CompleteLivenessRequest{LivenessSessionID: start.LivenessSessionID})
    case signdocs.StepTypeBiometricMatch:
        client.Steps.Complete(ctx, tx.TransactionID, step.StepID,
            &signdocs.CompleteBiometricMatchRequest{
                ReferenceImage: &signdocs.ReferenceImage{Source: "BASE64_IMAGE", Data: imageBase64},
            })
    case signdocs.StepTypeOTPChallenge:
        client.Steps.Start(ctx, tx.TransactionID, step.StepID, nil)
    case signdocs.StepTypeOTPVerify:
        client.Steps.Complete(ctx, tx.TransactionID, step.StepID,
            &signdocs.CompleteOTPRequest{Code: otpCode})
    case signdocs.StepTypeClickAccept:
        client.Steps.Start(ctx, tx.TransactionID, step.StepID, nil)
        client.Steps.Complete(ctx, tx.TransactionID, step.StepID,
            &signdocs.CompleteClickRequest{Accepted: true})
    }
}
List<Step> steps = client.steps().list(tx.transactionId);

for (Step step : steps) {
    switch (step.type) {
        case "BIOMETRIC_LIVENESS" -> {
            var start = client.steps().start(tx.transactionId, step.stepId,
                new StartStepRequest("HOSTED_PAGE"));
            client.steps().complete(tx.transactionId, step.stepId,
                Map.of("livenessSessionId", start.livenessSessionId));
        }
        case "BIOMETRIC_MATCH" ->
            client.steps().complete(tx.transactionId, step.stepId,
                Map.of("referenceImage", Map.of("source", "BASE64_IMAGE", "data", imageBase64)));
        case "OTP_CHALLENGE" ->
            client.steps().start(tx.transactionId, step.stepId);
        case "OTP_VERIFY" ->
            client.steps().complete(tx.transactionId, step.stepId, Map.of("code", otpCode));
        case "CLICK_ACCEPT" -> {
            client.steps().start(tx.transactionId, step.stepId);
            client.steps().complete(tx.transactionId, step.stepId, Map.of("accepted", true));
        }
    }
}
$steps = $client->steps->list($tx->transactionId);

foreach ($steps as $step) {
    match ($step->type) {
        'BIOMETRIC_LIVENESS' => (function () use ($client, $tx, $step) {
            $start = $client->steps->start($tx->transactionId, $step->stepId,
                new StartStepRequest(captureMode: 'HOSTED_PAGE'));
            $client->steps->complete($tx->transactionId, $step->stepId,
                ['livenessSessionId' => $start->livenessSessionId]);
        })(),
        'BIOMETRIC_MATCH' => $client->steps->complete($tx->transactionId, $step->stepId,
            ['referenceImage' => ['source' => 'BASE64_IMAGE', 'data' => $imageBase64]]),
        'OTP_CHALLENGE' => $client->steps->start($tx->transactionId, $step->stepId),
        'OTP_VERIFY' => $client->steps->complete($tx->transactionId, $step->stepId,
            ['code' => $otpCode]),
        'CLICK_ACCEPT' => (function () use ($client, $tx, $step) {
            $client->steps->start($tx->transactionId, $step->stepId);
            $client->steps->complete($tx->transactionId, $step->stepId, ['accepted' => true]);
        })(),
    };
}

Passo 3: Finalizar transação

await client.transactions.finalize(tx.transactionId);
client.transactions.finalize(tx.transaction_id)
client.Transactions.Finalize(ctx, tx.TransactionID)
client.transactions().finalize(tx.transactionId);
$client->transactions->finalize($tx->transactionId);

Nota: Nem todas as combinações de etapas são válidas. Consulte a documentação da API para restrições de combinação. Por exemplo, OTP_VERIFY deve ser precedido por OTP_CHALLENGE.