Skip to main content

Official Python SDK for the Clicksign e-signature API (v3)

Project description

Clicksign Python SDK

versão CI Python TestPyPI PyPI licença documentação API v3

Cliente Python para a Clicksign API v3 (JSON:API). Requer Python >= 3.10, sem dependências de runtime (apenas stdlib). Documentação detalhada em docs/.


Índice


Fluxo completo: docs/WORKFLOW.md — envelope → documento → signatário → ativação passo a passo.

Examples: docs/examples/ — receitas prontas para retry, webhooks, multi-tenant, observabilidade e connection pool.

Contrato do SDK: docs/SDK_CONTRACT.md — timeouts, retry, JSON:API, erros e paginação.

Observabilidade: docs/OBSERVABILITY.md — hooks, log, correlation id, structlog, OpenTelemetry, PII.


Instalação

Versão atual: 0.1.2 (disponível no TestPyPI; PyPI de produção em breve).

pip install --index-url https://test.pypi.org/simple/ \
  --extra-index-url https://pypi.org/simple/ \
  clicksign-python-sdk==0.1.2

Quando publicado no PyPI de produção:

pip install clicksign-python-sdk==0.1.2

O módulo importado continua sendo clicksign (import clicksign).

Extras opcionais:

pip install clicksign-python-sdk[httpx]   # connection pooling (alto QPS)
pip install clicksign-python-sdk[async]   # AsyncClicksignClient (requer httpx)

Configuração

Dois padrões principais — escolha com base em como sua aplicação gerencia credenciais:

Padrão Quando usar
configure() + resources Uma API key por processo; scripts; workers simples
ClicksignClient Múltiplas keys; dependências explícitas; código novo

Configuração global (single tenant)

import clicksign
from clicksign import Envelope, Document

clicksign.configure(
    api_key="YOUR_API_KEY",
    environment="sandbox",  # or "production"
)

envelopes = Envelope.list()
envelope = Envelope.create(name="Contrato", locale="pt-BR")
document = Document.create(
    envelope.id,
    filename="contrato.pdf",
    content_base64="...",
)

Cliente explícito (ClicksignClient)

from clicksign import ClicksignClient

client = ClicksignClient(api_key="YOUR_API_KEY", environment="sandbox")

envelopes = client.notarial.envelopes.list()
envelope = client.notarial.envelopes.create(name="Contrato", locale="pt-BR")

# Alias direto (shorthand)
envelope = client.envelopes.retrieve(envelope.id)
envelope.update(name="Contrato atualizado")

Multi-conta

Para apps multi-tenant onde cada requisição/job usa uma API key diferente, use Services para vincular um cliente à thread atual:

from clicksign import Envelope, Services

tenant = Services(api_key="TENANT_API_KEY", environment="sandbox")

with tenant.use():
    Envelope.list()  # roteado pelo cliente deste tenant

Services.use() define cliente HTTP e bulk para a thread. Em runtime async/fiber, prefira ClicksignClient ou AsyncClicksignClient explícito — contexto thread-local pode não se propagar.


Timeouts, retry e instrumentação

Timeouts por requisição

from clicksign import ClicksignClient, RequestOptions

client = ClicksignClient(api_key="YOUR_API_KEY", environment="sandbox")

client.envelopes.create(
    name="Contrato",
    options=RequestOptions(
        read_timeout=30.0,
        open_timeout=5.0,
    ),
)

Timeouts separados: open_timeout (TCP connect), write_timeout (envio do corpo), read_timeout (resposta).

Retry

Padrão 3 retries com full-jitter exponential backoff. Desative por chamada:

client.envelopes.retrieve("uuid", options={"max_retries": 0})

BulkRequirement.create retenta apenas TimeoutError — operações atômicas não são idempotentes.

Correlação de requisições

from clicksign import RequestOptions, correlation_id

client.envelopes.retrieve(
    "uuid",
    options=RequestOptions(headers=correlation_id("req-123")),
)

Em falhas, use error.request_id (header X-Request-Id) para tickets de suporte da Clicksign.

Hooks de instrumentação

import clicksign

clicksign.on_request(lambda e: print(e["method"], e["path"], e["status"]))
clicksign.on_retry(lambda e: print(e["attempt"], e["wait_ms"]))
clicksign.on_error(lambda e: print(e["error"]))

Veja docs/OBSERVABILITY.md para exemplos com structlog, OpenTelemetry e Prometheus, e como evitar PII em handlers on_error.

Log HTTP integrado

export CLICKSIGN_LOG=debug   # ou info, warn, error
clicksign.configure(log="debug")
# Usa stdlib logger "clicksign"; header Authorization nunca é logado.

