Documents / TUTORIAL

Generate an invoice PDF from JSON

Send parties and line items, save a PDF and check the result before sending it to a customer.

This guide describes production API usage. The website demo has a separate, smaller anonymous allowance. Subscribe to an available listing before running the scripts.

Choose your marketplace

The complete scripts below target RapidAPI. Use the provider tabs for the matching base URL and authentication pattern; ApyHub capabilities may be split across listings and remain unavailable until published. Never use a pending listing as a production endpoint.

import os
import httpx

base_url = "https://document-generation-api-docx-html-pdf.p.rapidapi.com"
headers = {
    "X-RapidAPI-Key": os.environ["RAPIDAPI_KEY"],
    "X-RapidAPI-Host": "document-generation-api-docx-html-pdf.p.rapidapi.com",
}
payload = {
    "data": {
        "number": "INV-2026-0042",
        "date": "2026-10-16",
        "currency": "$",
        "seller": {
            "name": "Studio North",
            "address": ["1 Example Street"],
        },
        "buyer": {
            "name": "Acme Design",
        },
        "items": [{
                "description": "Design consultation",
                "quantity": 3,
                "unit_price": 85,
                "tax_rate": 0,
            }],
        "notes": "Sample invoice. Payment within 30 days.",
    },
    "format": "pdf",
}
response = httpx.post(
    base_url + "/v1/documents/preset/invoice",
    headers=headers, json=payload, timeout=120
)
response.raise_for_status()
with open("result.pdf", "wb") as output:
    output.write(response.content)

The invoice preset is the fastest path to a useful document. Send JSON and get a finished PDF—there is no template upload or base64 encoding to manage.

cURL

Set your RapidAPI key once, then run the request:

export RAPIDAPI_KEY='your-key-from-rapidapi'

curl --fail-with-body --request POST \
  --url 'https://document-generation-api-docx-html-pdf.p.rapidapi.com/v1/documents/preset/invoice' \
  --header 'content-type: application/json' \
  --header 'x-rapidapi-host: document-generation-api-docx-html-pdf.p.rapidapi.com' \
  --header "x-rapidapi-key: ${RAPIDAPI_KEY}" \
  --data '{
    "data": {
      "number": "INV-1042",
      "date": "2026-09-22",
      "currency": "$",
      "seller": {"name": "Example Studio", "email": "billing@example.com"},
      "buyer": {"name": "Ada Lovelace"},
      "items": [
        {"description": "Consulting", "quantity": 2, "unit_price": 95, "tax_rate": 10}
      ],
      "notes": "Payment due within 30 days."
    },
    "format": "pdf"
  }' \
  --output invoice.pdf

Check that cURL succeeded before opening invoice.pdf. The preset calculates the subtotal, tax and total from the line items.

Python

Install the dependency with python -m pip install requests; keep RAPIDAPI_KEY set in the same terminal.

import os
from pathlib import Path

import requests

host = "document-generation-api-docx-html-pdf.p.rapidapi.com"
response = requests.post(
    f"https://{host}/v1/documents/preset/invoice",
    headers={
        "x-rapidapi-host": host,
        "x-rapidapi-key": os.environ["RAPIDAPI_KEY"],
    },
    json={
        "data": {
            "number": "INV-1042",
            "date": "2026-09-22",
            "currency": "$",
            "seller": {"name": "Example Studio"},
            "buyer": {"name": "Ada Lovelace"},
            "items": [
                {
                    "description": "Consulting",
                    "quantity": 2,
                    "unit_price": 95,
                    "tax_rate": 10,
                }
            ],
        },
        "format": "pdf",
    },
    timeout=65,
)
response.raise_for_status()
if "application/pdf" not in response.headers.get("content-type", ""):
    raise ValueError("Expected application/pdf; set format=pdf.")
Path("invoice.pdf").write_bytes(response.content)

Choose another output

  • pdf returns a final PDF.
  • docx returns an editable Word document.
  • html returns browser-ready markup.
  • json returns a data URI plus render metadata, which is convenient for JSON-only workflows.

The same request pattern works with the receipt, certificate, letter and report presets. Call GET /v1/presets to discover their field schemas and samples.

If you receive 401, confirm that both RapidAPI headers are present. For 429, wait before retrying and check the allowance for your subscribed plan. For a validation error, use the structured error details to correct the named field.

Allowance and output review

Every API call and retry may consume allowance. A monthly quota error needs a renewed allowance or a plan change. Fix 422 errors before retrying; honor Retry-After and use a finite attempt and job budget for temporary 429/502/503 responses. Coordinate pacing across workers. Inspect the returned file or report before using it downstream. See the Developer guide’s limits and Privacy Notice.

Make it part of your application.

Get credentials and a production allowance from an available marketplace.

RRapidAPI
Complete APIGet access
aApyHub
Generate invoice documentsGet access