Merge PDFs
Combine multiple PDF documents into a single file.
Merge PDFs
Combine multiple PDF documents into a single file. Supports 2-100 PDFs per request, with input from base64-encoded data or URLs.
POST
/v1/pdf/merge
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
pdfs | array | Yes | Array of PDF sources (2-100 items) |
storage | object | No | Storage options for the merged PDF |
PDF Source Object
Each item in the pdfs array must contain one of the following:
| Parameter | Type | Description |
|---|---|---|
data | string | Base64-encoded PDF content |
url | string | URL to fetch the PDF from |
Storage Object
| Parameter | Type | Default | Description |
|---|---|---|---|
enabled | boolean | false | Store the merged PDF for later retrieval |
filename | string | "merged.pdf" | Custom filename for storage |
Code Examples
curl -X POST https://api.pdfapi.dev/v1/pdf/merge \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"pdfs": [
{"data": "JVBERi0xLjQKMSAwIG9iago8PAovVHlwZSAvQ2F0YWxvZwo..."},
{"url": "https://example.com/document.pdf"},
{"data": "JVBERi0xLjQKMiAwIG9iago8PAovVHlwZSAvUGFnZQo..."}
],
"storage": {
"enabled": true,
"filename": "merged-report.pdf"
}
}' \
--output merged.pdf
const response = await fetch('https://api.pdfapi.dev/v1/pdf/merge', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.PDFAPI_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
pdfs: [
{ data: pdf1Base64 },
{ url: 'https://example.com/document.pdf' },
{ data: pdf2Base64 }
],
storage: {
enabled: true,
filename: 'merged-report.pdf'
}
}),
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error.message);
}
const buffer = await response.arrayBuffer();
// Save or process the merged PDF
import requests
import base64
import os
# Read local PDFs and encode as base64
with open('document1.pdf', 'rb') as f:
pdf1_base64 = base64.b64encode(f.read()).decode('utf-8')
with open('document2.pdf', 'rb') as f:
pdf2_base64 = base64.b64encode(f.read()).decode('utf-8')
response = requests.post(
'https://api.pdfapi.dev/v1/pdf/merge',
headers={
'Authorization': f'Bearer {os.environ["PDFAPI_KEY"]}',
'Content-Type': 'application/json',
},
json={
'pdfs': [
{'data': pdf1_base64},
{'url': 'https://example.com/document.pdf'},
{'data': pdf2_base64}
],
'storage': {
'enabled': True,
'filename': 'merged-report.pdf'
}
}
)
if response.status_code == 200:
with open('merged.pdf', 'wb') as f:
f.write(response.content)
else:
print(f"Error: {response.json()['error']['message']}")
package main
import (
"bytes"
"encoding/base64"
"encoding/json"
"io"
"net/http"
"os"
)
func main() {
// Read and encode local PDF
pdfContent, _ := os.ReadFile("document.pdf")
pdfBase64 := base64.StdEncoding.EncodeToString(pdfContent)
payload := map[string]interface{}{
"pdfs": []map[string]string{
{"data": pdfBase64},
{"url": "https://example.com/document.pdf"},
},
"storage": map[string]interface{}{
"enabled": true,
"filename": "merged-report.pdf",
},
}
body, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", "https://api.pdfapi.dev/v1/pdf/merge", bytes.NewBuffer(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("PDFAPI_KEY"))
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
pdf, _ := io.ReadAll(resp.Body)
os.WriteFile("merged.pdf", pdf, 0644)
}
Response
Success (200)
Returns the merged PDF file directly:
Content-Type: application/pdf
Content-Disposition: attachment; filename="merged.pdf"
If storage is enabled, the response also includes headers:
X-File-ID: f47ac10b-58cc-4372-a567-0e02b2c3d479
X-File-URL: https://api.pdfapi.dev/v1/files/f47ac10b-58cc-4372-a567-0e02b2c3d479
Error Responses
Invalid PDF Count (400)
{
"error": {
"code": "VALIDATION_ERROR",
"message": "PDFs array must contain between 2 and 100 items"
}
}
Invalid PDF Source (400)
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Each PDF must have either 'data' or 'url' field"
}
}
URL Fetch Failed (400)
{
"error": {
"code": "URL_FETCH_ERROR",
"message": "Failed to fetch PDF from URL: https://example.com/document.pdf"
}
}
Invalid PDF Content (400)
{
"error": {
"code": "INVALID_PDF",
"message": "Item at index 2 is not a valid PDF document"
}
}
See Error Codes for complete reference.
Use Cases
Combining Report Sections
Merge separate report sections into a single document:
curl -X POST https://api.pdfapi.dev/v1/pdf/merge \
-H "Authorization: Bearer $PDFAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"pdfs": [
{"url": "https://reports.example.com/cover-page.pdf"},
{"url": "https://reports.example.com/executive-summary.pdf"},
{"url": "https://reports.example.com/detailed-analysis.pdf"},
{"url": "https://reports.example.com/appendix.pdf"}
]
}' \
--output complete-report.pdf
Combining User-Uploaded Documents
Merge documents uploaded by users in your application:
async function mergeUserDocuments(documents) {
const pdfs = documents.map(doc => ({
data: doc.base64Content
}));
const response = await fetch('https://api.pdfapi.dev/v1/pdf/merge', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.PDFAPI_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
pdfs,
storage: { enabled: true, filename: 'user-documents.pdf' }
}),
});
return response;
}
Limits
| Aspect | Limit |
|---|---|
| Minimum PDFs | 2 |
| Maximum PDFs | 100 |
| Maximum total size | 100 MB |
| URL fetch timeout | 30 seconds |
Notes
- PDFs are merged in the order they appear in the
pdfsarray - All pages from each PDF are included in the merged document
- PDF metadata from the first document is preserved
- Password-protected PDFs are not supported
- If any PDF is invalid or cannot be fetched, the entire operation fails