turbodocx-sdk 0.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,530 @@
1
+ Metadata-Version: 2.4
2
+ Name: turbodocx-sdk
3
+ Version: 0.1.2
4
+ Summary: TurboDocx Python SDK - Digital signatures, document generation, and AI-powered workflows
5
+ Project-URL: Homepage, https://www.turbodocx.com
6
+ Project-URL: Documentation, https://www.turbodocx.com/docs
7
+ Project-URL: Repository, https://github.com/TurboDocx/SDK
8
+ Project-URL: Issues, https://github.com/TurboDocx/SDK/issues
9
+ Author-email: TurboDocx <team@turbodocx.com>
10
+ License: MIT
11
+ License-File: LICENSE
12
+ Keywords: api,digital-signature,document,document-automation,esignature,generation,sdk,turbodocx,turbosign
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Requires-Python: >=3.9
22
+ Requires-Dist: httpx>=0.24.0
23
+ Requires-Dist: pydantic>=2.0.0
24
+ Provides-Extra: dev
25
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
26
+ Requires-Dist: pytest-httpx>=0.21.0; extra == 'dev'
27
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
28
+ Description-Content-Type: text/markdown
29
+
30
+ [![TurboDocx](./banner.png)](https://www.turbodocx.com)
31
+
32
+ <div align="center">
33
+
34
+ # turbodocx-sdk
35
+
36
+ **Official Python SDK for TurboDocx**
37
+
38
+ [![PyPI Version](https://img.shields.io/pypi/v/turbodocx-sdk.svg)](https://pypi.org/project/turbodocx-sdk/)
39
+ [![PyPI Downloads](https://img.shields.io/pypi/dm/turbodocx-sdk)](https://pypi.org/project/turbodocx-sdk/)
40
+ [![Python Versions](https://img.shields.io/pypi/pyversions/turbodocx-sdk)](https://pypi.org/project/turbodocx-sdk/)
41
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
42
+
43
+ [Documentation](https://www.turbodocx.com/docs) • [API Reference](https://www.turbodocx.com/docs/api) • [Examples](#examples) • [Discord](https://discord.gg/NYKwz4BcpX)
44
+
45
+ </div>
46
+
47
+ ---
48
+
49
+ ## Features
50
+
51
+ - 🚀 **Production-Ready** — Battle-tested, processing thousands of documents daily
52
+ - ⚡ **Async-First** — Native asyncio support with sync wrappers available
53
+ - 🐍 **Pythonic API** — Idiomatic Python with type hints throughout
54
+ - 📝 **Full Type Hints** — Complete type annotations for IDE support
55
+ - 🛡️ **Pydantic Models** — Validated request/response models
56
+ - 🤖 **100% n8n Parity** — Same operations as our n8n community nodes
57
+
58
+ ---
59
+
60
+ ## Installation
61
+
62
+ ```bash
63
+ pip install turbodocx-sdk
64
+ ```
65
+
66
+ <details>
67
+ <summary>Other package managers</summary>
68
+
69
+ ```bash
70
+ # Poetry
71
+ poetry add turbodocx-sdk
72
+
73
+ # Pipenv
74
+ pipenv install turbodocx-sdk
75
+
76
+ # Conda
77
+ conda install -c conda-forge turbodocx-sdk
78
+ ```
79
+ </details>
80
+
81
+ ---
82
+
83
+ ## Quick Start
84
+
85
+ ### Async (Recommended)
86
+
87
+ ```python
88
+ import asyncio
89
+ import os
90
+ from turbodocx_sdk import TurboSign
91
+
92
+ async def main():
93
+ # 1. Configure with your API key and sender information
94
+ TurboSign.configure(
95
+ api_key=os.getenv("TURBODOCX_API_KEY"),
96
+ org_id=os.getenv("TURBODOCX_ORG_ID"),
97
+ sender_email=os.getenv("TURBODOCX_SENDER_EMAIL"), # REQUIRED
98
+ sender_name=os.getenv("TURBODOCX_SENDER_NAME") # OPTIONAL (but strongly recommended)
99
+ )
100
+
101
+ # 2. Send a document for signature
102
+ with open("contract.pdf", "rb") as f:
103
+ pdf_file = f.read()
104
+
105
+ result = await TurboSign.send_signature(
106
+ file=pdf_file,
107
+ document_name="Partnership Agreement",
108
+ recipients=[
109
+ {"name": "John Doe", "email": "john@example.com", "signingOrder": 1}
110
+ ],
111
+ fields=[
112
+ {
113
+ "type": "signature",
114
+ "recipientEmail": "john@example.com",
115
+ "template": {"anchor": "{signature1}", "placement": "replace", "size": {"width": 100, "height": 30}}
116
+ }
117
+ ]
118
+ )
119
+
120
+ print(f"Document ID: {result['documentId']}")
121
+
122
+ asyncio.run(main())
123
+ ```
124
+
125
+ ### Sync
126
+
127
+ ```python
128
+ from turbodocx_sdk import TurboSignSync
129
+
130
+ TurboSignSync.configure(api_key="your-api-key")
131
+
132
+ result = TurboSignSync.send_signature(
133
+ file_link="https://example.com/contract.pdf",
134
+ recipients=[{"name": "John Doe", "email": "john@example.com", "signingOrder": 1}],
135
+ fields=[{"type": "signature", "page": 1, "x": 100, "y": 500, "width": 200, "height": 50, "recipientOrder": 1}]
136
+ )
137
+ ```
138
+
139
+ ---
140
+
141
+ ## Configuration
142
+
143
+ ```python
144
+ from turbodocx_sdk import TurboSign
145
+ import os
146
+
147
+ # Basic configuration (REQUIRED)
148
+ TurboSign.configure(
149
+ api_key="your-api-key", # REQUIRED
150
+ org_id="your-org-id", # REQUIRED
151
+ sender_email="you@company.com", # REQUIRED - reply-to address for signature requests
152
+ sender_name="Your Company" # OPTIONAL but strongly recommended
153
+ )
154
+
155
+ # With environment variables (recommended)
156
+ TurboSign.configure(
157
+ api_key=os.environ["TURBODOCX_API_KEY"],
158
+ org_id=os.environ["TURBODOCX_ORG_ID"],
159
+ sender_email=os.environ["TURBODOCX_SENDER_EMAIL"],
160
+ sender_name=os.environ["TURBODOCX_SENDER_NAME"]
161
+ )
162
+
163
+ # With custom options
164
+ TurboSign.configure(
165
+ api_key=os.environ["TURBODOCX_API_KEY"],
166
+ org_id=os.environ["TURBODOCX_ORG_ID"],
167
+ sender_email=os.environ["TURBODOCX_SENDER_EMAIL"],
168
+ sender_name=os.environ["TURBODOCX_SENDER_NAME"],
169
+ base_url="https://custom-api.example.com", # Optional
170
+ timeout=30.0, # Optional: seconds
171
+ )
172
+ ```
173
+
174
+ **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.
175
+
176
+ ### Environment Variables
177
+
178
+ ```bash
179
+ # .env
180
+ TURBODOCX_API_KEY=your-api-key
181
+ TURBODOCX_ORG_ID=your-org-id
182
+ TURBODOCX_SENDER_EMAIL=you@company.com
183
+ TURBODOCX_SENDER_NAME=Your Company Name
184
+ ```
185
+
186
+ ```python
187
+ from dotenv import load_dotenv
188
+ import os
189
+ load_dotenv()
190
+
191
+ TurboSign.configure(
192
+ api_key=os.environ["TURBODOCX_API_KEY"],
193
+ org_id=os.environ["TURBODOCX_ORG_ID"],
194
+ sender_email=os.environ["TURBODOCX_SENDER_EMAIL"],
195
+ sender_name=os.environ["TURBODOCX_SENDER_NAME"]
196
+ )
197
+ ```
198
+
199
+ ---
200
+
201
+ ## API Reference
202
+
203
+ ### TurboSign
204
+
205
+ #### `create_signature_review_link()`
206
+
207
+ Upload a document for review without sending signature emails.
208
+
209
+ ```python
210
+ result = await TurboSign.create_signature_review_link(
211
+ file_link="https://example.com/contract.pdf",
212
+ recipients=[
213
+ {"name": "John Doe", "email": "john@example.com", "signingOrder": 1}
214
+ ],
215
+ fields=[
216
+ {"type": "signature", "page": 1, "x": 100, "y": 500, "width": 200, "height": 50, "recipientEmail": "john@example.com"}
217
+ ],
218
+ document_name="Service Agreement", # Optional
219
+ document_description="Q4 Contract", # Optional
220
+ sender_name="Acme Corp", # Optional
221
+ sender_email="contracts@acme.com", # Optional
222
+ cc_emails=["legal@acme.com"] # Optional
223
+ )
224
+
225
+ print(f"Preview URL: {result['previewUrl']}")
226
+ print(f"Document ID: {result['documentId']}")
227
+ ```
228
+
229
+ #### `send_signature()`
230
+
231
+ Upload a document and immediately send signature request emails.
232
+
233
+ ```python
234
+ result = await TurboSign.send_signature(
235
+ file_link="https://example.com/contract.pdf",
236
+ recipients=[
237
+ {"name": "Alice", "email": "alice@example.com", "signingOrder": 1},
238
+ {"name": "Bob", "email": "bob@example.com", "signingOrder": 2}
239
+ ],
240
+ fields=[
241
+ {"type": "signature", "recipientEmail": "alice@example.com", "page": 1, "x": 100, "y": 500, "width": 200, "height": 50},
242
+ {"type": "signature", "recipientEmail": "bob@example.com", "page": 1, "x": 100, "y": 600, "width": 200, "height": 50}
243
+ ]
244
+ )
245
+
246
+ for recipient in result["recipients"]:
247
+ print(f"{recipient['name']}: {recipient['signUrl']}")
248
+ ```
249
+
250
+ #### `get_status()`
251
+
252
+ Check the current status of a document.
253
+
254
+ ```python
255
+ status = await TurboSign.get_status("doc-uuid-here")
256
+
257
+ print(f"Status: {status['status']}") # 'pending', 'completed', 'voided'
258
+
259
+ for recipient in status["recipients"]:
260
+ print(f"{recipient['name']}: {recipient['status']}")
261
+ ```
262
+
263
+ #### `download()`
264
+
265
+ Download the signed document.
266
+
267
+ ```python
268
+ pdf_bytes = await TurboSign.download("doc-uuid-here")
269
+
270
+ # Save to file
271
+ with open("signed-contract.pdf", "wb") as f:
272
+ f.write(pdf_bytes)
273
+ ```
274
+
275
+ #### `void_document()`
276
+
277
+ Cancel a signature request.
278
+
279
+ ```python
280
+ await TurboSign.void_document("doc-uuid-here", reason="Contract terms changed")
281
+ ```
282
+
283
+ #### `resend_email()`
284
+
285
+ Resend signature request emails.
286
+
287
+ ```python
288
+ await TurboSign.resend_email("doc-uuid-here", recipient_ids=["recipient-uuid-1"])
289
+ ```
290
+
291
+ ---
292
+
293
+ ## Field Types
294
+
295
+ | Type | Description | Required | Auto-filled |
296
+ |:-----|:------------|:---------|:------------|
297
+ | `signature` | Signature field (draw or type) | Yes | No |
298
+ | `initials` | Initials field | Yes | No |
299
+ | `text` | Free-form text input | No | No |
300
+ | `date` | Date stamp | No | Yes (signing date) |
301
+ | `checkbox` | Checkbox / agreement | No | No |
302
+
303
+ ---
304
+
305
+ ## Examples
306
+
307
+ For complete, working examples including template anchors, advanced field types, and various workflows, see the [`examples/`](./examples/) directory:
308
+
309
+ - [`turbosign_send_simple.py`](./examples/turbosign_send_simple.py) - Send document directly with template anchors
310
+ - [`turbosign_basic.py`](./examples/turbosign_basic.py) - Create review link first, then send manually
311
+ - [`turbosign_advanced.py`](./examples/turbosign_advanced.py) - Advanced field types (checkbox, readonly, multiline text, etc.)
312
+
313
+ ### Sequential Signing
314
+
315
+ ```python
316
+ result = await TurboSign.send_signature(
317
+ file_link="https://example.com/contract.pdf",
318
+ recipients=[
319
+ {"name": "Employee", "email": "employee@company.com", "signingOrder": 1},
320
+ {"name": "Manager", "email": "manager@company.com", "signingOrder": 2},
321
+ {"name": "HR", "email": "hr@company.com", "signingOrder": 3}
322
+ ],
323
+ fields=[
324
+ # Employee signs first
325
+ {"type": "signature", "recipientEmail": "employee@company.com", "page": 1, "x": 100, "y": 400, "width": 200, "height": 50},
326
+ {"type": "date", "recipientEmail": "employee@company.com", "page": 1, "x": 320, "y": 400, "width": 100, "height": 30},
327
+ # Manager signs second
328
+ {"type": "signature", "recipientEmail": "manager@company.com", "page": 1, "x": 100, "y": 500, "width": 200, "height": 50},
329
+ # HR signs last
330
+ {"type": "signature", "recipientEmail": "hr@company.com", "page": 1, "x": 100, "y": 600, "width": 200, "height": 50}
331
+ ]
332
+ )
333
+ ```
334
+
335
+ ### Polling for Completion
336
+
337
+ ```python
338
+ import asyncio
339
+
340
+ async def wait_for_completion(document_id: str, max_attempts: int = 60):
341
+ for _ in range(max_attempts):
342
+ status = await TurboSign.get_status(document_id)
343
+
344
+ if status["status"] == "completed":
345
+ return await TurboSign.download(document_id)
346
+
347
+ if status["status"] == "voided":
348
+ raise Exception("Document was voided")
349
+
350
+ await asyncio.sleep(30) # Wait 30 seconds
351
+
352
+ raise TimeoutError("Timeout waiting for signatures")
353
+ ```
354
+
355
+ ### With FastAPI
356
+
357
+ ```python
358
+ from fastapi import FastAPI, HTTPException
359
+ from turbodocx_sdk import TurboSign
360
+ import os
361
+
362
+ app = FastAPI()
363
+ TurboSign.configure(api_key=os.environ["TURBODOCX_API_KEY"])
364
+
365
+ @app.post("/api/send-contract")
366
+ async def send_contract(pdf_url: str, recipients: list, fields: list):
367
+ try:
368
+ result = await TurboSign.send_signature(
369
+ file_link=pdf_url,
370
+ recipients=recipients,
371
+ fields=fields
372
+ )
373
+ return {"success": True, "document_id": result["documentId"]}
374
+ except Exception as e:
375
+ raise HTTPException(status_code=500, detail=str(e))
376
+ ```
377
+
378
+ ### With Django
379
+
380
+ ```python
381
+ from django.http import JsonResponse
382
+ from turbodocx_sdk import TurboSignSync
383
+ import os
384
+
385
+ TurboSignSync.configure(api_key=os.environ["TURBODOCX_API_KEY"])
386
+
387
+ def send_contract(request):
388
+ result = TurboSignSync.send_signature(
389
+ file_link=request.POST["pdf_url"],
390
+ recipients=request.POST["recipients"],
391
+ fields=request.POST["fields"]
392
+ )
393
+ return JsonResponse({"document_id": result["documentId"]})
394
+ ```
395
+
396
+ ---
397
+
398
+ ## Local Testing
399
+
400
+ The SDK includes a comprehensive manual test script to verify all functionality locally.
401
+
402
+ ### Running Manual Tests
403
+
404
+ ```bash
405
+ # Install dependencies
406
+ pip install -e .
407
+
408
+ # Run the manual test script
409
+ python manual_test.py
410
+ ```
411
+
412
+ ### What It Tests
413
+
414
+ The `manual_test.py` file tests all SDK methods:
415
+ - ✅ `create_signature_review_link()` - Document upload for review
416
+ - ✅ `send_signature()` - Send for signature
417
+ - ✅ `get_status()` - Check document status
418
+ - ✅ `download()` - Download signed document
419
+ - ✅ `void_document()` - Cancel signature request
420
+ - ✅ `resend_email()` - Resend signature emails
421
+
422
+ ### Configuration
423
+
424
+ Before running, update the hardcoded values in `manual_test.py`:
425
+ - `API_KEY` - Your TurboDocx API key
426
+ - `BASE_URL` - API endpoint (default: `http://localhost:3000`)
427
+ - `ORG_ID` - Your organization UUID
428
+ - `TEST_FILE_PATH` - Path to a test PDF/DOCX file
429
+ - `TEST_EMAIL` - Email address for testing
430
+
431
+ ### Expected Output
432
+
433
+ The script will:
434
+ 1. Upload a test document
435
+ 2. Send it for signature
436
+ 3. Check the status
437
+ 4. Test void and resend operations
438
+ 5. Print results for each operation
439
+
440
+ ---
441
+
442
+ ## Error Handling
443
+
444
+ ```python
445
+ from turbodocx_sdk import TurboSign, TurboDocxError
446
+
447
+ try:
448
+ await TurboSign.get_status("invalid-id")
449
+ except TurboDocxError as e:
450
+ print(f"Status: {e.status_code}")
451
+ print(f"Message: {e.message}")
452
+ print(f"Code: {e.code}")
453
+ except Exception as e:
454
+ print(f"Unexpected error: {e}")
455
+ ```
456
+
457
+ ### Common Error Codes
458
+
459
+ | Status | Meaning |
460
+ |:-------|:--------|
461
+ | `400` | Bad request — check your parameters |
462
+ | `401` | Unauthorized — check your API key |
463
+ | `404` | Document not found |
464
+ | `429` | Rate limited — slow down requests |
465
+ | `500` | Server error — retry with backoff |
466
+
467
+ ---
468
+
469
+ ## Type Hints
470
+
471
+ Full type hint support for IDE autocompletion:
472
+
473
+ ```python
474
+ from turbodocx_sdk import TurboSign
475
+ from turbodocx_sdk.types import (
476
+ PrepareForSigningOptions,
477
+ Recipient,
478
+ Field,
479
+ DocumentStatus
480
+ )
481
+
482
+ recipients: list[Recipient] = [
483
+ {"name": "John", "email": "john@example.com", "order": 1}
484
+ ]
485
+
486
+ fields: list[Field] = [
487
+ {"type": "signature", "page": 1, "x": 100, "y": 500, "width": 200, "height": 50, "recipientOrder": 1}
488
+ ]
489
+ ```
490
+
491
+ ---
492
+
493
+ ## Requirements
494
+
495
+ - Python 3.9+
496
+ - aiohttp (for async)
497
+ - requests (for sync)
498
+
499
+ ---
500
+
501
+ ## Related Packages
502
+
503
+ | Package | Description |
504
+ |:--------|:------------|
505
+ | [@turbodocx/sdk (JS)](../js-sdk) | JavaScript/TypeScript SDK |
506
+ | [turbodocx (Go)](../go-sdk) | Go SDK |
507
+ | [@turbodocx/n8n-nodes-turbodocx](https://www.npmjs.com/package/@turbodocx/n8n-nodes-turbodocx) | n8n community nodes |
508
+
509
+ ---
510
+
511
+ ## Support
512
+
513
+ - 📖 [Documentation](https://www.turbodocx.com/docs)
514
+ - 💬 [Discord](https://discord.gg/NYKwz4BcpX)
515
+ - 🐛 [GitHub Issues](https://github.com/TurboDocx/SDK/issues)
516
+ - 📧 [Email Support](mailto:support@turbodocx.com)
517
+
518
+ ---
519
+
520
+ ## License
521
+
522
+ MIT — see [LICENSE](./LICENSE)
523
+
524
+ ---
525
+
526
+ <div align="center">
527
+
528
+ [![TurboDocx](./footer.png)](https://www.turbodocx.com)
529
+
530
+ </div>
@@ -0,0 +1,8 @@
1
+ turbodocx_sdk/__init__.py,sha256=pJt6U1PAA8CB6aUo7A3ONKTWiVTU5xYWtcDz_ipPhmU,1443
2
+ turbodocx_sdk/http.py,sha256=WFKgyhEXawwN37pNgQhsuJ2swZuY5Z2-DwnaCyvdkw4,11467
3
+ turbodocx_sdk/modules/__init__.py,sha256=7hBrfcXIFdI0vQZvVEZeRJvSPb4qpUiRFuWzv414zW4,71
4
+ turbodocx_sdk/modules/sign.py,sha256=-qC0GYRzNoSXkkQwtcBwqCyroHBABuCAmldS941RE-A,17095
5
+ turbodocx_sdk-0.1.2.dist-info/METADATA,sha256=tFHYmVsi-Bp1joTiiucIRJI_vb3W5i9If8sI221xIEY,14984
6
+ turbodocx_sdk-0.1.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
7
+ turbodocx_sdk-0.1.2.dist-info/licenses/LICENSE,sha256=jrILGSYvBIS-t0T9oe4iq695wDGUg5979U7SF8su-0s,1066
8
+ turbodocx_sdk-0.1.2.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.28.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 TurboDocx
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.