Clicksign.NET
0.1.2
See the version list below for details.
dotnet add package Clicksign.NET --version 0.1.2
NuGet\Install-Package Clicksign.NET -Version 0.1.2
<PackageReference Include="Clicksign.NET" Version="0.1.2" />
<PackageVersion Include="Clicksign.NET" Version="0.1.2" />
<PackageReference Include="Clicksign.NET" />
paket add Clicksign.NET --version 0.1.2
#r "nuget: Clicksign.NET, 0.1.2"
#:package Clicksign.NET@0.1.2
#addin nuget:?package=Clicksign.NET&version=0.1.2
#tool nuget:?package=Clicksign.NET&version=0.1.2
Clicksign .NET SDK
Cliente .NET oficial para a Clicksign API v3 (JSON:API). Requer .NET 8+, zero dependências de runtime — apenas System.Net.Http (stdlib).
Índice
- Instalação
- Configuração
- Início rápido
- Fluxo de assinatura (notarial)
- Filtros, ordenação e paginação
- Outros recursos
- Tratamento de erros
- Ambientes
- Timeouts, retry e instrumentação
- Validação de webhook
- ASP.NET Core e DI
- Limitações e produção
- Desenvolvimento
Fluxo completo:
docs/WORKFLOW.md— envelope → documento → signatário → requisitos → ativação passo a passo.
Cookbook:
docs/examples/— receitas prontas para retry, bulk, webhooks, multi-conta e limitações de produção.
Contrato do SDK:
docs/SDK_CONTRACT.md— timeouts, retry, JSON:API, erros e paginação.
Observabilidade:
docs/OBSERVABILITY.md— hooks, MEL, OpenTelemetry, métricas.
Instalação
dotnet add package Clicksign.NET
Ou via NuGet Package Manager:
Install-Package Clicksign.NET
Configuração
using Clicksign;
var client = new ClicksignClient(new ClicksignClientOptions
{
ApiKey = Environment.GetEnvironmentVariable("CLICKSIGN_API_KEY")!,
Environment = ClicksignEnvironment.Sandbox,
MaxRetries = 3,
ConnectTimeout = TimeSpan.FromSeconds(2),
ReadTimeout = TimeSpan.FromSeconds(10),
});
| Opção | Tipo | Padrão | Descrição |
|---|---|---|---|
ApiKey |
string |
— | Access token (obrigatório) |
Environment |
string |
Production |
Define URL base |
BaseUrl |
string? |
null | Sobrescreve URL (WireMock, proxy, testes) |
ConnectTimeout |
TimeSpan |
2s |
Timeout de conexão TCP |
ReadTimeout |
TimeSpan |
10s |
Timeout de leitura da resposta |
MaxRetries |
int |
0 |
Retentativas em erros retryable |
Segurança: nunca commite tokens. Use variáveis de ambiente,
IConfigurationou secret manager.
Início rápido
using Clicksign;
using Clicksign.Resources.Notarial;
using Clicksign.Types;
var client = new ClicksignClient(new ClicksignClientOptions
{
ApiKey = Environment.GetEnvironmentVariable("CLICKSIGN_API_KEY")!,
Environment = ClicksignEnvironment.Sandbox,
});
// Criar envelope
var envelope = await client.Envelopes.CreateAsync(new EnvelopeCreateParams
{
Name = "Contrato de prestação de serviços",
AutoClose = true,
});
// Adicionar documento
var document = await client.Documents.CreateAsync(new DocumentCreateParams
{
EnvelopeId = envelope.Id,
Filename = "contrato.pdf",
ContentBase64 = Convert.ToBase64String(File.ReadAllBytes("contrato.pdf")),
});
// Adicionar signatário
var signer = await client.Signers.CreateAsync(new SignerCreateParams
{
EnvelopeId = envelope.Id,
Name = "João Silva",
Email = "joao@example.com",
});
// Requisitos em lote (atômico)
await client.BulkRequirements.CreateAsync(envelope.Id, ops => ops
.AddAgree(signer.Id, document.Id, RequirementRole.Sign)
.AddProvideEvidence(signer.Id, document.Id, RequirementAuth.Email));
// Ativar
await client.Envelopes.ActivateAsync(envelope.Id);
Fluxo de assinatura (notarial)
1. Envelope
var envelope = await client.Envelopes.CreateAsync(new EnvelopeCreateParams
{
Name = "Proposta comercial #1042",
AutoClose = true,
DeadlineAt = DateTimeOffset.UtcNow.AddDays(30),
});
2. Documento
Envie o PDF em Base64 ou a partir de um template:
// Upload Base64
var document = await client.Documents.CreateAsync(new DocumentCreateParams
{
EnvelopeId = envelope.Id,
Filename = "contrato.pdf",
ContentBase64 = Convert.ToBase64String(File.ReadAllBytes("contrato.pdf")),
});
// A partir de template (.doc/.docx)
var fromTemplate = await client.Documents.CreateAsync(new DocumentCreateParams
{
EnvelopeId = envelope.Id,
Filename = "contrato.docx",
Template = new DocumentTemplate
{
Id = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
Fields = new Dictionary<string, string> { ["nome_cliente"] = "Empresa XYZ" },
},
});
3. Signatário
var signer = await client.Signers.CreateAsync(new SignerCreateParams
{
EnvelopeId = envelope.Id,
Name = "Maria Silva",
Email = "maria@example.com",
PhoneNumber = "11999998888",
CommunicateEvents = new CommunicateEvents
{
SignatureRequest = NotificationChannel.Email,
SignatureReminder = NotificationChannel.WhatsApp,
},
});
Assinatura presencial — configure SignatureHost:
var signer = await client.Signers.CreateAsync(new SignerCreateParams
{
EnvelopeId = envelope.Id,
Name = "João Silva",
Email = "joao@example.com",
SignatureHost = new SignatureHost
{
Name = "Maria Recepcionista",
Email = "maria@empresa.com",
CommunicateEvents = new CommunicateEvents
{
SignatureRequest = NotificationChannel.Email,
},
},
});
4. Requisitos de assinatura
Pré-requisito para ativar: ao menos um
Agree(comRole) e umProvideEvidence(comAuth) por par signatário/documento.
4.1 Endpoint padrão (um por chamada)
// Concordância
await client.Requirements.CreateAsync(new RequirementCreateParams
{
EnvelopeId = envelope.Id,
Action = RequirementAction.Agree,
Role = RequirementRole.Sign,
SignerId = signer.Id,
DocumentId = document.Id,
});
// Autenticação
await client.Requirements.CreateAsync(new RequirementCreateParams
{
EnvelopeId = envelope.Id,
Action = RequirementAction.ProvideEvidence,
Auth = RequirementAuth.Email,
SignerId = signer.Id,
DocumentId = document.Id,
});
4.2 Bulk atômico (múltiplos em uma chamada)
var response = await client.BulkRequirements.CreateAsync(envelope.Id, ops => ops
.AddAgree(signer.Id, document.Id, RequirementRole.Sign)
.AddProvideEvidence(signer.Id, document.Id, RequirementAuth.Email)
.AddRubricate(signer.Id, document.Id, RubricateKind.Initials));
if (!response.IsSuccess)
{
foreach (var failure in response.Failures)
Console.Error.WriteLine($"slot {failure.Index}: {string.Join(", ", failure.Errors)}");
}
| Abordagem | Endpoint | Quando usar |
|---|---|---|
| 4.1 Padrão | /requirements |
Criar requisitos um a um |
| 4.2 Bulk | /bulk_requirements |
Múltiplas ações; tratar sucesso/falha por slot |
5. Ativar o envelope
// Preferido — atalho semântico
await client.Envelopes.ActivateAsync(envelope.Id);
// Equivalente via PATCH
await client.Envelopes.UpdateAsync(envelope.Id, new EnvelopeUpdateParams
{
Status = EnvelopeStatus.Running,
});
6. Notificar signatários
// Todos
await client.Envelopes.NotifyAllAsync(envelope.Id, new NotificationParams
{
Message = "Por favor, assine o documento pendente.",
EmailCustomization = new EmailCustomization { Subject = "Assinatura pendente" },
});
// Signatário específico
await client.Signers.NotifyAsync(signer.Id, envelope.Id, new NotificationParams
{
Message = "Sua vez de assinar.",
});
7. Monitorar eventos
var events = await client.Events.ListForEnvelopeAsync(envelope.Id);
foreach (var evt in events)
Console.WriteLine($"{evt.Name} @ {evt.CreatedAt}");
var docEvents = await client.Documents.ListEventsAsync(document.Id, envelope.Id);
Filtros, ordenação e paginação
// Uma página com filtros
var page = await client.Envelopes.Filter()
.Where("status", "draft")
.OrderBy("-created_at")
.Page(1).PerPage(20)
.FetchAsync();
// Todas as páginas (segue links.next)
var all = await client.Envelopes.Filter()
.Where("status", "running")
.FetchAllAsync();
// Filtro em sub-resource
var docs = await client.Documents.Filter(envelope.Id)
.Where("status", "completed")
.FetchAsync();
ResourceQuery<T> está disponível em Envelopes, Documents, Signers, Requirements, Memberships e AcceptanceTermWhatsapps via .Filter().
Outros recursos
ClicksignClient |
Resource | Operações |
|---|---|---|
Envelopes |
Envelope | CRUD, Activate, NotifyAll, Filter |
Documents |
Document | CRUD, ListEvents, Filter |
Signers |
Signer | list, get, create, delete, Notify, Filter |
Requirements |
Requirement | list, get, create, delete, Filter |
BulkRequirements |
BulkRequirement | CreateAsync (atomic ops) |
SignatureWatchers |
SignatureWatcher | list, get, create, delete |
Events |
Event | ListForEnvelope, Create, CreateAddImage, CreateCustom |
Webhooks |
Webhook | CRUD |
Folders |
Folder | list, get, create |
Users |
User | list, get, Me, create |
Templates |
Template | CRUD, ListTemplateFields |
TemplateFields |
TemplateField | list, update, delete |
Memberships |
Membership | CRUD (update via PUT), Filter |
Groups |
Group | CRUD, AddUsers, RemoveUsers |
AccessControlLists |
AccessControlList | Create, Destroy |
EnvelopeBulkCreations |
EnvelopeBulkCreation | Create (job assíncrono) |
AcceptanceTermWhatsapps |
AcceptanceTermWhatsapp | list, CRUD, Cancel, Filter |
AutoSignatureTerms |
AutoSignatureTerm | get, create |
Mapa completo de endpoints: docs/SPEC.md.
Tratamento de erros
Todos os erros HTTP lançam exceções que herdam de ClicksignException:
| HTTP | Exceção | IsRetryable |
|---|---|---|
| 401, 403 | ClicksignAuthenticationException |
não |
| 404 | ClicksignNotFoundException |
não |
| 400, 422 | ClicksignValidationException |
não |
| 409 | ClicksignConflictException |
não |
| 429 | ClicksignRateLimitException |
sim |
| 503 | ClicksignServiceUnavailableException |
sim |
| 5xx | ClicksignServerException |
sim |
| Timeout | ClicksignTimeoutException |
sim |
using Clicksign.Errors;
try
{
await client.Envelopes.GetAsync("id-inexistente");
}
catch (ClicksignNotFoundException e)
{
Console.Error.WriteLine($"request_id={e.RequestId} body={e.ResponseBody}");
}
catch (ClicksignValidationException e)
{
Console.Error.WriteLine($"status={e.StatusCode} body={e.ResponseBody}");
}
catch (ClicksignRateLimitException e)
{
if (e.RetryAfter.HasValue)
await Task.Delay(e.RetryAfter.Value);
}
catch (ClicksignException e)
{
Console.Error.WriteLine(e.Message);
}
Propriedades comuns: StatusCode, RequestId (header x-request-id), ResponseBody, IsRetryable.
Guia detalhado: docs/TROUBLESHOOTING.md.
Ambientes
| Constante | URL base |
|---|---|
ClicksignEnvironment.Sandbox |
https://sandbox.clicksign.com/api/v3 |
ClicksignEnvironment.Production |
https://app.clicksign.com/api/v3 |
O padrão é produção. Para desenvolvimento use Sandbox. Gere tokens no painel do ambiente correspondente.
Timeouts, retry e instrumentação
Retry automático
Com MaxRetries > 0, o SDK reenvia automaticamente em erros transitórios (429, 503, 5xx, timeout) com backoff exponencial full-jitter:
ceiling = min(0.5 × 2^(attempt−1), 30)s espera em [0, ceiling)
Em 429/503 com header Retry-After, o SDK respeita o tempo indicado.
Hooks de instrumentação
var client = new ClicksignClient(new ClicksignClientOptions
{
ApiKey = apiKey,
MaxRetries = 3,
OnRequest = e => logger.LogInformation(
"clicksign {Method} {Path} → {Status} ({Duration}ms tentativa {Attempt})",
e.Method, e.Path, e.Status, (long)e.DurationMs, e.Attempt),
OnRetry = e => logger.LogWarning(
"clicksign retry {Attempt}/{MaxRetries} wait={Wait}ms error={Error}",
e.Attempt, e.MaxRetries, e.WaitMs, e.Error.GetType().Name),
OnError = e => logger.LogError(
"clicksign failed {Method} {Path} status={Status}: {Message}",
e.Method, e.Path, e.Status, e.Error.Message),
});
Detalhes e receitas para OpenTelemetry e System.Diagnostics.Metrics: docs/OBSERVABILITY.md.
Validação de webhook
using Clicksign.Webhook;
// Em ASP.NET Core
[HttpPost("/webhook")]
public async Task<IActionResult> Receive()
{
Request.EnableBuffering();
var payload = await new StreamReader(Request.Body).ReadToEndAsync();
var signature = Request.Headers["Content-HMAC"].ToString();
var secret = Environment.GetEnvironmentVariable("CLICKSIGN_WEBHOOK_SECRET")!;
WebhookValidator.VerifySignature(payload, signature, secret); // lança se inválido
// ...
return Ok();
}
// Ou como bool
bool valid = WebhookValidator.IsValidSignature(payload, signature, secret);
Use sempre o corpo bruto da requisição — nunca re-serializar o JSON antes de validar.
ASP.NET Core e DI
// Program.cs
builder.Services.AddSingleton<ClicksignClient>(_ =>
new ClicksignClient(new ClicksignClientOptions
{
ApiKey = builder.Configuration["Clicksign:ApiKey"]!,
Environment = ClicksignEnvironment.Production,
MaxRetries = 3,
}));
// Controller / Service
public class EnvelopeService(ClicksignClient clicksign)
{
public Task<Envelope> CreateAsync(string name, CancellationToken ct) =>
clicksign.Envelopes.CreateAsync(new EnvelopeCreateParams { Name = name }, ct);
}
ClicksignClient é thread-safe após construção — registre sempre como singleton. Veja docs/ARCHITECTURE.md.
Limitações e produção
| Tópico | Detalhe |
|---|---|
| Async | Todos os métodos de I/O são async/await — sem API síncrona exposta |
| Bulk retry | Apenas timeout, não 5xx — operações atômicas não são idempotentes |
| Thread safety | ClicksignClient imutável após construção; seguro para reuso entre threads |
| Multi-conta | Uma instância por token — use múltiplas instâncias para múltiplas contas |
Detalhes: docs/examples/08-production-limitations.md.
Desenvolvimento
dotnet test # todos os testes
dotnet test --filter "FullyQualifiedName~Envelope" # classe específica
dotnet format --verify-no-changes # lint
dotnet format # formatar
dotnet build # compilar
dotnet pack src/Clicksign --configuration Release --output ./dist # gerar Clicksign.NET.*.nupkg
Licença
MIT — veja LICENSE.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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 is compatible. 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. |
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.