How to Convert CSV to PDF with cURL
This tutorial shows how to convert CSV to PDF with cURL and the pdfRest Convert to PDF API Tool. The request turns comma-separated data into a tagged table with configured columns, header styling, alternating row colors, borders, padding, and page behavior.
Why Convert CSV to PDF with cURL?
CSV is ideal for moving rows of data between spreadsheets, databases, and automated systems, but it does not define a dependable presentation. Opening the same file in different tools can change column widths, wrapping, and print layout, while nontechnical recipients may not know how the values are meant to be read.
A scheduled sales export illustrates the benefit. A shell job can retrieve regional totals as CSV, convert them to a PDF with a branded header row and right-aligned numeric column, and place the document in a shared reporting folder. If the data spans multiple pages, repeated headers keep each page understandable without manual spreadsheet formatting.
The conversion profile makes those decisions explicit and repeatable. It identifies the delimiter and header row, assigns relative widths and alignment by column, and controls borders, fills, padding, margins, and tagging so every generated report follows the same table design.
cURL Code Example for Converting CSV to PDF
#!/bin/sh
# 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 CSV input to a tagged PDF through multipart /pdf.
INPUT_PATH="/path/to/sample.csv"
OPTIONS='{"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}}},"csv":{"first_row_is_header":true,"delimiter":",","columns":[{"index":0,"width_weight":2,"text_align":"left"},{"index":1,"width_weight":3,"text_align":"left"},{"index":2,"width_weight":1,"text_align":"right"}]}}'
curl --location "$API_URL/pdf" \
--header "Accept: application/json" \
--header "Content-Type: multipart/form-data" \
--header "Api-Key: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" \
--form "file=@$INPUT_PATH" \
--form "structured_text_options=$OPTIONS" \
--form "output=pdf_from_csv"
Source: View the sample on GitHub
Breaking Down the Code
The CSV shell example calls cURL directly, so no language package is required. API_URL keeps regional routing visible: the active value uses the US service, and the commented alternative selects the EU service.
#!/bin/sh # 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 CSV input to a tagged PDF through multipart /pdf. INPUT_PATH="/path/to/sample.csv"
For this CSV request, the endpoint excerpt makes the regional service choice explicit:
# 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"
INPUT_PATH identifies the local .csv source. The @ prefix in the later --form argument instructs cURL to upload that file’s contents instead of sending its path as text.
# This sample converts CSV input to a tagged PDF through multipart /pdf.
INPUT_PATH="/path/to/sample.csv"
OPTIONS='{"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}}},"csv":{"first_row_is_header":true,"delimiter":",","columns":[{"index":0,"width_weight":2,"text_align":"left"},{"index":1,"width_weight":3,"text_align":"left"},{"index":2,"width_weight":1,"text_align":"right"}]}}'
The JSON assigned to OPTIONS is pdfRest-specific rather than shell syntax. title becomes document metadata, language identifies the document language, and enable_tagging explicitly requests logical structure. page_setup selects Letter portrait pages with 36-point margins, while style supplies fonts, text size, color, and format-specific presentation.
{
"csv": {
"first_row_is_header": true,
"delimiter": ",",
"columns": [
{
"index": 0,
"width_weight": 2,
"text_align": "left"
},
{
"index": 1,
"width_weight": 3,
"text_align": "left"
},
{
"index": 2,
"width_weight": 1,
"text_align": "right"
}
]
}
}
first_row_is_header defaults to true; setting it to false renders every record as a body row. delimiter defaults to a comma and must contain exactly one character, so a tab or semicolon can be selected but a multi-character separator cannot.
Column indexes are zero-based. Unspecified columns default to weight 1 and left alignment. Width weights are positive relative proportions, not points or pixels, and text_align accepts only left, center, or right. An index outside the parsed CSV, a nonpositive weight, or another alignment value produces a validation error.
The per-column CSV weights take precedence over style.table.column_width_weights; the broader table list is only a fallback when CSV-specific widths are absent. The remaining table style controls borders, colors, row striping, and padding. keep_header_with_first_row prevents a header from appearing alone, and repeat_headers_on_overflow repeats it as rows continue onto later pages.
For CSV conversion, the --form arguments create the multipart fields: file carries the structured source, structured_text_options carries serialized settings, and output names the requested PDF.
--header "Content-Type: multipart/form-data" \ --header "Api-Key: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" \ --form "file=@$INPUT_PATH" \ --form "structured_text_options=$OPTIONS" \ --form "output=pdf_from_csv"
The CSV request asks for JSON with Accept, declares multipart form data with Content-Type, and authenticates through Api-Key. Success returns the generated PDF resource and download URL; failure returns API error information.
# This sample converts CSV input to a tagged PDF through multipart /pdf.
INPUT_PATH="/path/to/sample.csv"
OPTIONS='{"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}}},"csv":{"first_row_is_header":true,"delimiter":",","columns":[{"index":0,"width_weight":2,"text_align":"left"},{"index":1,"width_weight":3,"text_align":"left"},{"index":2,"width_weight":1,"text_align":"right"}]}}'
curl --location "$API_URL/pdf" \
--header "Accept: application/json" \
--header "Content-Type: multipart/form-data" \
--header "Api-Key: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" \
--form "file=@$INPUT_PATH" \
--form "structured_text_options=$OPTIONS" \
--form "output=pdf_from_csv"
Beyond the Tutorial
This pattern works well for recurring operational reports, exports attached to support cases, and tabular snapshots that need to remain readable outside a spreadsheet application. Adjusting the column profile lets the same command accommodate identifiers, descriptions, dates, and numeric measures.
Tagged output adds logical table structure that can assist navigation and downstream processing, but it does not by itself certify accessibility conformance. Test profile variations in API Lab and consult the Convert to PDF documentation for the complete parameter contract.