Português · Read in English
Cliente Python síncrono para a API Assinafy, com suporte a documentos, signatários, assignments, templates, campos, contratos, webhooks, autenticação e OAuth 2.1 com PKCE.
Requer Python 3.10+ e TLS 1.2 ou superior.
pip install assinafyUse uma chave de API para o seu workspace, um token para uma sessão de usuário ou OAuth para acessar o workspace conectado por outra pessoa.
import os
from assinafy import AssinafyClient
client = AssinafyClient(
api_key=os.environ["ASSINAFY_API_KEY"],
account_id=os.environ["ASSINAFY_ACCOUNT_ID"],
)| Modo | Enviado como | Uso |
|---|---|---|
| Chave de API | X-Api-Key |
seu próprio workspace |
| Token de acesso | Authorization: Bearer |
sessão obtida por authentication.login() |
| Código do signatário | signer-access-code na query |
ações da pessoa que assina |
| OAuth 2.1 + PKCE | Authorization: Bearer |
aplicativos de marketplace |
O cliente remove credenciais das rotas públicas, OAuth bearer-only e rotas autenticadas pelo código do signatário. Use https://sandbox.assinafy.com.br/v1 em base_url para o sandbox. URLs não loopback devem usar HTTPS. O cliente compartilha um pool de conexões; use with ou chame close().
O atalho abaixo envia o PDF, cria os signatários, espera o processamento e cria um assignment virtual:
with AssinafyClient(
api_key=os.environ["ASSINAFY_API_KEY"],
account_id=os.environ["ASSINAFY_ACCOUNT_ID"],
) as client:
result = client.upload_and_request_signatures(
source={"file_path": "./contrato.pdf"},
signers=[
{"full_name": "Pessoa Exemplo", "email": "signer@example.com"},
],
message="Por favor, assine o documento.",
)
document_id = result["document"]["id"]
assignment_id = result["assignment"]["id"]As etapas não são transacionais. Se uma etapa falhar, AssinafyError.context contém os IDs já criados. Para estimar custos, escolher o método de verificação ou controlar cada resposta, use os recursos diretamente:
document = client.documents.upload({"file_path": "./contrato.pdf"})
document = client.documents.wait_until_ready(document["id"])
signer = client.signers.create({
"full_name": "Pessoa Exemplo",
"email": "signer@example.com",
"government_id": "<cpf-ou-cnpj>",
})
request = {
"method": "virtual",
"message": "Por favor, assine o documento.",
"signers": [{
"id": signer["id"],
"verification_method": "Email",
"notification_methods": ["Email"],
"step": 1,
}],
}
estimate = client.assignments.estimate_cost(document["id"], request)
if estimate["has_sufficient_resources"]:
assignment = client.assignments.create(document["id"], request)
status = client.documents.get(document["id"])
if status["status"] == "completed":
pdf = client.documents.download(document["id"], "certificated")verification_method |
Notificação | Requisitos |
|---|---|---|
Email |
Email |
e-mail do signatário |
Whatsapp |
Whatsapp |
telefone WhatsApp e disponibilidade no plano |
IdDocumentFaceMatchBasic |
Email ou Whatsapp |
CPF, recurso biométrico e consentimento explícito |
DigitalCertificate |
Email ou Whatsapp |
CPF/CNPJ, recurso de certificado e assignment virtual |
Sem métodos informados, a API usa e-mail. Certificado digital aceita A1/A3 ICP-Brasil, exige que o signatário fique sozinho no passo e produz o artefato PAdES. Biometria usa uma captura hospedada; a URL retornada é uma credencial e não deve ser registrada.
No fluxo biométrico, consulte e inicie a captura somente após obter consentimento:
state = client.signers.identity_verification(signer_access_code)
capture = client.signers.start_identity_verification(signer_access_code, consent=True)O workspace consulta a evidência com assignments.identity_verification() e conclui a análise com assignments.review_identity_verification().
As ações do signatário usam apenas o código de acesso:
public_client = AssinafyClient()
public_client.signers.verify_code(signer_access_code, verification_code)
view = public_client.assignments.get_for_signer(signer_access_code)
public_client.signers.confirm_data(document_id, signer_access_code, {
"full_name": "Pessoa Exemplo", "email": "signer@example.com",
})
public_client.signers.accept_terms(signer_access_code)
signed = public_client.assignments.sign(
document_id, assignment_id, [], signer_access_code
)Crie documentos a partir de um template e espere o processamento antes de usar as páginas:
document = client.documents.create_from_template(
template_id,
[{"role_id": "role-id", "email": "signer@example.com", "name": "Pessoa Exemplo"}],
{"name": "Contrato de exemplo"},
)
document = client.documents.wait_until_ready(document["id"])client.contracts lista, lê e atualiza termos, relaciona instrumentos, renova e encerra contratos. Escritas aceitam updated_at para impedir a sobrescrita de uma versão mais recente.
Registre a aplicação e os redirect URIs na Assinafy. Guarde cada transação no servidor e consuma-a uma única vez:
oauth = client.oauth(
os.environ["ASSINAFY_CLIENT_ID"],
os.environ.get("ASSINAFY_CLIENT_SECRET"),
)
transaction = oauth.start_authorization(
"https://app.example.com/oauth/callback",
["documents:read", "documents:write"],
)
# Salve transaction na sessão autenticada e redirecione para authorization_url.
authorization_url = transaction["authorization_url"]
# No callback, use a query já analisada pelo framework.
code = oauth.handle_callback(callback_query, transaction)
tokens = oauth.exchange_code(code, transaction)
connected = AssinafyClient(token=tokens["access_token"])PKCE S256, state e iss são obrigatórios. O código expira rapidamente e é de uso único. Cada refresh token também é de uso único; substitua-o atomicamente pelo novo valor retornado:
new_tokens = oauth.refresh(tokens["refresh_token"])
oauth.revoke(new_tokens["refresh_token"], token_type_hint="refresh_token")Não repita automaticamente trocas ou renovações após erro de rede: a requisição pode ter sido aceita. Segredos, tokens, códigos e a transação OAuth devem permanecer no servidor.
Configure webhook_secret e valide o corpo bruto antes de analisar o JSON. Depois de validar, deduplique por webhook-id dentro da janela de assinatura.
client = AssinafyClient(webhook_secret=os.environ["ASSINAFY_WEBHOOK_SECRET"])
if not client.webhook_verifier.verify_delivery(raw_body, request_headers):
raise ValueError("Assinatura de webhook inválida")
event = client.webhook_verifier.extract_event(raw_body)Objetos e listas são devolvidos sem o envelope {status, message, data}. Listas paginadas têm {"data": [...], "meta": {...}}; downloads retornam bytes. O SDK nunca repete uma requisição automaticamente.
Capture AssinafyError; use ApiError.status_code, response_data, retry_after e os campos rate_limit_* para erros HTTP e limites. ValidationError ocorre antes de I/O e NetworkError representa falhas de transporte.
Cada método público documenta verbo, rota, corpo completo e resposta desembrulhada. Recursos disponíveis em AssinafyClient: accounts, assignments, authentication, contracts, documents, fields, signer_documents, signers, tags, templates, users, webhooks e a fábrica oauth().
ruff check src tests scripts
ruff format --check src tests scripts
mypy src scripts/live_smoke.py
pytest --cov=assinafy --cov-branch --cov-fail-under=90Licença MIT. Consulte a documentação oficial da API para scopes, limites, catálogos e schemas atuais.