POST
/v1/pdf/generate

Generate a PDF from HTML, URL, or Markdown

Quick Example
curl -X POST https://api.speedstein.com/v1/pdf/generate \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<html><body><h1>Hello World</h1></body></html>",
    "format": "A4",
    "margin": "1cm"
  }' \
  --output document.pdf

Request

Headers

HeaderValueRequired
AuthorizationBearer YOUR_API_KEY
Required
Content-Typeapplication/json
Required

Body Parameters

html
string
Required*

The HTML content to convert to PDF. Must be valid HTML5. Use this OR url (not both).

"html": "<html><body><h1>Title</h1><p>Content</p></body></html>"
url
string
Required*

URL to convert to PDF. Must be publicly accessible. Use this OR html (not both).

"url": "https://example.com/page-to-convert"
format
string
Optional

Page format. Default: A4

A4
A3
A5
Letter
Legal
Tabloid
"format": "A4"
margin
string | object
Optional

Page margins. Can be a single value (all sides) or an object with top, right, bottom, left.

"margin": "1cm" // All sides
"margin": { "top": "2cm", "right": "1.5cm", "bottom": "2cm", "left": "1.5cm" }
orientation
string
Optional

Page orientation. Default: portrait

portrait
landscape
"orientation": "landscape"
print_background
boolean
Optional

Print background graphics. Default: true

"print_background": true
scale
number
Optional

Scale of the webpage rendering. Range: 0.1 to 2. Default: 1

"scale": 1.2
wait_for
string
Optional

Wait condition before generating PDF:

load
domcontentloaded
networkidle0
networkidle2
"wait_for": "networkidle0"
header_html
string
Optional

HTML template for page header. Supports variables: {{pageNumber}}, {{totalPages}}, {{date}}

"header_html": "<div style='font-size:10px;text-align:center'>Page {{pageNumber}}</div>"
footer_html
string
Optional

HTML template for page footer. Supports same variables as header.

"footer_html": "<div style='font-size:9px;text-align:right'>{{pageNumber}} of {{totalPages}}</div>"

Response

200
Success
PDF generated successfully
{
  "id": "pdf_1a2b3c4d5e6f",
  "url": "https://storage.speedstein.com/pdfs/1a2b3c4d5e6f.pdf",
  "size": 45234,
  "pages": 3,
  "format": "A4",
  "generation_time_ms": 1847,
  "created_at": "2025-10-28T12:34:56Z",
  "expires_at": "2025-11-04T12:34:56Z"
}

Response Fields

  • id - Unique identifier for the PDF
  • url - Download URL (valid until expiration)
  • size - File size in bytes
  • pages - Number of pages in the PDF
  • format - Page format used
  • generation_time_ms - Time taken to generate PDF in milliseconds
  • created_at - ISO 8601 timestamp of creation
  • expires_at - ISO 8601 timestamp when URL expires (7-365 days based on tier)

Error Responses

400
Bad Request
{ "error": { "code": "invalid_request", "message": "Either 'html' or 'url' parameter is required" } }
401
Unauthorized
{ "error": { "code": "unauthorized", "message": "Invalid or missing API key" } }
429
Rate Limit Exceeded
{ "error": { "code": "rate_limit_exceeded", "message": "Too many requests. Please retry after 60 seconds.", "retry_after": 60 } }
402
Quota Exceeded
{ "error": { "code": "quota_exceeded", "message": "Monthly quota exceeded. Upgrade your plan or wait for reset.", "quota_reset_at": "2025-11-01T00:00:00Z" } }

Complete Examples

Node.js with async/await

const fetch = require('node-fetch');
const fs = require('fs').promises;

async function generatePDF() {
  try {
    const response = await fetch('https://api.speedstein.com/v1/pdf/generate', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.SPEEDSTEIN_API_KEY}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        html: '<html><body><h1>Invoice #12345</h1></body></html>',
        format: 'A4',
        margin: '1cm',
        print_background: true,
        footer_html: '<div style="font-size:9px;text-align:center">{{pageNumber}}</div>'
      })
    });

    if (!response.ok) {
      const error = await response.json();
      throw new Error(`API Error: ${error.error.message}`);
    }

    const metadata = await response.json();
    console.log('PDF generated:', metadata);

    // Download the PDF
    const pdfResponse = await fetch(metadata.url);
    const buffer = await pdfResponse.buffer();
    await fs.writeFile('invoice.pdf', buffer);

    console.log(`Saved as invoice.pdf (${metadata.size} bytes, ${metadata.pages} pages)`);
  } catch (error) {
    console.error('Error generating PDF:', error.message);
  }
}

generatePDF();

Python with requests

import os
import requests

def generate_pdf():
    response = requests.post(
        'https://api.speedstein.com/v1/pdf/generate',
        headers={
            'Authorization': f'Bearer {os.environ["SPEEDSTEIN_API_KEY"]}',
            'Content-Type': 'application/json'
        },
        json={
            'html': '<html><body><h1>Report</h1></body></html>',
            'format': 'A4',
            'margin': '2cm',
            'orientation': 'portrait',
            'print_background': True
        }
    )

    if response.status_code != 200:
        print(f"Error: {response.json()['error']['message']}")
        return

    metadata = response.json()
    print(f"PDF generated: {metadata['id']}")

    # Download the PDF
    pdf_response = requests.get(metadata['url'])
    with open('report.pdf', 'wb') as f:
        f.write(pdf_response.content)

    print(f"Saved as report.pdf ({metadata['size']} bytes)")

if __name__ == '__main__':
    generate_pdf()