Developer Guide

How to Sign PDFs with Python

3 steps to sign a PDF with Python: Install the TurboDocx SDK with pip install turbodocx-sdk, configure TurboSign.configure() with your API key, org ID, and sender email, then call the async TurboSign.send_signature() method with the file, recipients, and signature fields. TurboDocx emails each recipient a signing link and returns an audit trail once everyone has signed.

This guide shows you how to integrate e-signatures into your Django, FastAPI, or Flask application in under 5 minutes.

Last updated: September 23, 2026

5 min

Setup time

Python

Python 3.9+

Type hints included

Async-Native

Built on httpx

1

Installation

This is the digital signature SDK for Python developers who need e-signatures without building signing UI or PDF plumbing. Install it from PyPI; the package includes full type hints for IDE support.

pip / poetry
pip install turbodocx-sdk

Requirements: Python 3.9+. TurboSign is async-native; call it with await from asyncio, FastAPI, or Django async views, or run it from sync code with asyncio.run().

2

Obtaining an API Key

Before you begin, you'll need your API credentials from the TurboDocx dashboard.

  1. Sign up for a free account at TurboDocx
  2. Navigate to Settings → API Keys
  3. Copy your API Key and Organization ID
.env
TURBODOCX_API_KEY=your_api_key_here
TURBODOCX_ORG_ID=your_org_id_here
TURBODOCX_SENDER_EMAIL=you@company.com
TURBODOCX_SENDER_NAME=Your Company Name
3

Sending a Signing Request

Use the SDK to send a document for signature. The recipient will receive an email with a link to sign.

send_signature.py
import asyncio
import os
from turbodocx_sdk import TurboSign

async def main():
    # Configure with your API credentials
    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")      # Recommended
    )

    # Read PDF file
    with open("contract.pdf", "rb") as f:
        pdf_file = f.read()

    # Send document for signature
    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())

Tip: To check a document without waiting for a webhook, poll await TurboSign.get_status(result["documentId"]); it returns a status of under_review, completed, voided, or expired.

4

Processing Results with Webhooks

Configure webhooks to receive real-time notifications when documents are signed. Verify the X-TurboDocx-Signature header with verify_webhook_signature() before trusting a payload, using the raw request body rather than the parsed JSON.

webhook_handler.py (FastAPI)
import json
import os
from fastapi import FastAPI, Request, HTTPException
from turbodocx_sdk import TurboSign, verify_webhook_signature

app = FastAPI()

@app.post("/webhooks/turbosign")
async def handle_webhook(request: Request):
    # Use the raw body for verification; json.loads() first would change the bytes
    raw_body = await request.body()
    if not verify_webhook_signature(
        raw_body,
        request.headers.get("x-turbodocx-signature", ""),
        request.headers.get("x-turbodocx-timestamp", ""),
        os.getenv("TURBODOCX_WEBHOOK_SECRET"),
    ):
        raise HTTPException(status_code=401, detail="invalid signature")

    payload = json.loads(raw_body)
    event = payload.get("event")
    data = payload.get("data")

    if event == "signature.document.completed":
        document_id = data["document_id"]
        print(f"Document signed: {document_id}")

        # Download the signed PDF
        signed_pdf = await TurboSign.download(document_id)

        # Save to your storage
        with open(f"signed-{document_id}.pdf", "wb") as f:
            f.write(signed_pdf)

    return {"received": True}
5

Conclusion

You now have everything you need to integrate document signing into your Python application using the TurboDocx e-signature API. The async SDK handles authentication, document delivery, signature collection, and legally-binding audit trails.

What you can do next:

  • Add multiple recipients with sequential signing order
  • Use different field types: initials, dates, text, checkboxes
  • Poll TurboSign.get_status() or verify webhook deliveries for real-time status
  • Get audit trails and compliance certificates

Related Guides

Resources

Frequently Asked Questions

How do I sign a PDF with Python?

Install the TurboDocx SDK (pip install turbodocx-sdk), configure it with your API key, then use TurboSign.send_signature() to send the document for e-signature.

Is there a Python digital signature SDK for PDFs?

Yes. Running pip install turbodocx-sdk adds async document sending, status polling, webhook events, and audit trails to a Python codebase, so you avoid hand-building the HTTP calls and PDF handling.

Does the Python SDK support async/await?

Yes, the TurboDocx Python SDK is fully async-native and built on httpx. Call it from asyncio, FastAPI, or Django async views directly, or wrap a call in asyncio.run() to use it from synchronous code.

What Python version is required?

The TurboDocx Python SDK requires Python 3.9 or higher.

Ready to Get Started?

Create a free account and get your API key. Start sending documents for signature in minutes.