Python SDK for Assinafy API - Digital signature platform
Project description
Assinafy Python SDK
Python SDK for the Assinafy API.
The SDK is synchronous, uses httpx, and covers the documented API groups for authentication, documents, signers, signer documents, assignments, field definitions, templates, and webhooks.
Requirements
- Python 3.10+
httpx(installed automatically)
Installation
pip install assinafy
Quick Start
import os
from assinafy import AssinafyClient
client = AssinafyClient(
api_key=os.environ["ASSINAFY_API_KEY"],
account_id=os.environ["ASSINAFY_ACCOUNT_ID"],
webhook_secret=os.environ.get("ASSINAFY_WEBHOOK_SECRET"),
)
result = client.upload_and_request_signatures(
source={"file_path": "./contract.pdf"},
signers=[
{"full_name": "John Doe", "email": "john@example.com"},
{"full_name": "Jane Smith", "email": "jane@example.com"},
],
message="Please sign this contract",
)
print(result["document"]["id"])
Authentication
Prefer api_key; it is sent as the documented X-Api-Key header. token sends Authorization: Bearer <token> for legacy/user-token flows.
client = AssinafyClient(api_key="k_xxx", account_id="acc_xxx")
client = AssinafyClient(token="jwt_xxx", account_id="acc_xxx")
Unauthenticated clients are allowed for public and signer-access-code endpoints:
public_client = AssinafyClient()
session = public_client.authentication.login("user@example.com", "password")
Configuration
| Parameter | Type | Default | Description |
|---|---|---|---|
api_key |
str | None | Sent as X-Api-Key. |
token |
str | None | Sent as Authorization: Bearer <token>. |
account_id |
str | None | Default workspace/account ID for account-scoped methods. |
base_url |
str | https://api.assinafy.com.br/v1 |
API base URL. |
webhook_secret |
str | None | Secret used by WebhookVerifier. |
timeout |
float | 30.0 |
Request timeout in seconds. |
logger |
object | no-op | Object with debug/info/warn/error methods. |
Resources
Authentication
client.authentication.login("user@example.com", "password")
client.authentication.social_login("google", "provider-token", True)
client.authentication.create_api_key("password")
client.authentication.get_api_key()
client.authentication.delete_api_key()
client.authentication.change_password("user@example.com", "old", "new")
client.authentication.request_password_reset("user@example.com")
client.authentication.reset_password("user@example.com", "new", token="reset-token")
Documents
doc = client.documents.upload({"file_path": "./contract.pdf"})
doc = client.documents.upload({"buffer": pdf_bytes, "file_name": "contract.pdf"})
client.documents.statuses()
client.documents.list({"page": 1, "per_page": 20, "sort": "-updated_at"})
client.documents.get(doc["id"])
client.documents.activities(doc["id"])
client.documents.wait_until_ready(doc["id"])
client.documents.download(doc["id"], "certificated")
client.documents.thumbnail(doc["id"])
client.documents.download_page(doc["id"], page_id)
client.documents.verify(signature_hash)
client.documents.public_info(doc["id"])
client.documents.send_token(doc["id"], "signer@example.com", "email")
client.documents.delete(doc["id"])
Uploads follow the documented multipart shape and are locally limited to PDF files up to 25 MB.
Templates
templates = client.templates.list({"search": "NDA", "per_page": 20})
template = client.templates.get(template_id)
client.documents.create_from_template(
template_id,
[{"role_id": "role-id", "id": signer_id, "verification_method": "Email"}],
{"name": "NDA - John Doe", "message": "Please sign."},
)
client.documents.estimate_cost_from_template(
template_id,
[{"role_id": "role-id", "id": signer_id}],
)
Signers
signer = client.signers.create({
"full_name": "John Doe",
"email": "john@example.com",
})
client.signers.create({
"full_name": "Jane Doe",
"whatsapp_phone_number": "+5548999990000",
})
client.signers.get(signer["id"])
client.signers.list({"search": "john", "per_page": 50})
client.signers.update(signer["id"], {"full_name": "Johnny Doe"})
client.signers.delete(signer["id"])
client.signers.find_by_email("john@example.com")
Signer-access-code endpoints:
client.signers.get_self(signer_access_code)
client.signers.accept_terms(signer_access_code)
client.signers.verify_email(signer_access_code, "123456")
client.signers.confirm_data(
document_id,
signer_access_code,
{"email": "john@example.com", "has_accepted_terms": True},
)
client.signers.upload_signature(signer_access_code, png_bytes, "signature")
client.signers.download_signature(signer_access_code, "signature")
Assignments
client.assignments.estimate_cost(document_id, {"signers": [{"verification_method": "Email"}]})
assignment = client.assignments.create(document_id, {
"method": "virtual",
"signers": [{"id": signer["id"]}],
"message": "Please review and sign",
"expires_at": "2026-12-31T00:00:00Z",
})
client.assignments.reset_expiration(document_id, assignment["id"], "2027-01-31T00:00:00Z")
client.assignments.resend_notification(document_id, assignment["id"], signer["id"])
client.assignments.estimate_resend_cost(document_id, assignment["id"], signer["id"])
client.assignments.whatsapp_notifications(document_id, assignment["id"])
Signer-facing assignment endpoints:
client.assignments.get_for_signer(signer_access_code)
client.assignments.sign(document_id, assignment_id, [{"itemId": "item-1"}], signer_access_code)
client.assignments.decline(document_id, assignment_id, "I do not agree.", signer_access_code)
Signer Documents
client.signer_documents.current(signer_id, signer_access_code)
client.signer_documents.list(signer_id, signer_access_code, {"status": "pending_signature"})
client.signer_documents.sign_multiple(["doc-1", "doc-2"], signer_access_code)
client.signer_documents.decline_multiple(["doc-1"], "Unfavorable terms.", signer_access_code)
client.signer_documents.download(signer_id, document_id, signer_access_code, "original")
Field Definitions
field = client.fields.create({"type": "text", "name": "CPF"})
client.fields.list({"include_standard": True})
client.fields.get(field["id"])
client.fields.update(field["id"], {"name": "CPF updated"})
client.fields.validate(field["id"], "400.676.228-36", signer_access_code=signer_access_code)
client.fields.validate_multiple(
[{"field_id": field["id"], "value": "400.676.228-36"}],
signer_access_code=signer_access_code,
)
client.fields.list_types()
client.fields.delete(field["id"])
Webhooks
client.webhooks.register({
"url": "https://example.com/webhooks/assinafy",
"email": "admin@example.com",
"events": ["document_ready", "signer_signed_document"],
})
client.webhooks.get()
client.webhooks.inactivate()
client.webhooks.delete()
client.webhooks.list_event_types()
client.webhooks.list_dispatches({"delivered": False, "page": 1, "per_page": 20})
client.webhooks.retry_dispatch(dispatch_id)
Webhook Verification
signature = request.headers.get("X-Assinafy-Signature", "")
raw_body = request.get_data()
if not client.webhook_verifier.verify(raw_body, signature):
return "Invalid signature", 401
event = client.webhook_verifier.extract_event(raw_body)
event_type = client.webhook_verifier.get_event_type(event)
event_data = client.webhook_verifier.get_event_data(event)
Query Parameters
The SDK accepts Pythonic aliases for documented hyphenated query parameters. For example, per_page is sent as per-page, and signer_access_code is sent as signer-access-code.
Errors
The SDK raises typed errors; every failure raises a subclass of AssinafyError.
from assinafy import ApiError, AssinafyError, NetworkError, ValidationError
try:
client.documents.upload({"file_path": "./contract.pdf"})
except ValidationError as err:
print("Validation failed:", err.errors)
except ApiError as err:
print(f"API error {err.status_code}:", err.response_data)
except NetworkError as err:
print("Network error:", err)
except AssinafyError as err:
print("SDK error:", err, err.context)
Development
pip install -e ".[dev]"
pytest
mypy src
ruff check src tests
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file assinafy-1.1.1.tar.gz.
File metadata
- Download URL: assinafy-1.1.1.tar.gz
- Upload date:
- Size: 21.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3ac7c20e509a20cc9d0cc3bdeae0a052cdf9dfc044b32b6a7310db35c811471b
|
|
| MD5 |
20f5d95baa3daf0c5f62d14a8c77ec27
|
|
| BLAKE2b-256 |
95c705d0e1e8d3b1f7c4fe2318d0a4b22a670df9932bad40ecbfafdae9430a1b
|
Provenance
The following attestation bundles were made for assinafy-1.1.1.tar.gz:
Publisher:
release.yml on assinafy/python-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
assinafy-1.1.1.tar.gz -
Subject digest:
3ac7c20e509a20cc9d0cc3bdeae0a052cdf9dfc044b32b6a7310db35c811471b - Sigstore transparency entry: 1485953744
- Sigstore integration time:
-
Permalink:
assinafy/python-sdk@6fcec0ea85cd97271f0e1087e80fb66b32e3dcce -
Branch / Tag:
refs/tags/v1.1.1 - Owner: https://github.com/assinafy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6fcec0ea85cd97271f0e1087e80fb66b32e3dcce -
Trigger Event:
push
-
Statement type:
File details
Details for the file assinafy-1.1.1-py3-none-any.whl.
File metadata
- Download URL: assinafy-1.1.1-py3-none-any.whl
- Upload date:
- Size: 21.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
65341db24a3d58e21e70265bd84cf7e44f59d47404af0b5af06a0dff4f9a330e
|
|
| MD5 |
23875452d278fd3ac22f4d115fab7549
|
|
| BLAKE2b-256 |
88210505816ba33da64e2050481cab97e40c0b2fecb4120e0261c5ac08f54971
|
Provenance
The following attestation bundles were made for assinafy-1.1.1-py3-none-any.whl:
Publisher:
release.yml on assinafy/python-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
assinafy-1.1.1-py3-none-any.whl -
Subject digest:
65341db24a3d58e21e70265bd84cf7e44f59d47404af0b5af06a0dff4f9a330e - Sigstore transparency entry: 1485953789
- Sigstore integration time:
-
Permalink:
assinafy/python-sdk@6fcec0ea85cd97271f0e1087e80fb66b32e3dcce -
Branch / Tag:
refs/tags/v1.1.1 - Owner: https://github.com/assinafy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6fcec0ea85cd97271f0e1087e80fb66b32e3dcce -
Trigger Event:
push
-
Statement type: