Guias de Desenvolvimento

Signing Sessions

Guias dos SDKs

Assinatura com OTP (CLICK_PLUS_OTP)

Adiciona verificação por código OTP (One-Time Password) ao fluxo de aceite. O signatário precisa confirmar o aceite e inserir um código enviado por e-mail ou SMS.

Etapas geradas: CLICK_ACCEPT, OTP_CHALLENGE, OTP_VERIFY


Passo 1: Criar transação

Mesmo padrão da assinatura simples, mas com perfil CLICK_PLUS_OTP.

const tx = await client.transactions.create({
  purpose: 'DOCUMENT_SIGNATURE',
  policy: { profile: 'CLICK_PLUS_OTP' },
  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='CLICK_PLUS_OTP'),
    signer=Signer(name='João Silva', email='joao@example.com', user_external_id='user-001'),
    document=InlineDocument(content=pdf_base64, filename='contrato.pdf'),
))
tx, err := client.Transactions.Create(ctx, &signdocs.CreateTransactionRequest{
    Purpose: signdocs.TransactionPurposeDocumentSignature,
    Policy:  signdocs.Policy{Profile: signdocs.PolicyProfileClickPlusOTP},
    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("CLICK_PLUS_OTP");
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: 'CLICK_PLUS_OTP'),
    signer: new Signer(name: 'João Silva', email: 'joao@example.com', userExternalId: 'user-001'),
    document: ['content' => $pdfBase64, 'filename' => 'contrato.pdf'],
));

Passo 2: Listar etapas

A transação gera 3 etapas na seguinte ordem:

Ordem Tipo Descrição
1 CLICK_ACCEPT Aceite por clique
2 OTP_CHALLENGE Envio do código OTP
3 OTP_VERIFY Verificação do código
const steps = await client.steps.list(tx.transactionId);
// steps[0].type = 'CLICK_ACCEPT'
// steps[1].type = 'OTP_CHALLENGE'
// steps[2].type = 'OTP_VERIFY'
steps = client.steps.list(tx.transaction_id)
# steps[0].type = 'CLICK_ACCEPT'
# steps[1].type = 'OTP_CHALLENGE'
# steps[2].type = 'OTP_VERIFY'
steps, _ := client.Steps.List(ctx, tx.TransactionID)
// steps[0].Type = "CLICK_ACCEPT"
// steps[1].Type = "OTP_CHALLENGE"
// steps[2].Type = "OTP_VERIFY"
List<Step> steps = client.steps().list(tx.transactionId);
// steps.get(0).type = "CLICK_ACCEPT"
// steps.get(1).type = "OTP_CHALLENGE"
// steps.get(2).type = "OTP_VERIFY"
$steps = $client->steps->list($tx->transactionId);
// $steps[0]->type = 'CLICK_ACCEPT'
// $steps[1]->type = 'OTP_CHALLENGE'
// $steps[2]->type = 'OTP_VERIFY'

Passo 3: Completar CLICK_ACCEPT

Inicie e complete a etapa de aceite (mesmo padrão da assinatura simples).

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

Passo 4: Iniciar OTP_CHALLENGE

Ao iniciar a etapa OTP_CHALLENGE, o código OTP é enviado ao signatário (e-mail ou SMS).

const otpStart = await client.steps.start(tx.transactionId, steps[1].stepId);
console.log(otpStart.message); // "Código enviado para joao@example.com"

// Em sandbox, o código é retornado diretamente:
console.log(otpStart.otpCode); // "123456" (apenas em homologação)
otp_start = client.steps.start(tx.transaction_id, steps[1].step_id)
print(otp_start.message)  # "Código enviado para joao@example.com"

# Em sandbox:
print(otp_start.otp_code)  # "123456" (apenas em homologação)
otpStart, _ := client.Steps.Start(ctx, tx.TransactionID, steps[1].StepID, nil)
fmt.Println(otpStart.Message) // "Código enviado para joao@example.com"

// Em sandbox:
fmt.Println(otpStart.OTPCode) // "123456" (apenas em homologação)
StartStepResponse otpStart = client.steps().start(tx.transactionId, steps.get(1).stepId);
System.out.println(otpStart.message); // "Código enviado para joao@example.com"

// Em sandbox:
System.out.println(otpStart.otpCode); // "123456" (apenas em homologação)
$otpStart = $client->steps->start($tx->transactionId, $steps[1]->stepId);
echo $otpStart->message; // "Código enviado para joao@example.com"

// Em sandbox:
echo $otpStart->otpCode; // "123456" (apenas em homologação)

Passo 5: Completar OTP_VERIFY

Envie o código OTP recebido pelo signatário para completar a verificação.

await client.steps.complete(tx.transactionId, steps[2].stepId, {
  code: '123456',
});
from signdocs_brasil.models import CompleteOtpRequest

client.steps.complete(tx.transaction_id, steps[2].step_id,
    CompleteOtpRequest(code='123456'))
client.Steps.Complete(ctx, tx.TransactionID, steps[2].StepID,
    &signdocs.CompleteOTPRequest{Code: "123456"})
client.steps().complete(tx.transactionId, steps.get(2).stepId,
    Map.of("code", "123456"));
$client->steps->complete($tx->transactionId, $steps[2]->stepId, ['code' => '123456']);

Passo 6: Finalizar transação

const finalized = await client.transactions.finalize(tx.transactionId);
console.log(finalized.status); // COMPLETED
finalized = client.transactions.finalize(tx.transaction_id)
finalized, _ := client.Transactions.Finalize(ctx, tx.TransactionID)
Transaction finalized = client.transactions().finalize(tx.transactionId);
$finalized = $client->transactions->finalize($tx->transactionId);

Passo 7: Obter evidências

const evidence = await client.evidence.get(tx.transactionId);
console.log(evidence.evidenceId);
evidence = client.evidence.get(tx.transaction_id)
evidence, _ := client.Evidence.Get(ctx, tx.TransactionID)
Evidence evidence = client.evidence().get(tx.transactionId);
$evidence = $client->evidence->get($tx->transactionId);

Nota sobre sandbox: Em ambiente de homologação (api-hml.signdocs.com.br), o código OTP é retornado diretamente no campo otpCode da resposta ao iniciar a etapa OTP_CHALLENGE. Isso facilita testes automatizados sem necessidade de receber o e-mail/SMS real.