TurboDocx Python SDK - Digital signatures, document generation, and AI-powered workflows
Project description
turbodocx-sdk
Official Python SDK for TurboDocx
The most developer-friendly DocuSign & PandaDoc alternative for e-signatures and document generation. Send documents for signature and automate document workflows programmatically.
Why TurboDocx?
A modern, developer-first alternative to legacy e-signature platforms:
| Looking for... | TurboDocx offers |
|---|---|
| DocuSign API alternative | Simple REST API, transparent pricing |
| PandaDoc alternative | Document generation + e-signatures in one SDK |
| HelloSign/Dropbox Sign alternative | Full API access, modern DX |
| Adobe Sign alternative | Quick integration, developer-friendly docs |
| SignNow alternative | Predictable costs, responsive support |
| Documint alternative | DOCX/PDF generation from templates |
| WebMerge alternative | Data-driven document automation |
Other platforms we compare to: SignRequest, SignEasy, Zoho Sign, Eversign, SignWell, Formstack Documents
TurboDocx Ecosystem
| Package | Description |
|---|---|
| @turbodocx/html-to-docx | Convert HTML to DOCX - fastest JS library |
| @turbodocx/n8n-nodes-turbodocx | n8n community nodes for TurboDocx |
| TurboDocx Writer | Microsoft Word add-in |
Features
- 🚀 Production-Ready — Battle-tested, processing thousands of documents daily
- ⚡ Async-First — Native asyncio support with sync wrappers available
- 🐍 Pythonic API — Idiomatic Python with type hints throughout
- 📝 Full Type Hints — Complete type annotations for IDE support
- 🛡️ Pydantic Models — Validated request/response models
- 🤖 100% n8n Parity — Same operations as our n8n community nodes
Installation
pip install turbodocx-sdk
Other package managers
# Poetry
poetry add turbodocx-sdk
# Pipenv
pipenv install turbodocx-sdk
# Conda
conda install -c conda-forge turbodocx-sdk
Quick Start
Async (Recommended)
import asyncio
import os
from turbodocx_sdk import TurboSign
async def main():
# 1. Configure with your API key and sender information
TurboSign.configure(
api_key=os.getenv("TURBODOCX_API_KEY"),
org_id=os.getenv("TURBODOCX_ORG_ID"),
sender_email=os.getenv("TURBODOCX_SENDER_EMAIL"), # REQUIRED
sender_name=os.getenv("TURBODOCX_SENDER_NAME") # OPTIONAL (but strongly recommended)
)
# 2. Send a document for signature
with open("contract.pdf", "rb") as f:
pdf_file = f.read()
result = await TurboSign.send_signature(
file=pdf_file,
document_name="Partnership Agreement",
recipients=[
{"name": "John Doe", "email": "john@example.com", "signingOrder": 1}
],
fields=[
{
"type": "signature",
"recipientEmail": "john@example.com",
"template": {"anchor": "{signature1}", "placement": "replace", "size": {"width": 100, "height": 30}}
}
]
)
print(f"Document ID: {result['documentId']}")
asyncio.run(main())
Sync
from turbodocx_sdk import TurboSignSync
TurboSignSync.configure(api_key="your-api-key")
result = TurboSignSync.send_signature(
file_link="https://example.com/contract.pdf",
recipients=[{"name": "John Doe", "email": "john@example.com", "signingOrder": 1}],
fields=[{"type": "signature", "page": 1, "x": 100, "y": 500, "width": 200, "height": 50, "recipientOrder": 1}]
)
Configuration
from turbodocx_sdk import TurboSign
import os
# Basic configuration (REQUIRED)
TurboSign.configure(
api_key="your-api-key", # REQUIRED
org_id="your-org-id", # REQUIRED
sender_email="you@company.com", # REQUIRED - reply-to address for signature requests
sender_name="Your Company" # OPTIONAL but strongly recommended
)
# With environment variables (recommended)
TurboSign.configure(
api_key=os.environ["TURBODOCX_API_KEY"],
org_id=os.environ["TURBODOCX_ORG_ID"],
sender_email=os.environ["TURBODOCX_SENDER_EMAIL"],
sender_name=os.environ["TURBODOCX_SENDER_NAME"]
)
# With custom options
TurboSign.configure(
api_key=os.environ["TURBODOCX_API_KEY"],
org_id=os.environ["TURBODOCX_ORG_ID"],
sender_email=os.environ["TURBODOCX_SENDER_EMAIL"],
sender_name=os.environ["TURBODOCX_SENDER_NAME"],
base_url="https://custom-api.example.com", # Optional
timeout=30.0, # Optional: seconds
)
Important: sender_email is REQUIRED. This email will be used as the reply-to address for signature request emails. Without it, emails will default to "API Service User via TurboSign". The sender_name is optional but strongly recommended for a professional appearance.
Environment Variables
# .env
TURBODOCX_API_KEY=your-api-key
TURBODOCX_ORG_ID=your-org-id
TURBODOCX_SENDER_EMAIL=you@company.com
TURBODOCX_SENDER_NAME=Your Company Name
from dotenv import load_dotenv
import os
load_dotenv()
TurboSign.configure(
api_key=os.environ["TURBODOCX_API_KEY"],
org_id=os.environ["TURBODOCX_ORG_ID"],
sender_email=os.environ["TURBODOCX_SENDER_EMAIL"],
sender_name=os.environ["TURBODOCX_SENDER_NAME"]
)
API Reference
TurboSign
create_signature_review_link()
Upload a document for review without sending signature emails.
result = await TurboSign.create_signature_review_link(
file_link="https://example.com/contract.pdf",
recipients=[
{"name": "John Doe", "email": "john@example.com", "signingOrder": 1}
],
fields=[
{"type": "signature", "page": 1, "x": 100, "y": 500, "width": 200, "height": 50, "recipientEmail": "john@example.com"}
],
document_name="Service Agreement", # Optional
document_description="Q4 Contract", # Optional
sender_name="Acme Corp", # Optional
sender_email="contracts@acme.com", # Optional
cc_emails=["legal@acme.com"] # Optional
)
print(f"Preview URL: {result['previewUrl']}")
print(f"Document ID: {result['documentId']}")
send_signature()
Upload a document and immediately send signature request emails.
result = await TurboSign.send_signature(
file_link="https://example.com/contract.pdf",
recipients=[
{"name": "Alice", "email": "alice@example.com", "signingOrder": 1},
{"name": "Bob", "email": "bob@example.com", "signingOrder": 2}
],
fields=[
{"type": "signature", "recipientEmail": "alice@example.com", "page": 1, "x": 100, "y": 500, "width": 200, "height": 50},
{"type": "signature", "recipientEmail": "bob@example.com", "page": 1, "x": 100, "y": 600, "width": 200, "height": 50}
]
)
for recipient in result["recipients"]:
print(f"{recipient['name']}: {recipient['signUrl']}")
get_status()
Check the current status of a document.
status = await TurboSign.get_status("doc-uuid-here")
print(f"Status: {status['status']}") # 'pending', 'completed', 'voided'
for recipient in status["recipients"]:
print(f"{recipient['name']}: {recipient['status']}")
download()
Download the signed document.
pdf_bytes = await TurboSign.download("doc-uuid-here")
# Save to file
with open("signed-contract.pdf", "wb") as f:
f.write(pdf_bytes)
void_document()
Cancel a signature request.
await TurboSign.void_document("doc-uuid-here", reason="Contract terms changed")
resend_email()
Resend signature request emails.
await TurboSign.resend_email("doc-uuid-here", recipient_ids=["recipient-uuid-1"])
get_audit_trail()
Get the complete audit trail for a document, including all events and timestamps.
audit = await TurboSign.get_audit_trail("doc-uuid-here")
print(f"Document: {audit['document']['name']}")
for entry in audit["auditTrail"]:
print(f"{entry['actionType']} - {entry['timestamp']}")
if entry.get("user"):
print(f" By: {entry['user']['name']} ({entry['user']['email']})")
if entry.get("recipient"):
print(f" Recipient: {entry['recipient']['name']}")
The audit trail includes a cryptographic hash chain for tamper-evidence verification.
Field Types
| Type | Description |
|---|---|
signature |
Signature field (draw or type) |
initials |
Initials field |
text |
Free-form text input |
date |
Date stamp |
checkbox |
Checkbox / agreement |
full_name |
Full name |
first_name |
First name |
last_name |
Last name |
email |
Email address |
title |
Job title |
company |
Company name |
Examples
For complete, working examples including template anchors, advanced field types, and various workflows, see the examples/ directory:
turbosign_send_simple.py- Send document directly with template anchorsturbosign_basic.py- Create review link first, then send manuallyturbosign_advanced.py- Advanced field types (checkbox, readonly, multiline text, etc.)
Sequential Signing
result = await TurboSign.send_signature(
file_link="https://example.com/contract.pdf",
recipients=[
{"name": "Employee", "email": "employee@company.com", "signingOrder": 1},
{"name": "Manager", "email": "manager@company.com", "signingOrder": 2},
{"name": "HR", "email": "hr@company.com", "signingOrder": 3}
],
fields=[
# Employee signs first
{"type": "signature", "recipientEmail": "employee@company.com", "page": 1, "x": 100, "y": 400, "width": 200, "height": 50},
{"type": "date", "recipientEmail": "employee@company.com", "page": 1, "x": 320, "y": 400, "width": 100, "height": 30},
# Manager signs second
{"type": "signature", "recipientEmail": "manager@company.com", "page": 1, "x": 100, "y": 500, "width": 200, "height": 50},
# HR signs last
{"type": "signature", "recipientEmail": "hr@company.com", "page": 1, "x": 100, "y": 600, "width": 200, "height": 50}
]
)
Polling for Completion
import asyncio
async def wait_for_completion(document_id: str, max_attempts: int = 60):
for _ in range(max_attempts):
status = await TurboSign.get_status(document_id)
if status["status"] == "completed":
return await TurboSign.download(document_id)
if status["status"] == "voided":
raise Exception("Document was voided")
await asyncio.sleep(30) # Wait 30 seconds
raise TimeoutError("Timeout waiting for signatures")
With FastAPI
from fastapi import FastAPI, HTTPException
from turbodocx_sdk import TurboSign
import os
app = FastAPI()
TurboSign.configure(api_key=os.environ["TURBODOCX_API_KEY"])
@app.post("/api/send-contract")
async def send_contract(pdf_url: str, recipients: list, fields: list):
try:
result = await TurboSign.send_signature(
file_link=pdf_url,
recipients=recipients,
fields=fields
)
return {"success": True, "document_id": result["documentId"]}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
With Django
from django.http import JsonResponse
from turbodocx_sdk import TurboSignSync
import os
TurboSignSync.configure(api_key=os.environ["TURBODOCX_API_KEY"])
def send_contract(request):
result = TurboSignSync.send_signature(
file_link=request.POST["pdf_url"],
recipients=request.POST["recipients"],
fields=request.POST["fields"]
)
return JsonResponse({"document_id": result["documentId"]})
Local Testing
The SDK includes a comprehensive manual test script to verify all functionality locally.
Running Manual Tests
# Install dependencies
pip install -e .
# Run the manual test script
python manual_test.py
What It Tests
The manual_test.py file tests all SDK methods:
- ✅
create_signature_review_link()- Document upload for review - ✅
send_signature()- Send for signature - ✅
get_status()- Check document status - ✅
download()- Download signed document - ✅
void_document()- Cancel signature request - ✅
resend_email()- Resend signature emails
Configuration
Before running, update the hardcoded values in manual_test.py:
API_KEY- Your TurboDocx API keyBASE_URL- API endpoint (default:http://localhost:3000)ORG_ID- Your organization UUIDTEST_FILE_PATH- Path to a test PDF/DOCX fileTEST_EMAIL- Email address for testing
Expected Output
The script will:
- Upload a test document
- Send it for signature
- Check the status
- Test void and resend operations
- Print results for each operation
Error Handling
from turbodocx_sdk import TurboSign, TurboDocxError
try:
await TurboSign.get_status("invalid-id")
except TurboDocxError as e:
print(f"Status: {e.status_code}")
print(f"Message: {e.message}")
print(f"Code: {e.code}")
except Exception as e:
print(f"Unexpected error: {e}")
Common Error Codes
| Status | Meaning |
|---|---|
400 |
Bad request — check your parameters |
401 |
Unauthorized — check your API key |
404 |
Document not found |
429 |
Rate limited — slow down requests |
500 |
Server error — retry with backoff |
Type Hints
Full type hint support for IDE autocompletion:
from turbodocx_sdk import TurboSign
from turbodocx_sdk.types import (
PrepareForSigningOptions,
Recipient,
Field,
DocumentStatus
)
recipients: list[Recipient] = [
{"name": "John", "email": "john@example.com", "order": 1}
]
fields: list[Field] = [
{"type": "signature", "page": 1, "x": 100, "y": 500, "width": 200, "height": 50, "recipientOrder": 1}
]
Requirements
- Python 3.9+
- aiohttp (for async)
- requests (for sync)
Related Packages
| Package | Description |
|---|---|
| @turbodocx/sdk (JS) | JavaScript/TypeScript SDK |
| turbodocx (Go) | Go SDK |
| @turbodocx/n8n-nodes-turbodocx | n8n community nodes |
Support
License
MIT — see 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
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 turbodocx_sdk-0.1.6.tar.gz.
File metadata
- Download URL: turbodocx_sdk-0.1.6.tar.gz
- Upload date:
- Size: 816.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9ea11f670ca56479ec5655d807baec0ffe631d25aff5b4b44182d0e0adc7c967
|
|
| MD5 |
cabb63efff5b706d5f6f54ce73382350
|
|
| BLAKE2b-256 |
ade1238d1ed1f032dd96b76ae0afe5b3db946aa4d9051985bf5632d801a818b9
|
Provenance
The following attestation bundles were made for turbodocx_sdk-0.1.6.tar.gz:
Publisher:
publish-py.yml on TurboDocx/SDK
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
turbodocx_sdk-0.1.6.tar.gz -
Subject digest:
9ea11f670ca56479ec5655d807baec0ffe631d25aff5b4b44182d0e0adc7c967 - Sigstore transparency entry: 920524614
- Sigstore integration time:
-
Permalink:
TurboDocx/SDK@debc5a5dd4b44f448f24bc8bb6368f0474b4a7a2 -
Branch / Tag:
refs/tags/py-sdk-v0.1.6 - Owner: https://github.com/TurboDocx
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-py.yml@debc5a5dd4b44f448f24bc8bb6368f0474b4a7a2 -
Trigger Event:
release
-
Statement type:
File details
Details for the file turbodocx_sdk-0.1.6-py3-none-any.whl.
File metadata
- Download URL: turbodocx_sdk-0.1.6-py3-none-any.whl
- Upload date:
- Size: 14.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
49817a2b700f0ac3a4272815d8070fc98fa56e395af133286342d82c832089b8
|
|
| MD5 |
fae6f7265e92cd39c413b518a4ded685
|
|
| BLAKE2b-256 |
56210f7707d9c2dce75e7327c76ad9f445f4f12a41896127925c9dcfe8ca360f
|
Provenance
The following attestation bundles were made for turbodocx_sdk-0.1.6-py3-none-any.whl:
Publisher:
publish-py.yml on TurboDocx/SDK
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
turbodocx_sdk-0.1.6-py3-none-any.whl -
Subject digest:
49817a2b700f0ac3a4272815d8070fc98fa56e395af133286342d82c832089b8 - Sigstore transparency entry: 920524671
- Sigstore integration time:
-
Permalink:
TurboDocx/SDK@debc5a5dd4b44f448f24bc8bb6368f0474b4a7a2 -
Branch / Tag:
refs/tags/py-sdk-v0.1.6 - Owner: https://github.com/TurboDocx
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-py.yml@debc5a5dd4b44f448f24bc8bb6368f0474b4a7a2 -
Trigger Event:
release
-
Statement type: