ForSign.Sdk 2.0.6

dotnet add package ForSign.Sdk --version 2.0.6
                    
NuGet\Install-Package ForSign.Sdk -Version 2.0.6
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ForSign.Sdk" Version="2.0.6" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ForSign.Sdk" Version="2.0.6" />
                    
Directory.Packages.props
<PackageReference Include="ForSign.Sdk" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ForSign.Sdk --version 2.0.6
                    
#r "nuget: ForSign.Sdk, 2.0.6"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ForSign.Sdk@2.0.6
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ForSign.Sdk&version=2.0.6
                    
Install as a Cake Addin
#tool nuget:?package=ForSign.Sdk&version=2.0.6
                    
Install as a Cake Tool

Documentação Completa do SDK ForSign para .NET

📢 Novidade v2.0.6: Suporte completo a todos os canais de notificação (Email, SMS, WhatsApp) e nova classe NoNotification para desabilitar notificações explicitamente. O padrão agora é não enviar notificação quando NotificationType não é definido.

🚀 Introdução

Bem-vindo à documentação oficial do SDK ForSign para .NET! Este SDK oferece integração simples e completa com a plataforma ForSign de assinaturas eletrônicas digitais.

Principais Funcionalidades

  • Múltiplos Tipos de Assinatura: Clique, desenho, texto, escolha do usuário e carimbo automático
  • Posicionamento Flexível: Use coordenadas fixas ou tags dinâmicas no PDF
  • Segurança Avançada: Duplo fator de autenticação por e-mail e selfie
  • Workflows Personalizáveis: Ordem de assinatura, assinatura presencial, finalização manual/automática
  • Formulários Dinâmicos: Campos de texto, seleção e checkbox com validação
  • Anexos Avançados: Controle de tipos de arquivo, quantidade e métodos de captura
  • Gerenciamento Completo: CRUD de operações, anexos e configurações
  • Múltiplos Idiomas: Português, Inglês e Espanhol
  • Templates e Grupos: Reutilize configurações e organize operações
  • Observers: Adicione participantes que apenas monitoram

📋 Índice

  1. Configuração Inicial
  2. Upload de Documentos
  3. Criação de Operações
  4. Tipos de Posicionamento
  5. Tipos de Assinatura
  6. Autenticação (2FA)
  7. Canais de Notificação
  8. Formulários Dinâmicos
  9. Anexos
  10. Gerenciamento de Operações
  11. Download de Documentos
  12. Configurações Avançadas
  13. Exemplos Completos
  14. Referência Rápida

🔧 Configuração Inicial

Requisitos

  • .NET Framework 4.5+ ou .NET Core/Standard 2.0+
  • .NET 5, 6, 7 ou 8
  • API Key da ForSign (obtenha no painel de desenvolvedor)

Instalação via NuGet

dotnet add package ForSign.Sdk

Ou

Install-Package ForSign.Sdk

Configuração Básica

using ForSign.Sdk;

// 1. Criar cliente
var client = new ForSignClient();

// 2. Configurar credencial com sua API Key
const string API_KEY = "SUA_API_KEY_AQUI";
var credential = new ApiKeyCredential(API_KEY);
client.SetCredential(credential);

// Pronto! O SDK já está configurado e pronto para uso
Console.WriteLine("SDK configurado com sucesso!");

⚠️ Segurança: Nunca exponha sua API Key em código front-end ou repositórios públicos. Use variáveis de ambiente ou cofres de segredos.


📤 Upload de Documentos

A ForSign aceita apenas arquivos PDF com tamanho máximo de 10 MB.

Método 1: Upload de Arquivo Local

var fileRequest = UploadFileRequest.AddFileFromPath("/caminho/completo/documento.pdf");
var upload = await client.UploadFileAsync(fileRequest);
var fileInfo = new FileInformation(upload.Data.Id, upload.Data.FileName);

Método 2: Upload de URL

var fileRequest = await UploadFileRequest.AddFileFromUrlAsync(
    "https://exemplo.com/documento.pdf",
    "documento.pdf"
);
var upload = await client.UploadFileAsync(fileRequest);
var fileInfo = new FileInformation(upload.Data.Id, upload.Data.FileName);

Método 3: Upload de Bytes

byte[] pdfBytes = File.ReadAllBytes("documento.pdf");
var fileRequest = await UploadFileRequest.AddFileFromBytesAsync(pdfBytes, "documento.pdf");
var upload = await client.UploadFileAsync(fileRequest);
var fileInfo = new FileInformation(upload.Data.Id, upload.Data.FileName);

Método 4: Upload de Base64

string base64Content = "JVBERi0xLjQKJ..."; // Base64 do PDF
var fileRequest = await UploadFileRequest.AddFileFromBase64Async("documento.pdf", base64Content);
var upload = await client.UploadFileAsync(fileRequest);
var fileInfo = new FileInformation(upload.Data.Id, upload.Data.FileName);

Método 5: Upload de Stream

using var memoryStream = new MemoryStream(pdfBytes);
var fileRequest = await UploadFileRequest.AddFileFromStreamAsync(memoryStream, "documento.pdf");
var upload = await client.UploadFileAsync(fileRequest);
var fileInfo = new FileInformation(upload.Data.Id, upload.Data.FileName);

🏗️ Criação de Operações

Use o OperationRequestBuilder para construir operações de forma fluente:

var operation = OperationRequestBuilder
    .InitializeWithName("Título da Operação")
    .SetExpirationDate(DateTime.Now.AddDays(30))
    .WithExternalId("MEU-ID-123")
    .SetSignersOrderRequirement(true)
    .SetInPersonSigning(false)
    .SetLanguage(Language.Portuguese)
    .SetDisplayCover(true)
    .EnableMemberActionNotifications(true)
    .WithOptionalMessage("Mensagem aos signatários")
    .WithRedirectUrl("https://seusite.com/sucesso/{operationId}")
    .AddSigner(signer1)
    .AddSigner(signer2)
    .AddObserver("Nome", "email@exemplo.com")
    .AddToGroup(groupId)
    .SetManualFinish(true)
    .Build();

var response = await client.CreateOperationAsync(operation);

// Obter URLs de assinatura
foreach (var member in response.Members)
{
    Console.WriteLine($"{member.Name}: {member.SignUrl}");
}

📍 Tipos de Posicionamento

Opção 1: Assinaturas com Tags (Dinâmico) ⭐ RECOMENDADO

Tags permitem posicionamento dinâmico baseado em marcadores no PDF.

Preparar o PDF

Adicione marcadores no formato {{nome_da_tag}} no seu PDF:

┌────────────────────────────────────┐
│ CONTRATO                           │
│                                    │
│ Assinatura: {{assinatura_cliente}}│
│ Rubrica: {{rubrica_cliente}}      │
└────────────────────────────────────┘
Configurar no SDK
var signer = new Signer
{
    Name = "João Silva",
    Email = "joao@exemplo.com",
    SignatureType = new DefaultSignatureType(SignatureType.UserChoice)
};

// Assinatura por tag
var signatureTag = new TagPosition(fileInfo, "assinatura_cliente");
signer.SetTagSignaturePosition(signatureTag);

// Rubrica por tag (opcional)
var rubricTag = new TagPosition(fileInfo, "rubrica_cliente");
signer.SetTagRubricPosition(rubricTag);

Regras para nomes de tags:

  • ✅ Use apenas: a-z, A-Z, 0-9, -, _
  • ❌ Não use: espaços, pontos, caracteres especiais
  • Formato no PDF: {{nome_da_tag}}
  • Regex de validação: ^[a-zA-Z0-9_-]+$

Quando usar tags:

  • ✅ Documentos gerados dinamicamente
  • ✅ PDFs com conteúdo variável
  • ✅ Contratos onde layout pode mudar
  • ✅ Múltiplas assinaturas em páginas diferentes

Opção 2: Assinaturas com Coordenadas (Fixo)

Para posicionamento preciso em templates com layout fixo:

var signer = new Signer
{
    Name = "Maria Souza",
    Email = "maria@exemplo.com",
    SignatureType = new DefaultSignatureType(SignatureType.UserChoice)
};

// Formato: (arquivo, página, X%, Y%)
signer.AddSignatureInPosition(fileInfo, 1, "50%", "80%");
signer.AddSignatureInPosition(fileInfo, 2, "50%", "20%");

// Rubricas
signer.AddRubricInPosition(fileInfo, 1, "10%", "90%");
signer.AddRubricInPosition(fileInfo, 2, "10%", "90%");

Sistema de coordenadas:

  • X: 0% (esquerda) a 100% (direita)
  • Y: 0% (topo) a 100% (fundo)
  • Sempre use formato percentual: "50%", "80%"

Quando usar coordenadas:

  • ✅ Templates de formulários fixos
  • ✅ PDFs sempre com mesmo layout
  • ✅ Controle pixel-perfect da posição
  • ✅ Documentos de página única

✍️ Tipos de Assinatura

1. Assinatura Padrão (Escolha do Usuário)

signer.SignatureType = new DefaultSignatureType(SignatureType.UserChoice);
// Usuário pode escolher entre desenhar, clicar ou digitar

Opções disponíveis:

  • SignatureType.UserChoice - Usuário escolhe o método
  • SignatureType.Click - Assinatura com um clique
  • SignatureType.Draw - Desenhar a assinatura
  • SignatureType.Text - Digitar o nome

2. Certificado Digital (ICP-Brasil)

signer.SignatureType = new CertificateSignatureType();

Assinatura com certificado digital ICP-Brasil. Oferece o mais alto nível de validade jurídica no Brasil, equivalente à assinatura física.

Características:

  • ✅ Validade jurídica máxima (equiparada à assinatura manuscrita)
  • ✅ Conformidade com ICP-Brasil
  • ✅ Não-repúdio garantido
  • ✅ Ideal para contratos de alto valor

Quando usar:

  • Contratos que exigem validade jurídica máxima
  • Transações financeiras e imobiliárias
  • Documentos que serão apresentados em cartórios ou órgãos públicos
  • Operações que exigem conformidade regulatória

3. Certificado em Nuvem

signer.SignatureType = new CloudCertificateSignatureType();

Assinatura com certificado digital armazenado na nuvem. Combina a segurança do certificado digital com a conveniência de acesso remoto.

Características:

  • ✅ Validade jurídica equivalente ao certificado físico
  • ✅ Acesso de qualquer dispositivo
  • ✅ Não requer token físico ou cartão
  • ✅ Processo de assinatura simplificado

Quando usar:

  • Assinaturas remotas com validade jurídica
  • Equipes distribuídas geograficamente
  • Alto volume de assinaturas
  • Processos digitais end-to-end

🔐 Autenticação Dois Fatores (2FA)

Opção 1: Email

signer.DoubleAuthenticationMethod = new EmailDoubleAuthentication("email@exemplo.com");

Um código de segurança será enviado para o email antes da assinatura.

Opção 2: SMS

signer.DoubleAuthenticationMethod = new SmsDoubleAuthentication("11987654321");

Um código de segurança será enviado via SMS para o telefone antes da assinatura.

Opção 3: WhatsApp

signer.DoubleAuthenticationMethod = new WhatsAppDoubleAuthentication("11987654321");

Um código de segurança será enviado via WhatsApp para o telefone antes da assinatura.

Fluxo do 2FA:

  1. Signatário acessa URL de assinatura
  2. Sistema solicita código (Email/SMS/WhatsApp)
  3. Após validação, libera assinatura

📢 Canais de Notificação

Configure como os signatários receberão as notificações:

Opção 1: Sem Notificação (Padrão)

// Opção 1: Não definir (padrão = sem notificação)
// signer.NotificationType permanece null

// Opção 2: Explicitamente sem notificação
signer.NotificationType = new NoNotification();

O signatário não receberá notificações automáticas. Use quando você mesmo irá enviar o link de assinatura.

Opção 2: Email

signer.NotificationType = new EmailNotification("email@exemplo.com");

O signatário receberá notificações por email.

Opção 3: SMS

signer.NotificationType = new SmsNotification("+5511987654321");

O signatário receberá notificações via SMS.

Nota: Use o formato internacional com código do país (+55 para Brasil).

Opção 4: WhatsApp

signer.NotificationType = new WhatsAppNotification("+5511987654321");

O signatário receberá notificações via WhatsApp.

Nota: Use o formato internacional com código do país (+55 para Brasil).

Resumo dos Canais

Canal Classe Exemplo
Sem notificação NoNotification ou null new NoNotification()
Email EmailNotification new EmailNotification("email@ex.com")
SMS SmsNotification new SmsNotification("+5511999999999")
WhatsApp WhatsAppNotification new WhatsAppNotification("+5511999999999")

Tipos de notificações enviadas:

  • URL de assinatura
  • Lembretes
  • Status da operação
  • Conclusão do processo

📝 Formulários Dinâmicos

Campo de Texto

var textField = TextFormField.WithName("Nome Completo")
    .WithInstructions("Digite seu nome completo")
    .IsRequired()
    .WithMaxLength(100)
    .WithTextFormat(FrontTypeFormField.Text)
    .WithSize(2.5f, 25f) // altura, largura em %
    .OnPosition(new FormFieldPosition(fileInfo, 1, "30%", "40%"))
    .WithValue("Valor Padrão");

signer.AddFormField(textField);

Formatos de texto disponíveis:

  • FrontTypeFormField.Text - Texto livre
  • FrontTypeFormField.Number - Apenas números
  • FrontTypeFormField.Email - Email
  • FrontTypeFormField.Phone - Telefone
  • FrontTypeFormField.Date - Data (DD/MM/YYYY)
  • FrontTypeFormField.DateUs - Data (MM/DD/YYYY)

Campo de Checkbox

var checkbox = CheckboxFormField.WithName("Aceito Termos")
    .WithInstructions("Marque se aceita")
    .IsRequired()
    .WithOptions(new List<string> { "Aceito", "Não aceito" })
    .WithSize(2.5f, 25f)
    .OnPosition(new FormFieldPosition(fileInfo, 1, "20%", "30%"))
    .WithValue("Aceito");

signer.AddFormField(checkbox);

Campo de Seleção (Dropdown)

var selectField = SelectFormField.WithName("Estado")
    .WithInstructions("Selecione seu estado")
    .IsRequired()
    .WithOptions(new List<string> { "SP", "RJ", "MG", "RS" })
    .WithSize(2.5f, 25f)
    .OnPosition(new FormFieldPosition(fileInfo, 1, "40%", "50%"))
    .WithValue("SP");

signer.AddFormField(selectField);

Título e Descrição do Formulário

signer.FormTitle = "Dados Cadastrais";
signer.FormDescription = "Preencha as informações abaixo para prosseguir";

📎 Anexos

Solicitar Anexos

var attachment = new Attachment(
    "RG ou CNH",
    "Envie foto do documento de identidade",
    isRequired: true
);

// Tipos de arquivo permitidos
attachment.PermitFileType(AttachmentFileType.PNG);
attachment.PermitFileType(AttachmentFileType.JPEG);
attachment.PermitFileType(AttachmentFileType.JPG);
attachment.PermitFileType(AttachmentFileType.PDF);
attachment.PermitFileType(AttachmentFileType.DOC);
attachment.PermitFileType(AttachmentFileType.DOCX);

// Métodos de captura/envio
attachment.PermitAttachmentByInput(InputAttachmentType.CameraSideBack);
attachment.PermitAttachmentByInput(InputAttachmentType.CameraSideFront);
attachment.PermitAttachmentByInput(InputAttachmentType.UploadFile);

// Limitar quantidade de arquivos
attachment.MaxFilesAllowed = 2;

signer.RequestAttachment(attachment);

Tipos de input disponíveis:

  • InputAttachmentType.CameraSideBack - Câmera traseira
  • InputAttachmentType.CameraSideFront - Câmera frontal (selfie)
  • InputAttachmentType.UploadFile - Upload de arquivo

Listar Anexos de um Membro

long memberId = 12345;
var attachments = await client.GetMemberAttachmentsAsync(memberId);

foreach (var att in attachments)
{
    Console.WriteLine($"Anexo: {att.Name} - Enviado: {att.IsUploaded}");
}

Aprovar Anexos

long memberId = 12345;
var attachmentIds = new List<long> { 67890, 98765 };
await client.ApproveAttachmentsAsync(memberId, attachmentIds);

Rejeitar Anexos

long memberId = 12345;
var rejectedList = new List<RejectedAttachment>
{
    new RejectedAttachment { Id = 67890, Reason = "Documento ilegível" },
    new RejectedAttachment { Id = 98765, Reason = "Formato inválido" }
};
await client.RejectAttachmentsAsync(memberId, rejectedList);

Baixar Anexo

long attachmentId = 67890;
var download = await client.DownloadAttachmentAsync(attachmentId);

// Salvar arquivo
File.WriteAllBytes(download.FileName, download.Content);
Console.WriteLine($"ContentType: {download.ContentType}");

🔧 Gerenciamento de Operações

Finalizar Operação Manualmente

long operationId = 12345;
await client.CompleteOperationAsync(operationId);
Console.WriteLine("Operação finalizada!");

Nota: Todos os signatários obrigatórios devem ter assinado antes.

Cancelar Operação

long operationId = 12345;
await client.CancelOperationAsync(operationId, "Cancelamento solicitado pelo cliente");

Configurar Finalização Automática

long operationId = 12345;
DateTime endDate = DateTime.Now.AddDays(7);
await client.SetOperationAutomaticCompletionAsync(operationId, endDate);

Nota: A data deve ser pelo menos 1 hora no futuro.

Configurar Finalização Manual

long operationId = 12345;
await client.SetOperationManualCompletionAsync(operationId);

Isso altera uma operação de finalização automática para manual.


📥 Download de Documentos

Download do ZIP da Operação

long operationId = 12345;
var zipResponse = await client.DownloadOperationZipAsync(operationId);

O ZIP contém:

  • Documento(s) assinado(s)
  • Trilha de auditoria (audit trail)
  • Anexos enviados pelos signatários
  • Formulários preenchidos (CSV)

Forma 1: Converter Base64 Manualmente

byte[] zipBytes = Convert.FromBase64String(zipResponse.Base64File);
File.WriteAllBytes("operacao.zip", zipBytes);

Forma 2: Usar Método de Extensão (RECOMENDADO)

byte[] zipBytes = zipResponse.GetZipBytes();
File.WriteAllBytes("operacao.zip", zipBytes);

Forma 3: Salvar Diretamente em Arquivo

zipResponse.SaveToFile("/caminho/completo/arquivo.zip");

Forma 4: Salvar em Diretório (Nome Automático)

string savedPath = zipResponse.SaveToDirectory("/caminho/diretorio");
Console.WriteLine($"Arquivo salvo em: {savedPath}");

⚙️ Configurações Avançadas

1. Idioma da Interface

.SetLanguage(Language.Portuguese)
// Opções: Portuguese, English, Spanish

Define o idioma da interface de assinatura e notificações.

2. Exibir/Ocultar Capa Inicial

.SetDisplayCover(true) // ou false

A capa mostra informações da operação antes de iniciar.

3. Ordem de Assinatura

.SetSignersOrderRequirement(true)
  • true = signatários devem assinar na ordem adicionada
  • false = podem assinar em qualquer ordem

4. Assinatura Presencial

.SetInPersonSigning(true)
  • true = todos assinam no mesmo dispositivo simultaneamente
  • false = assinam remotamente

5. URL de Redirecionamento

.WithRedirectUrl("https://seusite.com/sucesso/{operationId}/{externalId}")

Parâmetros dinâmicos:

  • {operationId} - Substituído pelo ID da operação
  • {externalId} - Substituído pelo ID externo (se definido)

Segurança: Sempre use HTTPS.

6. ID Externo

.WithExternalId("SEU-CODIGO-123")

Útil para correlacionar com seu sistema interno.

7. Adicionar a Grupos

.AddToGroup(groupId)
// ou adicionar a múltiplos grupos
.AddToGroups(new List<long> { group1, group2, group3 })

Organize operações em grupos para melhor gestão.

8. Adicionar Observadores

.AddObserver("Nome do Monitor", "monitor@empresa.com")

Observadores recebem notificações mas não precisam assinar.

9. Notificações de Ações dos Membros

.EnableMemberActionNotifications(true)

Receba notificações quando signatários:

  • Visualizam o documento
  • Completam assinatura
  • Rejeitam documento
  • Enviam formulários

10. Mensagem Opcional

.WithOptionalMessage("Por favor, revise e assine até o dia 30/01.")

Mensagem personalizada exibida aos signatários.

11. Finalização Manual

.SetManualFinish(true)
  • true = você deve chamar CompleteOperationAsync() para finalizar
  • false = finaliza automaticamente quando todos assinarem

12. Data de Expiração

.SetExpirationDate(DateTime.Now.AddDays(30))

Após essa data, a operação expira se não for finalizada.

13. Metadados Personalizados

.AddMetadata("chave", "valor")
.AddMetadata("departamento", "vendas")
.AddMetadata("contrato_tipo", "locacao")

Adicione dados customizados à operação.


📚 Exemplos Completos

Exemplo 1: Contrato Simples com Tags

using ForSign.Sdk;

var client = new ForSignClient();
client.SetCredential(new ApiKeyCredential("SUA_API_KEY"));

// Upload do documento que contém {{assinatura_cliente}}
var fileRequest = await UploadFileRequest.AddFileFromUrlAsync(
    "https://exemplo.com/contrato-tags.pdf",
    "contrato.pdf"
);
var upload = await client.UploadFileAsync(fileRequest);
var fileInfo = new FileInformation(upload.Data.Id, upload.Data.FileName);

// Configurar signatário com tag
var signer = new Signer
{
    Name = "João Cliente",
    Email = "joao@cliente.com",
    SignatureType = new DefaultSignatureType(SignatureType.UserChoice),
    DoubleAuthenticationMethod = new EmailDoubleAuthentication("joao@cliente.com")
};

var signTag = new TagPosition(fileInfo, "assinatura_cliente");
signer.SetTagSignaturePosition(signTag);

// Criar operação
var operation = OperationRequestBuilder
    .InitializeWithName("Contrato de Serviços - João")
    .SetLanguage(Language.Portuguese)
    .SetExpirationDate(DateTime.Now.AddDays(15))
    .AddSigner(signer)
    .Build();

var response = await client.CreateOperationAsync(operation);
Console.WriteLine($"URL: {response.Members[0].SignUrl}");

Exemplo 2: Workflow Completo com Formulários e Anexos

var client = new ForSignClient();
client.SetCredential(new ApiKeyCredential("SUA_API_KEY"));

// Upload
var upload = await client.UploadFileAsync(
    await UploadFileRequest.AddFileFromUrlAsync(
        "https://exemplo.com/cadastro.pdf",
        "cadastro.pdf"
    )
);
var fileInfo = new FileInformation(upload.Data.Id, upload.Data.FileName);

// Signatário com tudo
var signer = new Signer
{
    Name = "Maria Silva",
    Email = "maria@exemplo.com",
    Phone = "11987654321",
    SignatureType = new DefaultSignatureType(SignatureType.UserChoice),
    DoubleAuthenticationMethod = new EmailDoubleAuthentication("maria@exemplo.com"),
    FormTitle = "Dados Pessoais",
    FormDescription = "Preencha suas informações"
};

// Assinatura
signer.AddSignatureInPosition(fileInfo, 1, "50%", "80%");

// Formulário - CPF
var cpfField = TextFormField.WithName("CPF")
    .IsRequired()
    .WithMaxLength(14)
    .WithTextFormat(FrontTypeFormField.Number)
    .OnPosition(new FormFieldPosition(fileInfo, 1, "30%", "40%"));
signer.AddFormField(cpfField);

// Formulário - Estado
var estadoField = SelectFormField.WithName("Estado")
    .IsRequired()
    .WithOptions(new List<string> { "SP", "RJ", "MG" })
    .OnPosition(new FormFieldPosition(fileInfo, 1, "30%", "50%"));
signer.AddFormField(estadoField);

// Anexo - RG
var rg = new Attachment("RG", "Envie foto do RG", true);
rg.PermitFileType(AttachmentFileType.JPEG);
rg.PermitFileType(AttachmentFileType.PNG);
rg.PermitAttachmentByInput(InputAttachmentType.UploadFile);
signer.RequestAttachment(rg);

// Criar operação
var operation = OperationRequestBuilder
    .InitializeWithName("Cadastro Completo - Maria")
    .SetExpirationDate(DateTime.Now.AddDays(7))
    .WithRedirectUrl("https://meusite.com/sucesso/{operationId}")
    .SetLanguage(Language.Portuguese)
    .AddSigner(signer)
    .Build();

var response = await client.CreateOperationAsync(operation);

// Aguardar assinatura e anexos...
// Depois, baixar documentos
await Task.Delay(TimeSpan.FromMinutes(5)); // Simulando espera
var zip = await client.DownloadOperationZipAsync(response.Id);
zip.SaveToDirectory("./downloads");

Exemplo 3: Assinatura com Certificado Digital

var client = new ForSignClient();
client.SetCredential(new ApiKeyCredential("SUA_API_KEY"));

var upload = await client.UploadFileAsync(
    await UploadFileRequest.AddFileFromUrlAsync(
        "https://exemplo.com/contrato-alto-valor.pdf",
        "contrato.pdf"
    )
);
var fileInfo = new FileInformation(upload.Data.Id, upload.Data.FileName);

// Assinatura com Certificado Digital ICP-Brasil
var signerCertificado = new Signer
{
    Name = "Dr. Ricardo Oliveira",
    Email = "ricardo@oliveira.com",
    SignatureType = new CertificateSignatureType(), // ← Certificado Digital
    DoubleAuthenticationMethod = new EmailDoubleAuthentication("ricardo@oliveira.com")
};
signerCertificado.AddSignatureInPosition(fileInfo, 1, "50%", "70%");

// Assinatura com Certificado em Nuvem
var signerNuvem = new Signer
{
    Name = "Ana Paula Santos",
    Email = "ana@santos.com",
    SignatureType = new CloudCertificateSignatureType(), // ← Certificado Nuvem
};
signerNuvem.AddSignatureInPosition(fileInfo, 1, "50%", "85%");

// Criar operação
var operation = OperationRequestBuilder
    .InitializeWithName("Contrato com Certificado Digital")
    .SetExpirationDate(DateTime.Now.AddDays(30))
    .AddSigner(signerCertificado)
    .AddSigner(signerNuvem)
    .Build();

var response = await client.CreateOperationAsync(operation);

foreach (var member in response.Members)
{
    Console.WriteLine($"{member.Name}: {member.SignUrl}");
}

Exemplo 4: Múltiplos Signatários com Ordem

var client = new ForSignClient();
client.SetCredential(new ApiKeyCredential("SUA_API_KEY"));

var upload = await client.UploadFileAsync(
    await UploadFileRequest.AddFileFromUrlAsync(
        "https://exemplo.com/contrato.pdf",
        "contrato.pdf"
    )
);
var fileInfo = new FileInformation(upload.Data.Id, upload.Data.FileName);

// Primeiro signatário: Empresa
var empresa = new Signer
{
    Name = "Empresa XYZ Ltda",
    Email = "contato@empresa.com",
    SignatureType = new DefaultSignatureType(SignatureType.UserChoice)
};
empresa.AddSignatureInPosition(fileInfo, 1, "30%", "80%");

// Segundo signatário: Cliente
var cliente = new Signer
{
    Name = "João Silva",
    Email = "joao@silva.com",
    SignatureType = new DefaultSignatureType(SignatureType.UserChoice),
    DoubleAuthenticationMethod = new EmailDoubleAuthentication("joao@silva.com")
};
cliente.AddSignatureInPosition(fileInfo, 1, "70%", "80%");

// Operação com ordem de assinatura
var operation = OperationRequestBuilder
    .InitializeWithName("Contrato Bilateral")
    .SetSignersOrderRequirement(true) // Empresa assina primeiro
    .SetExpirationDate(DateTime.Now.AddDays(30))
    .AddSigner(empresa)
    .AddSigner(cliente)
    .Build();

var response = await client.CreateOperationAsync(operation);

foreach (var member in response.Members)
{
    Console.WriteLine($"{member.Name}: {member.SignUrl}");
}

🚨 Tratamento de Erros

try
{
    var response = await client.CreateOperationAsync(operation);
}
catch (ForSignApiException ex)
{
    Console.WriteLine($"Erro da API ForSign: {ex.Message}");
    Console.WriteLine($"Status Code: {ex.StatusCode}");

    // Detalhes adicionais
    if (ex.ErrorResponse?.Messages != null)
    {
        foreach (var msg in ex.ErrorResponse.Messages)
        {
            Console.WriteLine($"  {msg.Key}: {msg.Value}");
        }
    }
}
catch (Exception ex)
{
    Console.WriteLine($"Erro inesperado: {ex.Message}");
}

Códigos de status comuns:

  • 400 Bad Request - Dados inválidos
  • 401 Unauthorized - API Key inválida
  • 402 Payment Required - Créditos insuficientes
  • 403 Forbidden - Sem permissão
  • 404 Not Found - Operação não encontrada
  • 500 Internal Server Error - Erro no servidor

📋 Referência Rápida

Tipos de Assinatura

  • SignatureType.UserChoice - Usuário escolhe
  • SignatureType.Click - Clique
  • SignatureType.Draw - Desenho
  • SignatureType.Text - Texto
  • CertificateSignatureType - Certificado Digital (ICP-Brasil)
  • CloudCertificateSignatureType - Certificado em Nuvem

Tipos de Formulário

  • TextFormField - Campo de texto
  • SelectFormField - Lista de seleção
  • CheckboxFormField - Checkbox

Formatos de Campo de Texto

  • FrontTypeFormField.Text - Texto livre
  • FrontTypeFormField.Number - Número
  • FrontTypeFormField.Email - Email
  • FrontTypeFormField.Phone - Telefone
  • FrontTypeFormField.Date - Data (DD/MM/YYYY)
  • FrontTypeFormField.DateUs - Data (MM/DD/YYYY)

Tipos de Arquivo para Anexos

  • AttachmentFileType.PNG
  • AttachmentFileType.JPEG
  • AttachmentFileType.JPG
  • AttachmentFileType.PDF
  • AttachmentFileType.DOC
  • AttachmentFileType.DOCX

Métodos de Input de Anexos

  • InputAttachmentType.CameraSideBack - Câmera traseira
  • InputAttachmentType.CameraSideFront - Câmera frontal
  • InputAttachmentType.UploadFile - Upload

Idiomas

  • Language.Portuguese - Português (pt-BR)
  • Language.English - Inglês (en)
  • Language.Spanish - Espanhol (es)

Canais de Notificação (Classes)

  • NoNotification - Sem notificação (padrão)
  • EmailNotification - E-mail
  • SmsNotification - SMS
  • WhatsAppNotification - WhatsApp

Canais de Autenticação

  • AuthenticationChannel.Email - E-mail
  • AuthenticationChannel.SMS - SMS
  • AuthenticationChannel.WhatsApp - WhatsApp

⚠️ Regras e Limitações

Arquivos

  • Formato: Apenas PDF
  • Tamanho: Máximo 10 MB

Tags

  • Formato: {{nome_da_tag}}
  • Caracteres permitidos: a-z, A-Z, 0-9, -, _
  • Não use: espaços, pontos, caracteres especiais

Coordenadas

  • Formato: Sempre percentual ("50%", "80%")
  • X: 0% (esquerda) a 100% (direita)
  • Y: 0% (topo) a 100% (fundo)

URLs de Redirecionamento

  • Devem começar com http:// ou https://
  • Parâmetros dinâmicos: {operationId}, {externalId}
  • Recomendado: sempre use HTTPS

🔐 Boas Práticas

Segurança

  1. Nunca exponha API Key em código front-end
  2. Use variáveis de ambiente ou cofres de segredos
  3. Sempre use HTTPS para redirect URLs
  4. Habilite 2FA para operações importantes

Performance

  1. Reutilize a mesma instância de ForSignClient
  2. Use upload por URL quando possível (evita tráfego)
  3. Configure timeouts adequados para operações longas

Confiabilidade

  1. Configure webhooks para atualizações em tempo real
  2. Sempre trate exceções ForSignApiException
  3. Use ExternalId para correlação com seu sistema
  4. Configure data de expiração adequada

UX

  1. Configure mensagens personalizadas
  2. Use redirect URLs para melhor experiência
  3. Escolha idioma adequado ao público
  4. Forneça instruções claras em formulários

🌐 Webhooks

A forma mais eficiente de monitorar operações é através de Webhooks.

Como funciona:

  1. Configure uma URL no painel de desenvolvedor
  2. ForSign enviará POST para essa URL em eventos importantes
  3. Sua aplicação recebe notificações em tempo real

Eventos comuns:

  • Operação criada
  • Signatário visualizou documento
  • Signatário assinou
  • Operação finalizada
  • Operação cancelada
  • Anexo enviado

Isso elimina necessidade de polling (consultar status repetidamente).


📞 Suporte

  • Documentação da API: https://api.forsign.digital/docs
  • Email: suporte@forsign.digital
  • Issues: GitHub Issues
  • Painel: Acesse o painel de desenvolvedor para obter API Key

📝 Changelog

v2.0.6 (2025-12-29)

  • NOVO: Classe NoNotification para desabilitar notificações explicitamente
  • NOVO: Suporte completo para SmsNotification
  • NOVO: Suporte completo para WhatsAppNotification
  • 🐛 FIX: Correção do mapeamento de NotificationType para NotificationChannel
  • 🐛 FIX: SMS e WhatsApp agora são processados corretamente
  • ⚠️ BREAKING: Padrão de notificação alterado de Email para None
  • 📚 DOCS: Documentação de canais de notificação atualizada

v2.0.5

  • 🔐 SDK agora usa apenas autenticação via API Key
  • 🗑️ Removido suporte a JWT/Bearer token
  • ⚡ Melhorias de performance

v2.0.4

  • ✨ Certificado Digital (ICP-Brasil)
  • ✨ Certificado em Nuvem
  • ✨ SelfieDoubleAuthentication

v2.0.0

  • Versão inicial pública do SDK

📄 Licença

Este projeto está licenciado sob a MIT License.


<p align="center"> <strong>Desenvolvido com ❤️ pela equipe ForSign</strong><br> <a href="https://forsign.digital">forsign.digital</a> </p>

Product Compatible and additional computed target framework versions.
.NET net5.0 is compatible.  net5.0-windows was computed.  net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 is compatible.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net45 is compatible.  net451 is compatible.  net452 is compatible.  net46 is compatible.  net461 is compatible.  net462 is compatible.  net463 was computed.  net47 is compatible.  net471 was computed.  net472 is compatible.  net48 is compatible.  net481 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.6 89 12/29/2025
2.0.5 172 12/23/2025
2.0.4 269 12/18/2025
2.0.3 267 12/18/2025
2.0.2 277 9/19/2025
2.0.1 253 9/19/2025
2.0.0 248 9/19/2025
1.0.6 304 2/2/2024
1.0.5 191 1/26/2024
1.0.4 164 1/26/2024
1.0.3 178 1/19/2024
1.0.2 171 1/19/2024
1.0.1 174 1/18/2024
0.1.4 174 1/26/2024

Version 2.0.6 - Notification Channel Improvements

**New Features:**
- NoNotification: Explicit class to disable notifications for a signer
- SmsNotification: Full support for SMS notifications
- WhatsAppNotification: Full support for WhatsApp notifications

**Bug Fixes:**
- Fixed: NotificationType not being properly converted to NotificationChannel
- Fixed: SMS and WhatsApp notification types were not being processed
- Fixed: Default notification behavior now correctly defaults to None (no notification)

**Breaking Changes:**
- Default NotificationChannel changed from Email to None
- If you relied on automatic Email notifications without setting NotificationType,
 you now need to explicitly set: signer.NotificationType = new EmailNotification("email@example.com")

**Migration Guide:**
- If you want NO notification: signer.NotificationType = null (or new NoNotification())
- If you want Email: signer.NotificationType = new EmailNotification("email@example.com")
- If you want SMS: signer.NotificationType = new SmsNotification("+5511999999999")
- If you want WhatsApp: signer.NotificationType = new WhatsAppNotification("+5511999999999")

For full documentation, visit: https://github.com/forsign/sdk-dotnet