Skip to main content

Official Python SDK for html2pdf service - convert HTML to PDF with ease

Project description

html2pdf-sdk

Official Python SDK for the html2pdf service - convert HTML to PDF with ease.

PyPI version Python License: MIT

Features

  • 🚀 Simple & Intuitive API - Easy to use, powerful capabilities
  • 🐍 Python 3.9+ - Full type hints and modern Python features
  • Async/Await Support - Both sync and async clients available
  • 🔄 Sync & Async Rendering - Choose based on your needs
  • 📦 Batch Processing - Render multiple PDFs efficiently
  • 🎨 Template Support - Use pre-built templates (invoices, reports, etc.)
  • 🔐 Webhook Integration - Get notified when jobs complete
  • Compliance - PDF/A, PDF/UA, WCAG, PDF/X validation
  • 🔄 Automatic Retries - Built-in retry logic for resilience
  • 📊 Progress Tracking - Monitor long-running jobs
  • 🎯 Type Safe - Comprehensive type hints with Pydantic models

Installation

pip install html2pdf-sdk
poetry add html2pdf-sdk
uv add html2pdf-sdk

Quick Start

Synchronous Usage

from html2pdf import Html2PdfClient
from html2pdf.types import RenderRequest, RenderOptions, Margins

# Initialize the client
client = Html2PdfClient(
    base_url="https://api.rendly.cloud",
    api_key="your-api-key"
)

# Render HTML to PDF (synchronous)
result = client.render.create(RenderRequest(
    html="<h1>Hello World</h1>",
    options=RenderOptions(
        page_size="A4",
        margins=Margins(
            top="1in",
            right="1in",
            bottom="1in",
            left="1in"
        )
    )
))

# Save the PDF
with open("output.pdf", "wb") as f:
    f.write(result.pdf)

print(f"Generated {result.metadata.pages} pages in {result.metadata.duration_ms}ms")

Asynchronous Usage

from html2pdf import AsyncHtml2PdfClient
from html2pdf.types import RenderRequest, RenderOptions
import asyncio

async def main():
    async with AsyncHtml2PdfClient(
        base_url="https://api.rendly.cloud",
        api_key="your-api-key"
    ) as client:
        result = await client.render.acreate(RenderRequest(
            html="<h1>Hello World</h1>",
            options=RenderOptions(page_size="A4")
        ))

        with open("output.pdf", "wb") as f:
            f.write(result.pdf)

        print(f"Generated {result.metadata.pages} pages")

asyncio.run(main())

Authentication

The SDK supports two authentication methods:

API Key Authentication

client = Html2PdfClient(
    base_url="https://api.rendly.cloud",
    api_key="your-api-key"
)

JWT Token Authentication

client = Html2PdfClient(
    base_url="https://api.rendly.cloud",
    access_token="your-jwt-token"
)

Core Features

Synchronous Rendering

For quick rendering (max 5MB HTML, 30s timeout):

result = client.render.create(RenderRequest(
    html="<h1>Invoice</h1><p>Total: $100</p>",
    options=RenderOptions(
        page_size="A4",
        print_background=True,
        margins=Margins(top="1in", right="1in", bottom="1in", left="1in")
    )
))

with open("invoice.pdf", "wb") as f:
    f.write(result.pdf)

Asynchronous Rendering

For large documents or complex pages:

# Submit the job
job = client.render.create_async(RenderRequest(
    url="https://example.com/large-report",
    options=RenderOptions(
        page_size="Letter",
        display_header_footer=True,
        header_template='<div style="font-size: 10px;">Report Header</div>',
        footer_template='<div style="font-size: 10px;">Page <span class="pageNumber"></span></div>'
    )
))

print(f"Job created: {job.job_id}")

# Poll for status
import time
while True:
    status = client.render.get_status(job.job_id)
    if status.status == "succeeded":
        pdf = client.render.download(job.job_id)
        with open("output.pdf", "wb") as f:
            f.write(pdf)
        break
    elif status.status == "failed":
        print(f"Render failed: {status.error.message}")
        break
    time.sleep(1)

Render and Wait (Simplified Async)

result = client.render.render_and_wait(
    RenderRequest(
        url="https://example.com",
        options=RenderOptions(page_size="A4")
    ),
    poll_interval=1.0,
    max_wait_time=300.0,
    on_progress=lambda status: print(f"Status: {status.status}")
)

with open("output.pdf", "wb") as f:
    f.write(result.pdf)

Batch Processing

Process multiple PDFs in parallel:

from html2pdf.types import BatchRequest, BatchItem

# Create a batch
batch = client.batch.create(BatchRequest(
    items=[
        BatchItem(
            mode="html",
            html="<h1>Document 1</h1>",
            item_id="doc1",
            options=RenderOptions(page_size="A4")
        ),
        BatchItem(
            mode="url",
            url="https://example.com/page1",
            item_id="doc2",
            options=RenderOptions(page_size="Letter")
        ),
        BatchItem(
            mode="html",
            html="<h1>Document 3</h1>",
            item_id="doc3"
        )
    ]
))

print(f"Batch created: {batch.batch_id}")

# Wait for completion
result = client.batch.wait_for_completion(
    batch.batch_id,
    on_progress=lambda status: print(f"Progress: {status.completed}/{status.total}")
)

# Download all PDFs as a ZIP
if result.status == "completed":
    zip_data = client.batch.download_zip(batch.batch_id)
    with open("batch-results.zip", "wb") as f:
        f.write(zip_data)

Batch from CSV

csv_data = """
mode,html,url,itemId
html,"<h1>Doc 1</h1>",,doc1
url,,https://example.com,doc2
html,"<h1>Doc 3</h1>",,doc3
"""

batch = client.batch.create_from_csv(csv_data)

Bulk Status Check

from html2pdf.types import BulkStatusRequest

statuses = client.batch.bulk_status(BulkStatusRequest(
    job_ids=["job_1", "job_2", "job_3"]
))

for job_id, status in statuses.jobs.items():
    print(f"{job_id}: {status.status}")

Template Rendering

Use pre-built templates for common documents:

from html2pdf.types import TemplateRenderRequest

result = client.templates.render(TemplateRenderRequest(
    template="invoice",
    data={
        "invoiceNumber": "INV-001",
        "date": "2024-01-15",
        "customerName": "John Doe",
        "items": [
            {
                "description": "Consulting Services",
                "quantity": 10,
                "price": 150,
                "total": 1500
            },
            {
                "description": "Software License",
                "quantity": 1,
                "price": 500,
                "total": 500
            }
        ],
        "subtotal": 2000,
        "tax": 200,
        "total": 2200
    },
    options=RenderOptions(
        page_size="A4",
        print_background=True
    )
))

with open("invoice.pdf", "wb") as f:
    f.write(result.pdf)

Validate Template Data

from html2pdf.types import TemplateValidateRequest

validation = client.templates.validate(TemplateValidateRequest(
    template="invoice",
    data={"invoiceNumber": "INV-001"}
))

if not validation.valid:
    print("Validation errors:", validation.errors)

Preview Template

html = client.templates.preview(
    template="certificate",
    data={
        "name": "John Doe",
        "achievement": "Course Completion",
        "date": "2024-01-15"
    }
)

print(html)

Webhooks

Get notified when rendering jobs complete:

from html2pdf.types import WebhookConfig

# Register a webhook
client.webhooks.create(WebhookConfig(
    url="https://myapp.com/webhooks/html2pdf",
    secret="your-secret-key-min-16-chars",
    events=["job.completed", "job.failed", "batch.completed"],
    enabled=True
))

# Get webhook config
webhook = client.webhooks.get()
print(f"Webhook: {webhook.url}")

# Update webhook
client.webhooks.update(WebhookConfig(
    url="https://myapp.com/webhooks/html2pdf",
    secret="your-secret-key",
    events=["job.completed", "batch.completed"],
    enabled=False
))

# Delete webhook
client.webhooks.delete()

Verify Webhook Signatures

In your webhook endpoint (Flask example):

from flask import Flask, request
from html2pdf.resources.webhooks import WebhooksResource

app = Flask(__name__)

@app.route("/webhooks/html2pdf", methods=["POST"])
def handle_webhook():
    signature = request.headers.get("x-webhook-signature")
    body = request.get_data(as_text=True)
    secret = "your-secret-key"

    is_valid = WebhooksResource.verify_signature_local(body, signature, secret)

    if not is_valid:
        return {"error": "Invalid signature"}, 401

    # Process webhook event
    event = request.get_json()
    print(f"Event: {event['type']}, Job: {event['jobId']}")

    return {"status": "ok"}

FastAPI example:

from fastapi import FastAPI, Request, HTTPException
from html2pdf.resources.webhooks import WebhooksResource