Início rápido

from clicksign import ClicksignClient

client = ClicksignClient(api_key="YOUR_API_KEY", environment="sandbox")

# Criar envelope
envelope = client.notarial.envelopes.create(name="Contrato NDA", locale="pt-BR")

# Adicionar documento
doc = client.notarial.documents.create(
    envelope.id,
    filename="nda.pdf",
    content_base64="...",
)

# Adicionar signatário
signer = client.notarial.signers.create(
    envelope.id,
    name="Ana Souza",
    email="ana@example.com",
    has_documentation=True,
)

# Requisito de assinatura (atomic)
client.notarial.bulk_requirements.create(
    envelope.id,
    block=lambda ops: ops.add_agree(
        signer_id=signer.id,
        document_id=doc.id,
        role="sign",
    ),
)

# Ativar envelope
envelope.update(status="running")

Fluxo de assinatura (notarial)

1. Envelope

envelope = client.notarial.envelopes.create(name="Contrato", locale="pt-BR")
envelope.update(deadline_at="2025-12-31T23:59:59Z")

2. Documento

import base64

doc = client.notarial.documents.create(
    envelope.id,
    filename="contrato.pdf",
    content_base64=base64.b64encode(open("contrato.pdf", "rb").read()).decode(),
)

3. Signatário

signer = client.notarial.signers.create(
    envelope.id,
    name="João Silva",
    email="joao@example.com",
    has_documentation=True,
    documentation="123.456.789-09",
)

4. Requisitos de assinatura (bulk atômico)

client.notarial.bulk_requirements.create(
    envelope.id,
    block=lambda ops: (
        ops.add_agree(signer_id=signer.id, document_id=doc.id, role="sign"),
        ops.add_provide_evidence(signer_id=signer.id, document_id=doc.id, auth="email"),
    ),
)

5. Ativar

envelope.update(status="running")
# ou: Envelope.activate(envelope.id)  — POST /envelopes/:id/activate

6. Notificar signatários

from clicksign.resources.notarial.signer import Signer

# Um signatário (envelope_id e signer_id obrigatórios)
Signer.notify(envelope.id, signer.id, message="Seu contrato está disponível para assinatura.")

# Todos os pendentes do envelope
envelope.notify(message="Seu contrato está disponível para assinatura.")

Detalhes: docs/WORKFLOW.md (seção 6).

7. Monitorar eventos

from clicksign.resources.notarial.envelope import Envelope

for event in Envelope.list_events(envelope.id):
    print(event.name, event.created)

# Eventos por documento (ex.: read, sign, custom)
from clicksign.resources.notarial.document import Document

for event in Document.list_events(doc.id, envelope_id=envelope.id):
    print(event.name, event.data)

# Callbacks em tempo real: docs/examples/03-webhooks.md

Filtros, ordenação e paginação

# QueryProxy chain
drafts = (
    client.envelopes
    .filter(status="draft")
    .order("-created_at")
    .per(20)
    .with_includes("folder")
    .to_list()
)

# Auto-paginação (itera todas as páginas)
for envelope in client.envelopes.filter(status="running"):
    print(envelope.id)

# page() + per() explícitos
page1 = client.envelopes.page(1).per(10).to_list()

per() máximo 50 — veja docs/PAGINATION.md.

JSON:API sideload (included)

envelopes = client.envelopes.with_includes("folder").to_list()
print(envelopes[0].folder.name)  # sem chamada HTTP extra

Outros recursos

Namespace Resource
client.notarial.envelopes Envelope
client.notarial.documents Document
client.notarial.signers Signer
client.notarial.requirements Requirement
client.notarial.bulk_requirements BulkRequirement
client.notarial.signature_watchers SignatureWatcher
— (nested) EventEnvelope.list_events, Document.list_events, Event.create_for_document
client.webhooks Webhook
client.users User
client.templates / client.template_fields Template, TemplateField
client.memberships / client.groups Membership, Group
client.folders Folder
client.access_control_lists AccessControlList
client.envelope_bulk_creations EnvelopeBulkCreation
client.acceptance_term.whatsapps Whatsapp
client.auto_signature.terms Term

Endpoints sem resource dedicado:

raw = client.raw_request("get", "/beta/feature")
envelope = client.deserialize(raw, Envelope)
print(envelope.last_response.status)

User-Agent e identificação da aplicação

clicksign.set_app_info("My CRM", "2.1.0", "https://example.com")
# User-Agent: clicksign-python/x.y.z Python/3.10.x My_CRM/2.1.0

