§ ONLINE API PDF MERGE · REST · ANY LANGUAGE

The PDF merge REST API — combine uploads and URLs into one PDF.

One endpoint. Any number of files. SelectPdf merges local PDFs and remote PDF URLs in the order you list them, with optional per-file passwords, viewer prefs and output metadata — REST-callable from any language.


§CLIENT LIBRARIES

PDF merge API in eight languages.

Open-source client libraries on GitHub for seven runtimes plus a Go example using the standard library. Same API surface across runtimes — learn once, deploy anywhere.

PdfMerge.cs
using System;
using SelectPdf.Api;

PdfMergeClient client = new PdfMergeClient(apiKey);

// Add files in the order they appear in the merged PDF
client.addUrlFile(testUrl);                  // remote URL
client.addFile(testPdf);                     // local upload
// client.addFile(testPdf, "src_password"); // with password

// Optional: protect + label the merged output
client.setUserPassword("secret");
client.setDocTitle("Combined statement");

// --- Merge to a local file ---
client.saveToFile(localFile);
Console.WriteLine("Pages: " + client.getNumberOfPages());
Console.WriteLine("Credits left: " + client.CreditsRemaining);
.NET (C#) CLIENT
Three lines, one merged PDF.

Bypass the raw multipart wiring. The official client exposes named addFile / addUrlFile / saveToFile methods, password overloads, and language-idiomatic error handling.

PdfMerge.java
package com.selectpdf;

PdfMergeClient client = new PdfMergeClient(apiKey);

// Add files in the order they appear in the merged PDF
client.addUrlFile(testUrl);                  // remote URL
client.addFile(testPdf);                     // local upload
// client.addFile(testPdf, "src_password"); // with password

// Optional: protect + label the merged output
client.setUserPassword("secret");
client.setDocTitle("Combined statement");

// --- Merge to a local file ---
client.saveToFile(localFile);
System.out.printf("Pages: %d%n", client.getNumberOfPages());

UsageClient u = new UsageClient(apiKey);
System.out.println("Usage: " + u.getUsage(false));
JAVA CLIENT
Three lines, one merged PDF.

Bypass the raw multipart wiring. The official client exposes named addFile / addUrlFile / saveToFile methods, password overloads, and language-idiomatic error handling.

pdf-merge.php
require("SelectPdf.Api.php");

$client = new SelectPdf\Api\PdfMergeClient($apiKey);

// Add files in the order they appear in the merged PDF
$client->addUrlFile($testUrl);                 // remote URL
$client->addFile($testPdf);                    // local upload
// $client->addFile($testPdf, "src_password"); // with password

// Optional: protect + label the merged output
$client->setUserPassword("secret");
$client->setDocTitle("Combined statement");

// --- Merge to a local file ---
$client->saveToFile($localFile);
echo "Pages: " . $client->getNumberOfPages() . "\n";

$u = new \SelectPdf\Api\UsageClient($apiKey);
$usage = $u->getUsage(false);
echo "Credits: " . $usage["available"] . "\n";
PHP CLIENT
Three lines, one merged PDF.

Bypass the raw multipart wiring. The official client exposes named addFile / addUrlFile / saveToFile methods, password overloads, and language-idiomatic error handling.

pdf_merge.py
import selectpdf

client = selectpdf.PdfMergeClient(apiKey)

# Add files in the order they appear in the merged PDF
client.addUrlFile(testUrl)                 # remote URL
client.addFile(testPdf)                    # local upload
# client.addFileWithPassword(testPdf, "src_password")  # with password

# Optional: protect + label the merged output
client.setUserPassword("secret")
client.setDocTitle("Combined statement")

# --- Merge to a local file ---
client.saveToFile(localFile)
print("Pages:", client.getNumberOfPages())

usage = selectpdf.UsageClient(apiKey).getUsage()
print("Credits:", usage["available"])
PYTHON CLIENT
Three lines, one merged PDF.

Bypass the raw multipart wiring. The official client exposes named addFile / addUrlFile / saveToFile methods, password overloads, and language-idiomatic error handling.

pdf-merge.js
var selectpdf = require('selectpdf');

var client = new selectpdf.PdfMergeClient(apiKey);

// Add files in the order they appear in the merged PDF
client.addUrlFile(testUrl);                  // remote URL
client.addFile(testPdf);                     // local upload
// client.addFile(testPdf, 'src_password');  // with password

// Optional: protect + label the merged output
client.setUserPassword('secret');
client.setDocTitle('Combined statement');

// --- Merge to a local file ---
client.saveToFile(localFile, function(err, file) {
    if (err) return console.error('Merge error:', err);
    console.log('Pages:', client.getNumberOfPages());
});
NODE.JS CLIENT
Three lines, one merged PDF.

Bypass the raw multipart wiring. The official client exposes named addFile / addUrlFile / saveToFile methods, password overloads, and language-idiomatic error handling.

pdf_merge.rb
require 'selectpdf'

client = SelectPdf::PdfMergeClient.new(api_key)

# Add files in the order they appear in the merged PDF
client.add_url_file(test_url)              # remote URL
client.add_file(test_pdf)                  # local upload
# client.add_file(test_pdf, 'src_password')  # with password

# Optional: protect + label the merged output
client.user_password = 'secret'
client.doc_title = 'Combined statement'

# --- Merge to a local file ---
client.save_to_file(local_file)
print "Pages: #{client.number_of_pages}\n"

usage = SelectPdf::UsageClient.new(api_key).get_usage(false)
print "Credits: #{usage['available']}\n"
RUBY CLIENT
Three lines, one merged PDF.

Bypass the raw multipart wiring. The official client exposes named addFile / addUrlFile / saveToFile methods, password overloads, and language-idiomatic error handling.

PdfMerge.pl
use SelectPdf;
use JSON;

my $client = SelectPdf::PdfMergeClient->new($apiKey);

# Add files in the order they appear in the merged PDF
$client->addUrlFile($test_url);              # remote URL
$client->addFile($test_pdf);                 # local upload
# $client->addFileWithPassword($test_pdf, "src_password");

# Optional: protect + label the merged output
$client->setUserPassword("secret");
$client->setDocTitle("Combined statement");

# --- Merge to a local file ---
$client->saveToFile($local_file);
print "Pages: " . $client->getNumberOfPages() . "\n";

my $u = SelectPdf::UsageClient->new($apiKey);
print "Credits: " . $u->getUsage(0)->{"available"} . "\n";
PERL CLIENT
Three lines, one merged PDF.

Bypass the raw multipart wiring. The official client exposes named addFile / addUrlFile / saveToFile methods, password overloads, and language-idiomatic error handling.

pdfmerge.go
// No dedicated Go SDK — POST /api2/pdfmerge/ over net/http.
package main

import (
    "bytes"
    "io"
    "mime/multipart"
    "net/http"
    "os"
)

const apiURL = "https://selectpdf.com/api2/pdfmerge/"

func main() {
    b := &bytes.Buffer{}
    w := multipart.NewWriter(b)
    w.WriteField("key", apiKey)
    w.WriteField("files_no", "2")
    w.WriteField("url_1", testUrl)       // file 1: remote URL
    // file 2: upload as multipart part named "file_2"
    f, _ := os.Open(testPdf)
    defer f.Close()
    part, _ := w.CreateFormFile("file_2", testPdf)
    io.Copy(part, f)
    w.Close()

    req, _ := http.NewRequest("POST", apiURL, b)
    req.Header.Set("Content-Type", w.FormDataContentType())
    resp, _ := http.DefaultClient.Do(req)
    defer resp.Body.Close()

    out, _ := os.Create(localFile)
    defer out.Close()
    io.Copy(out, resp.Body)
}
GO CLIENT
Three lines, one merged PDF.

No dedicated client library for this runtime — the snippet uses the standard library to POST a multipart/form-data request directly to the REST endpoint.

CLIENTnet/http — no SDK
ENDPOINTPOST /api2/pdfmerge/
§WHAT IT DOES

Combine PDFs. From anywhere.

MIXED INPUTS

Local uploads + remote URLs

Each input slot is independent — pass url_N for a remote PDF or upload file_N as a multipart part. Mix the two within a single request.

ORDERED

Pages in the order you list them

Index 1 first, then 2, 3, … up to files_no. No re-sorting, no surprises — the merged PDF mirrors the order you specified.

PROTECTED SOURCES

Open password-protected PDFs

Pass password_N for any source that requires a password to open. The API decrypts before merging.

PROTECTED OUTPUT

Password-protect the merged PDF

Set user_password (view) and owner_password (modify) on the merged output — independent of any source passwords.

DOC METADATA

Title, author, viewer prefs

Set doc_title / doc_subject / doc_keywords / doc_author + viewer page-layout and page-mode hints on the merged output.

SYNC + ASYNC

202 + poll for the long ones

Sync for fast merges (up to timeout=120 s). For large jobs, set async=True: get a job ID, poll GET /api2/asyncjob/ until the merged PDF is ready.

§HOW IT WORKS

One endpoint, two required things.

POST to /api2/pdfmerge/ as multipart/form-data. Pass your license key, the number of files, and one input per slot — either url_N for a remote PDF or a multipart file part named file_N. The response body is the merged PDF.

POST — multipart/form-data
POST https://selectpdf.com/api2/pdfmerge/
Content-Type: multipart/form-data
POST /api2/pdfmerge/ HTTP/1.1
Host: selectpdf.com
Content-Type: multipart/form-data; boundary=----X

------X
Content-Disposition: form-data; name="key"

YOUR_LICENSE_KEY
------X
Content-Disposition: form-data; name="files_no"

2
------X
Content-Disposition: form-data; name="url_1"

https://selectpdf.com/demo/files/selectpdf.pdf
------X
Content-Disposition: form-data; name="url_2"

https://example.com/another.pdf
------X--
key REQUIRED

Your API license key. Get one in 30 seconds — free for 7 days.

files_no REQUIRED

How many files to merge. Pair with url_N and/or file_N parts for each slot 1…N.

url_N · file_N URL · OR · FILE

For each slot N from 1 to files_no, either a remote URL or a multipart file upload.

Reminders. Files are merged in numeric order (1 first, then 2, …). Add password_N for any source PDF that requires a password to open. See the full reference in the 25-row section below.
§ENDPOINTS

Three PDF merge API endpoints. One key.

All endpoints under https://selectpdf.com/api2/. The same license key authenticates every call.

POST /api2/pdfmerge/ Merge PDF files into a single output. The main endpoint — synchronous unless async=True. POST only (multipart/form-data); GET returns 400 from the controller. More details →
GETPOST /api2/asyncjob/ Poll an async PDF-merge job. Returns the merged PDF once ready, or HTTP 202 while still running. More details →
GETPOST /api2/usage/ Read your subscription: current plan, monthly limit, used and remaining credits. More details →
§PARAMETERS

Every parameter, in one place.

The full PDF-merge parameter surface (25 rows, 22 swagger fields — `url_N` / `file_N` / `password_N` are listed individually for clarity but live in the swagger as a nested `input_files` array). Use the side navigation to jump between groups, or the search box to find a parameter by name.

§ MANDATORY 2 PARAMETERS

Mandatory parameters

Only two parameters are required — your license key and the count of files to merge.

PARAMETER
DESCRIPTION
key
REQUIRED string
Your API license key.
files_no
REQUIRED int
Number of PDF files that will be merged. Pair with the input-file convention below.
§ INPUT FILES 3 PARAMETERS

Per-file naming convention

Specify each input PDF (1 through files_no) either as a remote URL or as a multipart file upload. An optional per-file password unlocks protected sources before merging.

PARAMETER
DESCRIPTION
url_N
string
Remote URL of file N (URL-encoded). One per remote file; replace N with 1, 2, …, up to files_no.
(file upload "file_N")
multipart file
Local upload for file N. Submit the file as a multipart file part with name="file_N" (e.g. file_1, file_2). Use this OR url_N for each slot, not both.
password_N
string
Optional password for file N if the source PDF is password-protected. Applies to both url_N and uploaded file_N slots.
§ ADVANCED 3 PARAMETERS

Async mode, timeout & JSON parameter blob

Submit asynchronously for large merges, control the sync timeout, or pass every parameter as a single JSON object.

PARAMETER
DESCRIPTION
async
bool default: False
Submit the merge asynchronously. The endpoint returns HTTP 202 with the job ID in the X-SelectPdf-Job-Id header; poll /api2/asyncjob/ to retrieve the merged PDF.
True False
timeout
number (seconds) default: 30
Maximum amount of time the synchronous job can run. Up to 120 seconds.
raw_parameters
string (JSON)
Alternative to multiple form-data fields — pass a JSON object containing all parameter values as a single form-data field. The controller deserializes it into PdfMergeParameters and then uses the same processing path.
§ DOCUMENT METADATA 5 PARAMETERS

PDF document information

Set the document title, author, subject, keywords and creation-date stamp on the merged PDF.

PARAMETER
DESCRIPTION
doc_title
string
PDF document title.
doc_subject
string
Subject of the PDF document.
doc_keywords
string
PDF document keywords.
doc_author
string
Name of the PDF document author.
doc_add_creation_date
bool default: False
Save the creation date and time in the PDF document information.
True False
§ VIEWER PREFS 8 PARAMETERS

How the merged PDF opens in a viewer

Control the page layout, page mode and window behavior when the merged PDF is opened in a PDF viewer.

PARAMETER
DESCRIPTION
viewer_page_layout
enum default: 1
Page layout used when the document is opened. 0 — Single Page · 1 — One Column · 2 — Two Column Left · 3 — Two Column Right.
0 1 2 3
viewer_page_mode
enum default: 0
Document page mode. 0 — None · 1 — Outlines · 2 — Thumbs · 3 — Full Screen · 4 — OC · 5 — Attachments.
0 1 2 3 4 5
viewer_center_window
bool default: False
Position the document window in the center of the screen.
True False
viewer_display_doc_title
bool default: False
Display the document title in the viewer's title bar.
True False
viewer_fit_window
bool default: False
Resize the document window to fit the size of the first page.
True False
viewer_hide_menu_bar
bool default: False
Hide the PDF viewer application's menu bar.
True False
viewer_hide_toolbar
bool default: False
Hide the PDF viewer application's toolbar.
True False
viewer_hide_window_ui
bool default: False
Hide UI elements (scroll bars, navigation), leaving only the document content.
True False
§ SECURITY & OUTPUT 4 PARAMETERS

Output password, filename, content-type

Password-protect the merged output, set the download filename, and pick the response Content-Type.

PARAMETER
DESCRIPTION
user_password
string
Password required to view the merged PDF document. Applies to the merged output only — see password_N for per-file source passwords.
owner_password
string
Password required to view or modify the merged PDF document.
pdf_name
string default: Document.pdf
Filename used in the response Content-Disposition header. The `.pdf` extension is appended automatically if missing.
response_content_type
enum default: 0
Response Content-Type. 0 — binary/octet-stream · 1 — application/pdf.
0 1
§ASYNCHRONOUS CONVERSION

For merges that outlast your HTTP connection.

Recommended for many large source PDFs or callers that cannot keep an HTTP connection open for the full merge. Submit once, poll the result when it is ready.

  1. POST /api2/pdfmerge/ with async=True (and the rest of your parameters + files).
  2. The server replies 202 Accepted and returns the job ID in the X-SelectPdf-Job-Id response header.
  3. Poll GET /api2/asyncjob/?key=YOUR_KEY&job_id=… at a reasonable cadence.
  4. Each poll: 202 = still processing · 200 = merged PDF returned in the response body · 499 = merge failed (plain-text reason in the body).
GET https://selectpdf.com/api2/asyncjob/?key=YOUR_KEY&job_id=JOB_ID

The async parameter belongs to /api2/pdfmerge/ (see Advanced); job_id is a parameter of /api2/asyncjob/, not of this endpoint — the server returns the value to you in the X-SelectPdf-Job-Id response header.

§RESPONSE

HTTP status, plain English.

Standard HTTP semantics. The body of every non-200 contains a plain-text explanation — no error shapes to parse, no enum to memorize.

200
OK
The API call succeeded. The body is the merged PDF document with Content-Type: binary/octet-stream (or application/pdf if response_content_type=1).
202
Accepted — asynchronous job
The merge was accepted asynchronously. The job ID is returned in the X-SelectPdf-Job-Id header; poll /api2/asyncjob/ until the merged PDF is ready.
400
Bad Request
Uploaded PDF files or URLs do not match files_no or the naming convention; or an empty url_N was supplied. The response body explains in plain text.
401
Authorization Required
License key not specified or invalid. The response body contains an explanation in plain text.
415
Unsupported Media Type
The PDF Merge API requires data to be posted as multipart/form-data.
429
Too Many Requests
Concurrency limit on your plan exceeded. Requests are either queued or rejected with 429. The Retry-After header indicates how long to back off before retrying.
499
Custom — Conversion Error
Something went wrong during the merge (file unreadable, password incorrect, timeout, no worker available, etc.). The body contains an explanation in plain text.
RESPONSE HEADERS
X-SelectPdf-ApiAPI version (currently v2).
X-SelectPdf-PagesNumber of pages in the merged PDF document.
X-SelectPdf-Job-IdUUID of the merge job (also returned with HTTP 202 for async).
X-SelectPdf-ModeEndpoint mode — always production for PDF merge (no public demo endpoint).
X-SelectPdf-ExecutionServer execution path — always worker for PDF merge (no in-process fallback).
X-SelectPdf-Credits-TotalMonthly conversion credit limit on the calling key. -1 means unlimited.
X-SelectPdf-Credits-RemainingCredits remaining for the current month.
Retry-AfterReturned with 429: suggested back-off in seconds.
§USAGE TRACKING

Read your subscription. Programmatically.

Two ways to know where your quota stands. Every successful merge already returns X-SelectPdf-Credits-Total and X-SelectPdf-Credits-Remaining response headers — read those for a zero-extra-cost live view of remaining credits. Use the dedicated /api2/usage/ endpoint below when you also need the subscription tier or a month-by-month history.

GET https://selectpdf.com/api2/usage/?key=YOUR_KEY&get_history=True
POST https://selectpdf.com/api2/usage/
application/json
{
  "key": "YOUR_LICENSE_KEY",
  "get_history": "True"
}
response.json
{
  "status": "License key active.",
  "subscription_type": "Entry Level",
  "limit": 2000,
  "used": 340,
  "available": 1660,
  "history": [
    { "year": 2026, "month": 4,
      "conversions": 340, "credits": 340 },
    { "year": 2026, "month": 3,
      "conversions": 1876, "credits": 1923 }
  ]
}
§LIMITS

Concurrency scales with your plan.

Each plan allows a fixed number of simultaneous requests. Excess requests are queued or rejected with a 429 Too Many Requests. One conversion credit covers up to 50 pages of merged output — a 1-page and a 49-page merge cost the same. The API accepts PDF files up to 100 MB per source file.

Free Trial
200 /mo
1req
Entry
2,000 /mo
2req
Standard
5,000 /mo
4req
Advanced
20,000 /mo
8req
Premium
50,000 /mo
8req
Ultra
100,000 /mo
16req
Dedicated
Unlimited /mo
16req
CREDIT MATH
50 pages = 1 credit · 100 MB per source file

Each 50 pages of merged output counts as one conversion credit. A 12-page, a 1-page and a 49-page merged PDF all cost the same. The API accepts source PDFs up to 100 MB each. See API pricing for plan details.

?FAQ

PDF merge API, answered.

Six quick answers about the PDF-merge REST API. For the full surface, see the 25-row reference above.

Yes. Each file slot is independent: pass url_N for a remote PDF or upload a multipart file part named file_N. You can mix the two within a single merge request.
Yes. Pass password_N for any file slot whose PDF requires a password to open. The API will use that password to decrypt before merging.
Yes. Set user_password (required to open the PDF) and/or owner_password (required to modify or remove restrictions). Both are passed once for the merged output, independent of any per-file source passwords.
The order you listed the files — url_1 or file_1 first, then url_2 or file_2, and so on up to files_no.
Yes. Submit the request with async=True. The API returns 202 Accepted with a job ID in the X-SelectPdf-Job-Id header; poll GET /api2/asyncjob/?key=…&job_id=… until the merged PDF is returned. The maximum synchronous timeout parameter is 120 seconds.
Each 50 pages of merged output counts as one conversion credit. A 49-page output costs one credit, a 51-page output costs two. The API accepts source PDFs up to 100 MB per file. Monthly plans run from $19 to $449.