Getting started

github.com/Serendipity-AI/markdown2pdf-python

Our Python SDK makes it easy to use markdown2pdf.ai in your agentic workflows. Whilst using our REST APIs is straightforward, there are some complexities to handle around polling for payment completion and document generation that the SDK avoids you needing to worry about.

First up, you’ll need to install the SDK:

pip install markdown2pdf-python

With that done, you can try some sample code:

from markdown2pdf import MarkdownPDF

def pay(offer):
    print("⚡ Lightning payment required")
    print(f"Amount: {offer['amount']} {offer['currency']}")
    print(f"Description: {offer['description']}")
    print(f"Invoice: {offer['payment_request']}")
    input("Press Enter once paid...")

client = MarkdownPDF(on_payment_request=pay)
path = client.convert(markdown="# Insert your own markdown content here", title="My document title", download_path="output.pdf")
print("Saved PDF to:", path)

This code will convert the markdown content you provide into a PDF, prompting you to pay via Lightning Network if necessary. The on_payment_request function is called when payment is required, allowing you to handle the payment process in your application. There are several ways of handling payments automatically, such as fewsats.com or albyhub or using a Lightning wallet that supports automatic payments. In the example above, we simply print the payment details and wait for you to confirm payment manually. You can simply copy and paste the lightning invoice into your lightning wallet to pay.

SDK Reference

class MarkdownPDF

The main class for interacting with the markdown2pdf.ai service.

constructor

Used for initializing the MarkdownPDF client.

on_payment_request
function
required

This function is called when a payment is required. It receives an offer object containing details about the payment, such as amount, currency, description, and the Lightning invoice. You can implement your own logic to handle payments here. This parameter is required because the service uses the L402 protocol, which requires a payment to be made before generating the PDF.

def pay(offer):
    print("⚡ Lightning payment required")
    print(f"Amount: {offer['amount']} {offer['currency']}")
    print(f"Description: {offer['description']}")
    print(f"Invoice: {offer['payment_request']}")
    input("Press Enter once paid...")

client = MarkdownPDF(on_payment_request=pay)
offer = {
    "offer_id": "abc",
    "amount": 1,
    "currency": "usd",
    "description": "test payment",
    "payment_context_token": "def",
    "payment_request_url": "http://path.to/payment/request",
}
api_url
string

This parameter enables you to override the default API URL. This is typically used in development or testing environments, but for normal usage you won’t need to touch it and it can be set to None or omitted.

convert

Converts the provided markdown content into a PDF document. This method handles the payment process automatically if required, and saves a PDF to the specified path or returns it as bytes.

markdown
string
required

A string containing the markdown content you want to convert to PDF.

A note on markdown hashing

markdown2pdf.ai uses a hashing mechanism to ensure that you won’t get charge twice for creating the same PDF. Subsequent requests to convert the same markdown content will return the previously generated PDF without requiring a new payment.

Typically your markdown will come from the output of an LLM or AI agent. If you want to load some from a file, you can do it like this:

from markdown2pdf import MarkdownPDF
from pathlib import Path

def pay(offer):
    print("⚡ Lightning payment required")
    print(f"Amount: {offer['amount']} {offer['currency']}")
    print(f"Description: {offer['description']}")
    print(f"Invoice: {offer['payment_request']}")
    input("Press Enter once paid...")

client = MarkdownPDF(api_url="https://qa.api.markdown2pdf.ai", on_payment_request=pay)
markdown = Path("examples/md/Song of the silent stars.md").read_text(encoding="utf-8")
url = client.convert(markdown=markdown, title="Song of the silent stars", date="5th June 2025" ) 
print("PDF URL:", url)
date
string

A string containing the date to use on the front cover. If not provided, the current date will be used.

title
string

A string containing the title to use on the front cover. If not provided, a default will be used.

download_path
string

A string containing the path to use for saving the PDF file. If not provided, the PDF will be returned as bytes.

For example:

path = client.convert(markdown="# Save this one", download_path="output.pdf") 
print("Saved PDF to:", path)
return_bytes
boolean

Whether or not to return the PDF as bytes instead of saving it to a file. If set to True, the method will return the PDF content as a byte string. If set to False, it will save the PDF to the specified download_path or return the path if no path is provided.

For example:

pdf_bytes = client.convert(markdown="# Memory use case", return_bytes=True) 
print(f"PDF size in memory: {len(pdf_bytes)} bytes")

Automating payments

If you want to automate payments, you can use a service like fewsats.com or Albyhub. These services allow you to automatically pay Lightning invoices, completely headlessly.

from markdown2pdf import MarkdownPDF
from dotenv import load_dotenv
from pyalby import Account, Invoice, Payment

load_dotenv()
# In your .env file, ensure you have set the following. You can learn more about alby at https://albyhub.com.
# BASE_URL = https://api.getalby.com
# ALBY_ACCESS_TOKEN = <your_alby_access_token>
# LOG_LEVEL = INF

def pay(offer):
    print("Paying using Alby:")
    payment = Payment()
    pay = payment.bolt11_payment(offer["payment_request"])
    print(f"Payment made: {pay}")

client = MarkdownPDF(on_payment_request=pay)
path = client.convert(markdown="# Save this one using Alby", download_path="output.pdf") # Replace with your own unique markdown content to ensure you trigger L402.
print("Saved PDF to:", path)