Telemetria do provider (opt-in)

clicksign.configure(enable_telemetry=True)

Envia métricas de latência anonimizadas (sem API keys nem corpos). Desativado por padrão.


Tratamento de erros

from clicksign.errors import (
    AuthenticationError,
    PermissionError,
    NotFoundError,
    ValidationError,
    RateLimitError,
    ServerError,
    TimeoutError,
)

try:
    client.envelopes.create(name="")
except ValidationError as err:
    print(err.message)          # primeiro detalhe (compatível)
    print(err.error_code)       # código do primeiro erro
    print(err.source_pointer)   # ex: /data/attributes/name
    for api_error in err.api_errors:
        print(api_error.pointer, api_error.detail)
except RateLimitError as err:
    print(err.rate_limit_reset)
except ServerError as err:
    if err.retryable:
        ...
Exceção Status HTTP
AuthenticationError 401
PermissionError 403
NotFoundError 404
ValidationError 400, 422
RateLimitError 429
ServerError 5xx
TimeoutError timeout de rede

Ambientes

Ambiente Base URL
sandbox https://sandbox.clicksign.com/api/v3
production https://app.clicksign.com/api/v3
client = ClicksignClient(api_key="...", environment="production")

Async (FastAPI, asyncio)

Requer pip install clicksign-python-sdk[async]. Receita completa: docs/examples/13-async-fastapi.md.

import asyncio
from clicksign import AsyncClicksignClient

async def main():
    async with AsyncClicksignClient(api_key="YOUR_API_KEY", environment="sandbox") as client:
        envelopes = await client.notarial.envelopes.list()
        async for env in client.envelopes.filter(status="draft"):
            print(env.id)
        envelope = await client.envelopes.retrieve("uuid")
        await envelope.update_async(status="running")
        # Ativar: await client.notarial.envelopes.activate(envelope.id)

asyncio.run(main())
  • Não use Services.use() no asyncio — use AsyncClicksignClient explícito.
  • Paginação: .page(n) só vale com .first(); .to_list() auto-pagina desde a página 1 — docs/PAGINATION.md.

HTTP transport e connection pool

Padrão: UrllibHTTPClient (stdlib, sem connection pool — um handshake TCP/TLS por requisição). Adequado para scripts e baixo QPS.

Alto QPS: instale clicksign-python-sdk[httpx] e injete um cliente compartilhado:

from clicksign import ClicksignClient, HttpxHTTPClient

http = HttpxHTTPClient()  # um por processo / worker
client = ClicksignClient(api_key="...", environment="production", http_client=http)

AsyncClicksignClient usa httpx com connection pool no event loop.

Receita singleton: docs/examples/12-http-connection-pool.md.


Limitações e produção

  • UrllibHTTPClient não reutiliza conexões — use HttpxHTTPClient sob carga.
  • Services.use() usa threading.local() — incompatível com asyncio/trio.
  • Operações bulk atômicas retentam apenas TimeoutError (não são idempotentes).
  • Includes aninhados dependem do que a API retorna; tipos desconhecidos fazem fallback para Resource base.

Veja docs/examples/08-production-limitations.md.


Desenvolvimento

pip install -e ".[dev]"
pytest
pytest --cov=clicksign --cov-report=term-missing
ruff format .
ruff check .
mypy

Licença

MIT — veja LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

clicksign_python_sdk-0.1.3.tar.gz (43.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

clicksign_python_sdk-0.1.3-py3-none-any.whl (74.1 kB view details)

Uploaded Python 3

File details

Details for the file clicksign_python_sdk-0.1.3.tar.gz.

File metadata

  • Download URL: clicksign_python_sdk-0.1.3.tar.gz
  • Upload date:
  • Size: 43.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for clicksign_python_sdk-0.1.3.tar.gz
Algorithm Hash digest
SHA256 3e449ae85c7b62a43c5b8d55672cbb706acf581bf84feef44950b36cc2353874
MD5 e60b04a4f7cd624f6a2488796d489160
BLAKE2b-256 c4122188327c5e54094cf6f4be24fa22f1828c30651a6332ef5771203fcd1983

See more details on using hashes here.

File details

Details for the file clicksign_python_sdk-0.1.3-py3-none-any.whl.

File metadata

File hashes

Hashes for clicksign_python_sdk-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 6967c67d9ec9612db9fd671735c04e1ebac24fbd02e3b916972cb84ad87facea
MD5 02f088f92e4f9001f9c9f988ef6611ab
BLAKE2b-256 d1cfde4fe8e3818b5dd32810872c635c73c6bb94a1c3dc8a4102084a5a0e404c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page