How to Convert JSON to PDF with Python
This Python example converts a JSON file with the pdfRest Convert to PDF API Tool. It demonstrates multipart upload, hierarchy presentation, tagged output, page setup, typography, and explicit response handling.
Why Convert JSON to PDF with Python?
Python pipelines frequently write run metadata, validation results, and experiment configurations as JSON. Those files are ideal for further processing, but project leads and reviewers may need a PDF that can be annotated, distributed, or retained with other deliverables.
A data-science workflow offers a concrete case: after an evaluation run, Python can save model settings, dataset identifiers, metric values, and warning arrays as JSON. Converting that payload into a hierarchy-formatted PDF creates a readable experiment record without discarding the machine-readable source used for reproducibility.
When a developer needs to inspect literal JSON instead, source mode validates and pretty-prints the payload. Python automation can choose either presentation for each audience while using the same request to enforce page size, fonts, language metadata, and tagging.
Python Code Example for Converting JSON to PDF
import json
import os
import requests
# By default, we use the US-based API service. This is the primary endpoint for global use.
api_url = "https://api.pdfrest.com"
# For GDPR compliance and enhanced performance for European users, you can switch to the EU-based service by uncommenting the URL below.
# For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work
#api_url = "https://eu-api.pdfrest.com"
# This sample converts JSON input to a tagged PDF through multipart /pdf.
# It demonstrates structured_text_options and the format-specific conversion options.
input_path = "/path/to/sample.json"
options = json.loads(r'''{
"title": "Structured Content Sample",
"language": "en-US",
"enable_tagging": true,
"page_setup": {
"size": "Letter",
"orientation": "portrait",
"margin": {
"top": 36,
"right": 42,
"bottom": 36,
"left": 42
}
},
"style": {
"font": "Arial",
"heading_font": "Arial",
"code_font": "Courier",
"text_size": 11,
"text_color_rgb": [
34,
34,
34
],
"heading_scale": 1.35,
"table": {
"column_width_weights": [
2,
3,
2
],
"keep_header_with_first_row": true,
"repeat_headers_on_overflow": true,
"show_borders": true,
"border_width": 0.75,
"border_color_rgb": [
180,
188,
200
],
"header_fill_color_rgb": [
33,
64,
98
],
"header_text_color_rgb": [
255,
255,
255
],
"row_fill_color_rgb": [
250,
250,
252
],
"alternate_row_fill_color_rgb": [
235,
240,
246
],
"cell_padding": {
"top": 6,
"right": 8,
"bottom": 6,
"left": 8
}
}
},
"data_presentation": "hierarchy"
}''')
from requests_toolbelt import MultipartEncoder
with open(input_path, "rb") as input_file:
fields = {
"file": (os.path.basename(input_path), input_file, "text/plain"),
"structured_text_options": json.dumps(options),
}
form = MultipartEncoder(fields=fields)
response = requests.post(api_url + "/pdf", data=form, headers={
"Accept": "application/json",
"Content-Type": form.content_type,
"Api-Key": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
})
print("Response status code: " + str(response.status_code))
if response.ok:
print(json.dumps(response.json(), indent=2))
else:
print(response.text)
raise SystemExit(1)
Source: View the sample on GitHub
Breaking Down the Code
The Python JSON sample uses requests and MultipartEncoder from requests-toolbelt. Install both with python -m pip install requests requests-toolbelt when they are not already present.
import json import os import requests
This Python endpoint excerpt identifies the regional service used for JSON conversion:
# By default, we use the US-based API service. This is the primary endpoint for global use. api_url = "https://api.pdfrest.com" # For GDPR compliance and enhanced performance for European users, you can switch to the EU-based service by uncommenting the URL below. # For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work #api_url = "https://eu-api.pdfrest.com"
Python opens the .json input in binary mode and sends its base filename with the stream. /pdf uses that filename extension to infer the JSON input type.
# It demonstrates structured_text_options and the format-specific conversion options.
input_path = "/path/to/sample.json"
options = json.loads(r'''{
The options dictionary becomes pdfRest’s structured_text_options field. It supplies document metadata, explicitly requests tags, establishes Letter portrait pages and 36-point margins, and selects the fonts, text size, color, and JSON-specific presentation values.
{
"data_presentation": "hierarchy"
}
source is the default. It validates and parses the input, then pretty-prints normalized JSON syntax in a code-style block; original indentation and insignificant whitespace are not preserved. hierarchy removes the syntax and creates a nested list in which property names are bold and primitive values appear as key-value items.
Scalar arrays become ordinary nested values. Arrays containing objects or other arrays label their members Item 1, Item 2, and so on. The converter preserves JSON structure but intentionally does not infer application-specific report meaning. Malformed JSON is rejected in either presentation mode.
The sample’s shared style.table object does not affect JSON source or hierarchy output. It can be omitted when the profile is used only for JSON conversion.
For the JSON call, MultipartEncoder combines the file tuple with serialized structured_text_options. Its content_type, including the boundary, becomes the request’s Content-Type header.
with open(input_path, "rb") as input_file:
fields = {
"file": (os.path.basename(input_path), input_file, "text/plain"),
"structured_text_options": json.dumps(options),
}
form = MultipartEncoder(fields=fields)
response = requests.post(api_url + "/pdf", data=form, headers={
"Accept": "application/json",
"Content-Type": form.content_type,
"Api-Key": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
})
requests.post sends the encoded JSON form with the API key. The script pretty-prints resource JSON after success and otherwise displays the API message before exiting with a nonzero status.
"file": (os.path.basename(input_path), input_file, "text/plain"),
"structured_text_options": json.dumps(options),
}
form = MultipartEncoder(fields=fields)
response = requests.post(api_url + "/pdf", data=form, headers={
"Accept": "application/json",
"Content-Type": form.content_type,
"Api-Key": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
})
print("Response status code: " + str(response.status_code))
if response.ok:
print(json.dumps(response.json(), indent=2))
Beyond the Tutorial
The pattern also suits pipeline manifests, data-quality output, API snapshots, and reproducibility records. Hierarchy mode clarifies nested values and arrays; source mode provides normalized syntax for comparison and debugging.
Tags establish logical structure for assistive and downstream software without constituting a formal conformance claim. Test realistic files in API Lab and use the Convert to PDF documentation for current requirements and limitations.