Our Typescript SDK makes it easy to use markdown2pdf.ai in your agentic workflows. Whilst using our REST APIs is straightforward, there are some complexities (such as polling for payment completion and document generation) that the SDK handles for you.
If you run your TypeScript or ES module file (for example, via node test.ts) and see a warning like Module type of file is not specified and it doesn’t parse as CommonJS, you can add a "type": "module" (or "type": "commonjs") in your package.json (or rename your file to .mjs) to remove the warning.
With that done, you can try a sample code snippet:
Copy
import { convertMarkdownToPdf } from "@serendipityai/markdown2pdf-typescript";import type { OfferDetails } from "@serendipityai/markdown2pdf-typescript";async function pay(offer: OfferDetails) { console.log("⚡ Lightning payment required"); console.log(`Amount: ${offer.amount} ${offer.currency}`); console.log(`Description: ${offer.description}`); console.log(`Invoice: ${offer.payment_request}`); console.log("Press ENTER after completing the payment to continue..."); await new Promise< void >(resolve => { process.stdin.once("data", () => { resolve(); }); });}async function main() { const result = await convertMarkdownToPdf("# Hello from Typescript", { title: "My document title", downloadPath: "output.pdf", onPaymentRequest: pay }); console.log("Saved PDF to:", result);}main().catch(console.error);
This code converts your markdown into a PDF. If a Lightning payment is required, the SDK calls your onPaymentRequest callback (here our pay function) so that you can handle the payment (for example, by printing the invoice and waiting for manual confirmation). You can also integrate with services like fewsats.com or albyhub for automatic payments.
A TypeScript type that describes the payment offer details. This type is used in the onPaymentRequest callback.
Copy
type OfferDetails = { offer_id: string; // Unique identifier for the offer amount: number; // The payment amount currency: string; // The currency code (e.g., "usd") description: string; // Description of what the payment is for payment_context_token: string; // Token used for payment verification payment_request_url: string; // URL where the payment request can be viewed payment_request?: string; // Optional Lightning payment request (BOLT11 invoice)};
A TypeScript type that describes the configuration options for the convertMarkdownToPdf function.
Copy
type ConvertToPdfParams = { onPaymentRequest?: (offer: OfferDetails) => Promise<void>; // Callback for handling Lightning payments date?: string; // Date to display on the cover page title?: string; // Title to display on the cover page downloadPath?: string; // Path where the PDF should be saved returnBytes?: boolean; // Whether to return the PDF as a Buffer instead of saving to file apiUrl?: string; // Optional override for the API URL (for development/testing)};
async function convertMarkdownToPdf( markdown: string, options?: ConvertToPdfParams): Promise<string | Buffer>
Description:
Converts the provided markdown (a string) into a PDF. The function takes two parameters:
markdown: The markdown content to convert
options: An optional object containing configuration parameters for the conversion process
If a Lightning payment is required, the SDK calls your onPaymentRequest callback so that you can handle the payment. If onPaymentRequest is omitted and a payment is required, a PaymentRequiredError is thrown.
The SDK retrieves the final PDF; either saving it to downloadPath or returning it as a Buffer if returnBytes is true.
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 charged 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.
For example:
Copy
const result = await convertMarkdownToPdf("# Hello from Typescript", { title: "My document title", downloadPath: "output.pdf"});
A callback function that is called when a Lightning payment is required. The function receives an offer object containing payment details. This parameter is required because the service uses the L402 protocol, which requires a payment to be made before generating the PDF.
Copy
async function pay(offer: OfferDetails) { console.log("⚡ Lightning payment required"); console.log(`Amount: ${offer.amount} ${offer.currency}`); console.log(`Description: ${offer.description}`); console.log(`Invoice: ${offer.payment_request}`); await new Promise<void>(resolve => { process.stdin.once("data", () => { resolve(); }); });}const result = await convertMarkdownToPdf("# Hello from Typescript", { onPaymentRequest: pay, downloadPath: "output.pdf"});
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 Buffer. If set to false, it will save the PDF to the specified downloadPath or return the URL if no path is provided.
For example:
Copy
const pdfBytes = await convertMarkdownToPdf("# Memory use case", { returnBytes: true});console.log(`PDF size in memory: ${pdfBytes.length} bytes`);
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 undefined or omitted.
Returns
Condition
Resolves to
Type
downloadPath is provided and returnBytes is false
The value of downloadPath
string
returnBytes is true
The PDF as a Buffer
Buffer
Neither downloadPath nor returnBytes is provided/true
The final download URL
string
An error occurs (network, timeout, or payment required and no callback)
Rejects with error
Markdown2PdfError or PaymentRequiredError
The function always returns a Promise that resolves or rejects as described above.
If you want to automate Lightning payments (so that your “onPaymentRequest” callback pays the invoice automatically), you can integrate with a service (or Lightning wallet) such as fewsats.com or albyhub. (These services (or wallets) allow you to pay Lightning invoices “headlessly”.)
Below are two example integrations (using “fewsats” (via the Fewsats SDK) and “alby” (via axios) respectively):
Copy
import { convertMarkdownToPdf } from "@serendipityai/markdown2pdf-typescript";import axios from 'axios';import type { OfferDetails } from '@serendipityai/markdown2pdf-typescript';// Configure Alby clientconst ALBY_API_URL = 'https://api.getalby.com';const client = axios.create({ baseURL: ALBY_API_URL, headers: { 'Authorization': `Bearer ${process.env.ALBY_ACCESS_TOKEN}`, 'Content-Type': 'application/json' }});async function pay(offer: OfferDetails) { console.log("Paying using Alby:"); try { // Pay the invoice using Alby's API const response = await client.post('/payments/bolt11', { invoice: offer.payment_request }); if (response.status === 200) console.log('Payment successful:', response.data); else console.log('Payment status:', response.status); } catch (error) { if (axios.isAxiosError(error)) console.error('Payment failed:', error.response?.data || error.message); else console.error('Payment failed:', error); } await new Promise(resolve => { process.stdin.once("data", () => resolve(undefined)); });}async function main() { const path = await convertMarkdownToPdf("# Save this one using Alby", { downloadPath: "output.pdf", onPaymentRequest: pay }); console.log("Saved PDF to:", path);}main().catch(console.error);
Copy
import { convertMarkdownToPdf } from "@serendipityai/markdown2pdf-typescript";import axios from 'axios';import type { OfferDetails } from '@serendipityai/markdown2pdf-typescript';// Configure Alby clientconst ALBY_API_URL = 'https://api.getalby.com';const client = axios.create({ baseURL: ALBY_API_URL, headers: { 'Authorization': `Bearer ${process.env.ALBY_ACCESS_TOKEN}`, 'Content-Type': 'application/json' }});async function pay(offer: OfferDetails) { console.log("Paying using Alby:"); try { // Pay the invoice using Alby's API const response = await client.post('/payments/bolt11', { invoice: offer.payment_request }); if (response.status === 200) console.log('Payment successful:', response.data); else console.log('Payment status:', response.status); } catch (error) { if (axios.isAxiosError(error)) console.error('Payment failed:', error.response?.data || error.message); else console.error('Payment failed:', error); } await new Promise(resolve => { process.stdin.once("data", () => resolve(undefined)); });}async function main() { const path = await convertMarkdownToPdf("# Save this one using Alby", { downloadPath: "output.pdf", onPaymentRequest: pay }); console.log("Saved PDF to:", path);}main().catch(console.error);
Copy
import { convertMarkdownToPdf } from "@serendipityai/markdown2pdf-typescript";import axios from "axios";import type { OfferDetails } from '@serendipityai/markdown2pdf-typescript';// Constantsconst LN_BITS_URL = "https://demo.lnbits.com/api/v1/payments";const ADMIN_KEY = process.env.LNBITS_ADMIN_KEY as string; // Set in your envasync function pay(offer: OfferDetails) {console.log("Paying using lnbits:");try { const response = await axios.post( LN_BITS_URL, { out: true, bolt11: offer.payment_request }, { headers: { "X-Api-Key": ADMIN_KEY, "Content-Type": "application/json" } } ); console.log("Payment successful:", response.data);} catch (error) { if (axios.isAxiosError(error)) { console.error("Payment failed:", error.response?.data || error.message); } else { console.error("Unexpected error:", error); }}}async function main() {const path = await convertMarkdownToPdf("# Save this one using LNbits", { downloadPath: "output.pdf", onPaymentRequest: pay});console.log("Saved PDF to:", path);}main().catch(console.error);
Copy
import { convertMarkdownToPdf } from "@serendipityai/markdown2pdf-typescript";import type { OfferDetails } from '@serendipityai/markdown2pdf-typescript';import { Fewsats } from 'fewsats';// Configure the SDKconst client = new Fewsats({ apiKey: process.env.FEWSATS_API_KEY });async function pay(offer: OfferDetails) { console.log("Paying using Fewsats:"); console.log(offer); try { // Use the SDK to pay the offer const response = await client.payLightning(offer.payment_request, offer.amount, offer.currency, offer.description); if (response.success) { console.log('Payment successful:', response); } else { console.log('Payment failed:', response.error); } } catch (error) { console.error('Payment failed:', error.message); } await new Promise(resolve => { process.stdin.once("data", () => resolve(undefined)); });}async function main() { const path = await convertMarkdownToPdf("# Save this one using Fewsats", { downloadPath: "output.pdf", onPaymentRequest: pay }); console.log("Saved PDF to:", path);}main().catch(console.error);