app = FastAPI()

@app.post("/webhooks/html2pdf")
async def handle_webhook(request: Request):
    signature = request.headers.get("x-webhook-signature")
    body = await request.body()
    secret = "your-secret-key"

    is_valid = WebhooksResource.verify_signature_local(
        body.decode(), signature, secret
    )

    if not is_valid:
        raise HTTPException(status_code=401, detail="Invalid signature")

    event = await request.json()
    print(f"Event: {event['type']}, Job: {event['jobId']}")

    return {"status": "ok"}

Compliance & Validation

Validate PDFs against compliance standards:

from html2pdf.types import ComplianceCertificateRequest

with open("document.pdf", "rb") as f:
    pdf_data = f.read()

# Generate compliance certificate
certificate = client.compliance.generate_certificate(
    ComplianceCertificateRequest(
        pdf=pdf_data,
        standards=["pdfa", "pdfua", "wcag"],
        format="json"
    )
)

print(f"Certificate ID: {certificate.certificate_id}")

for result in certificate.results:
    print(f"{result.standard}: {'PASS' if result.compliant else 'FAIL'}")
    print(f"Score: {result.score}/100")

    if not result.compliant:
        print("Issues:")
        for issue in result.issues:
            print(f"  [{issue.severity}] {issue.message}")
            if issue.recommendation:
                print(f"    → {issue.recommendation}")

Specific Validations

# PDF/A validation
pdfa_result = client.compliance.validate_pdfa(pdf_data)

# PDF/UA (accessibility) validation
pdfua_result = client.compliance.validate_pdfua(pdf_data)

# WCAG compliance
wcag_result = client.compliance.validate_wcag(pdf_data)

# PDF/X (print production)
pdfx_result = client.compliance.validate_pdfx(pdf_data)

Advanced Options

Page Size Options

# Preset sizes
result = client.render.create(RenderRequest(
    html="<h1>Test</h1>",
    options=RenderOptions(
        page_size="A4"  # 'A4', 'Letter', 'Legal', 'A3', 'A5', 'Tabloid'
    )
))

# Custom dimensions
from html2pdf.types import CustomPageSize

result = client.render.create(RenderRequest(
    html="<h1>Test</h1>",
    options=RenderOptions(
        page_size=CustomPageSize(width="8.5in", height="11in")
    )
))

Headers and Footers

result = client.render.create(RenderRequest(
    html="<h1>Report</h1>",
    options=RenderOptions(
        display_header_footer=True,
        header_template="""
            <div style="font-size: 10px; width: 100%; text-align: center;">
                Company Report
            </div>
        """,
        footer_template="""
            <div style="font-size: 10px; width: 100%; text-align: center;">
                Page <span class="pageNumber"></span> of <span class="totalPages"></span>
            </div>
        """,
        margins=Margins(
            top="1in",
            bottom="1in",
            left="0.5in",
            right="0.5in"
        )
    )
))

PDF/A Compliance with Attachments

from html2pdf.types import PDFAttachment
import base64

with open("invoice.xml", "rb") as f:
    xml_content = f.read()

result = client.render.create(RenderRequest(
    html="<h1>Invoice</h1>",
    options=RenderOptions(
        compliance="pdfa-3",
        attachments=[
            PDFAttachment(
                filename="invoice.xml",
                content=base64.b64encode(xml_content).decode(),
                description="Structured invoice data (ZUGFeRD)",
                mime_type="text/xml",
                relationship="Data"
            )
        ]
    )
))

Digital Signatures

from html2pdf.types import DigitalSignature
import base64

with open("certificate.p12", "rb") as f:
    cert_data = f.read()

result = client.render.create(RenderRequest(
    html="<h1>Signed Document</h1>",
    options=RenderOptions(
        signature=DigitalSignature(
            certificate=base64.b64encode(cert_data).decode(),
            password="cert-password",
            reason="Document approval",
            contact_info="signer@example.com",
            location="New York, USA",
            name="John Doe"
        )
    )
))

Debug Mode

job = client.render.create_async(RenderRequest(
    html="<h1>Debug Test</h1>",
    options=RenderOptions(debug=True)
))

# Wait for completion
import time
while True:
    status = client.render.get_status(job.job_id)
    if status.status in ("succeeded", "failed"):
        break
    time.sleep(1)

# Download debug bundle (includes HTML, console logs, network errors, metadata)
if status.status == "succeeded":
    debug_zip = client.render.download_debug(job.job_id)
    with open("debug.zip", "wb") as f:
        f.write(debug_zip)

Error Handling

The SDK provides typed errors for better error handling:

from html2pdf import (
    Html2PdfError,
    ValidationError,
    AuthenticationError,
    RateLimitError,
    TimeoutError,
    NetworkError
)

try:
    result = client.render.create(RenderRequest(html="<h1>Test</h1>"))
except AuthenticationError as e:
    print(f"Authentication failed: {e.message}")
except RateLimitError as e:
    print(f"Rate limit exceeded: {e.message}")
except ValidationError as e:
    print(f"Validation error: {e.message}")
    print(f"Details: {e.details}")
except TimeoutError as e:
    print(f"Request timeout: {e.message}")
except NetworkError as e:
    print(f"Network error: {e.message}")
except Html2PdfError as e:
    print(f"Error [{e.status_code}]: {e.message}")
except Exception as e:
    print(f"Unknown error: {e}")

Configuration Options

client = Html2PdfClient(
    # Required
    base_url="https://api.rendly.cloud",

    # Authentication (choose one)
    api_key="your-api-key",
    # OR
    # access_token="your-jwt-token",

    # Optional
    timeout=60.0,  # Request timeout in seconds (default: 30.0)
    max_retries=5,  # Max retry attempts (default: 3)
    headers={  # Custom headers for all requests
        "X-Custom-Header": "value"
    }
)

Type Safety

The SDK is fully typed using Pydantic models:

from html2pdf import Html2PdfClient
from html2pdf.types import (
    RenderRequest,
    RenderOptions,
    PageSizeEnum,
    ComplianceStandard,
    Margins
)

# IDE autocomplete and type checking work seamlessly
options = RenderOptions(
    page_size=PageSizeEnum.A4,
    compliance=ComplianceStandard.PDFA_2,
    print_background=True,
    margins=Margins(
        top="1in",
        right="1in",
        bottom="1in",
        left="1in"
    )
)

request = RenderRequest(
    html="<h1>Test</h1>",
    options=options
)

Health Check

Check if the service is available:

is_healthy = client.health_check()
print(f"Service healthy: {is_healthy}")

Metrics

Get Prometheus metrics:

metrics = client.get_metrics()
print(metrics)

Context Managers

Both sync and async clients support context managers:

# Synchronous
with Html2PdfClient(...) as client:
    result = client.render.create(...)

# Asynchronous
async with AsyncHtml2PdfClient(...) as client:
    result = await client.render.acreate(...)

Requirements

  • Python 3.9 or higher
  • httpx >= 0.27.0
  • pydantic >= 2.0.0

Development

Setup

# Clone the repository
git clone https://github.com/nixbit-maker/Rendly.git
cd html2pdf/sdk-python

# Install dependencies
pip install -e ".[dev]"

Running Tests

pytest

Type Checking

mypy html2pdf

Linting and Formatting

ruff check html2pdf
ruff format html2pdf

License

MIT

Support

Contributing

Contributions are welcome! Please see CONTRIBUTING.md for details.

Changelog

See CHANGELOG.md for release notes.

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

html2pdf_sdk-1.0.0.tar.gz (23.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

html2pdf_sdk-1.0.0-py3-none-any.whl (28.7 kB view details)

Uploaded Python 3

File details

Details for the file html2pdf_sdk-1.0.0.tar.gz.

File metadata

  • Download URL: html2pdf_sdk-1.0.0.tar.gz
  • Upload date:
  • Size: 23.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for html2pdf_sdk-1.0.0.tar.gz
Algorithm Hash digest
SHA256 f551044f62baa3d0b1308237cf01d85cf5fee1b9b1af32577050b3a6c31d1e54
MD5 5e149a8ef9158078bd43e5056eaec34b
BLAKE2b-256 5026b245d55d7a934bad0408a1c68b9b48b3b0ec125caa868af043d5630716f6

See more details on using hashes here.

File details

Details for the file html2pdf_sdk-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: html2pdf_sdk-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 28.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for html2pdf_sdk-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 72ffb3b4c76ecffff911f3950961f0780190e71fc920e960828184d83a1ca46c
MD5 9ff14665526aaa29c9f0c77c79e96b9c
BLAKE2b-256 71f218dfaab83b3b0f596e006eba6a5fdaba626a43d61d4e048122684299b529

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page