Docs › Files, documents and media
PDF tools API
Merge, split, rotate and compress PDFs, read their text and draw their pages.
Upload a PDF and get a new one back: merged with others, cut down to some pages, rotated, or made smaller. Or read its details and text, or draw a page as a picture. Password-protected PDFs are refused. Files are processed and deleted; nothing is kept or logged.
Pages, size and details of a PDF
POST/v1/pdf/info
Page count, PDF version, title, author, dates, page sizes (named when A4, Letter and so on), and whether it has forms, signatures or attachments.
Send: A PDF, up to 10 MB. Post the file as the request body, or as multipart/form-data. Try it with this sample.
What you send here is never written to the log, and the answer is not cached.
curl
# a sample to try: https://api.dharun.dev/samples/document.pdf
curl -F "[email protected]" "https://api.dharun.dev/v1/pdf/info"JavaScript
// input is an <input type="file"> element
const form = new FormData();
form.append("file", input.files[0]);
const response = await fetch("https://api.dharun.dev/v1/pdf/info", { method: "POST", body: form });
const body = await response.json();
if (!response.ok) throw new Error(body.error.message);
console.log(body.data);Python
import requests
files = [("file", open("document.pdf", "rb"))]
response = requests.post("https://api.dharun.dev/v1/pdf/info", files=files, timeout=90)
body = response.json()
if not response.ok:
raise RuntimeError(body["error"]["message"])
print(body["data"])Response
{
"data": {
"pages": 2,
"version": "1.7",
"title": "India API sample document",
"author": "India API",
"subject": "",
"creator": "Typst 0.15.1",
"producer": "",
"created": "D:20261015000000+00'00'",
"modified": "D:20261015000000+00'00'",
"keywords": [],
"page_sizes": [
{
"width": 595.28,
"height": 841.89,
"name": "A4"
}
],
"encrypted": false,
"form": false,
"signatures": false,
"tagged": true,
"linearized": false,
"bookmarks": true,
"attachments": 0,
"bytes": 35632
},
"meta": {
"note": "Page sizes are in points (1/72 inch), each different size listed once."
}
}Text of a PDF, page by page
POST/v1/pdf/text
The text of each page, in reading order, or laid out as on the page with layout=true. needs_ocr is true when the pages hold almost no text, as in a scan: send those to /v1/ocr. Options go in the query string, or as form fields when the file is sent as multipart/form-data.
Send: A PDF, up to 10 MB. Post the file as the request body, or as multipart/form-data. Try it with this sample.
What you send here is never written to the log, and the answer is not cached.
| Parameter | Description |
|---|---|
firstquery | First page. Default 1. |
lastquery | Last page; at most 500 pages per request. |
layoutquery | Keep the page's layout with spaces, for tables. One of: true, false. |
curl
# a sample to try: https://api.dharun.dev/samples/document.pdf
curl -F "[email protected]" "https://api.dharun.dev/v1/pdf/text"JavaScript
// input is an <input type="file"> element
const form = new FormData();
form.append("file", input.files[0]);
const response = await fetch("https://api.dharun.dev/v1/pdf/text", { method: "POST", body: form });
const body = await response.json();
if (!response.ok) throw new Error(body.error.message);
console.log(body.data);Python
import requests
files = [("file", open("document.pdf", "rb"))]
response = requests.post("https://api.dharun.dev/v1/pdf/text", files=files, timeout=90)
body = response.json()
if not response.ok:
raise RuntimeError(body["error"]["message"])
print(body["data"])Response, with lists and long text shortened
{
"data": {
"pages": [
{
"page": 1,
"text": "India API sample document\n\nThis two-page PDF is a sample for the PDF tools of India API. Send it to the endpoints to\nread its details and text, take its pages a…"
},
{
"page": 2,
"text": "Page two\n\nவணக்கம். இது இந்தியா API-இன் மாதிரி ஆவணம்.\nनमस्ते। यह इंडिया API का नमूना दस्तावेज़ है।\nThank you for trying it."
}
],
"characters": 460,
"needs_ocr": false
},
"meta": {
"total": 2
}
}Merge PDFs into one
POST/v1/pdf/merge
Send two to twenty PDFs as form fields, in order; up to 25 MB together. Returns one PDF.
Send: Two to twenty PDFs as multipart/form-data, up to 25 MB together. Post the file as the request body, or as multipart/form-data with one field per file. Try it with this sample.
The answer returns the PDF itself; errors are JSON as everywhere else.
What you send here is never written to the log, and the answer is not cached.
curl
# a sample to try: https://api.dharun.dev/samples/document.pdf
curl -F "[email protected]" -F "[email protected]" -o out.pdf "https://api.dharun.dev/v1/pdf/merge"JavaScript
// input is an <input type="file"> element
const form = new FormData();
form.append("file", input.files[0]);
form.append("file", input.files[1]);
const response = await fetch("https://api.dharun.dev/v1/pdf/merge", { method: "POST", body: form });
if (!response.ok) throw new Error((await response.json()).error.message);
const file = await response.blob();Python
import requests
files = [("file", open("document-1.pdf", "rb")), ("file", open("document-2.pdf", "rb"))]
response = requests.post("https://api.dharun.dev/v1/pdf/merge", files=files, timeout=90)
if not response.ok:
raise RuntimeError(response.json()["error"]["message"])
open("out.pdf", "wb").write(response.content)Pick, reorder or split pages
POST/v1/pdf/pages
Returns a PDF of the pages named, in the order named; a page may be named twice. To split a PDF, ask for each part in turn. Options go in the query string, or as form fields when the file is sent as multipart/form-data.
Send: A PDF, up to 10 MB. Post the file as the request body, or as multipart/form-data. Try it with this sample.
The answer returns the PDF itself; errors are JSON as everywhere else.
What you send here is never written to the log, and the answer is not cached.
| Parameter | Description |
|---|---|
pagesquery, required | Pages: numbers and ranges such as 1-3,5,8- (8 to the end), odd, even or l (the last page). |
curl
# a sample to try: https://api.dharun.dev/samples/document.pdf
curl -F "[email protected]" -o out.pdf "https://api.dharun.dev/v1/pdf/pages?pages=2,1"JavaScript
// input is an <input type="file"> element
const form = new FormData();
form.append("file", input.files[0]);
const response = await fetch("https://api.dharun.dev/v1/pdf/pages?pages=2,1", { method: "POST", body: form });
if (!response.ok) throw new Error((await response.json()).error.message);
const file = await response.blob();Python
import requests
files = [("file", open("document.pdf", "rb"))]
response = requests.post("https://api.dharun.dev/v1/pdf/pages?pages=2,1", files=files, timeout=90)
if not response.ok:
raise RuntimeError(response.json()["error"]["message"])
open("out.pdf", "wb").write(response.content)Rotate pages
POST/v1/pdf/rotate
Turns pages clockwise by a multiple of 90 degrees. Options go in the query string, or as form fields when the file is sent as multipart/form-data.
Send: A PDF, up to 10 MB. Post the file as the request body, or as multipart/form-data. Try it with this sample.
The answer returns the PDF itself; errors are JSON as everywhere else.
What you send here is never written to the log, and the answer is not cached.
| Parameter | Description |
|---|---|
anglequery | Degrees, clockwise. Default 90. One of: 90, 180, 270, -90, -180, -270. |
pagesquery | Pages: numbers and ranges such as 1-3,5,8- (8 to the end), odd, even or l (the last page). |
curl
# a sample to try: https://api.dharun.dev/samples/document.pdf
curl -F "[email protected]" -o out.pdf "https://api.dharun.dev/v1/pdf/rotate?angle=90&pages=1"JavaScript
// input is an <input type="file"> element
const form = new FormData();
form.append("file", input.files[0]);
const response = await fetch("https://api.dharun.dev/v1/pdf/rotate?angle=90&pages=1", { method: "POST", body: form });
if (!response.ok) throw new Error((await response.json()).error.message);
const file = await response.blob();Python
import requests
files = [("file", open("document.pdf", "rb"))]
response = requests.post("https://api.dharun.dev/v1/pdf/rotate?angle=90&pages=1", files=files, timeout=90)
if not response.ok:
raise RuntimeError(response.json()["error"]["message"])
open("out.pdf", "wb").write(response.content)Make a PDF smaller
POST/v1/pdf/compress
Removes duplicate fonts and images and packs the file's structure. Pictures are not re-compressed, so a scanned PDF shrinks little. The original size is in the X-Original-Bytes header; when nothing was gained, the original comes back.
Send: A PDF, up to 10 MB. Post the file as the request body, or as multipart/form-data. Try it with this sample.
The answer returns the PDF itself; errors are JSON as everywhere else.
What you send here is never written to the log, and the answer is not cached.
curl
# a sample to try: https://api.dharun.dev/samples/document.pdf
curl -F "[email protected]" -o out.pdf "https://api.dharun.dev/v1/pdf/compress"JavaScript
// input is an <input type="file"> element
const form = new FormData();
form.append("file", input.files[0]);
const response = await fetch("https://api.dharun.dev/v1/pdf/compress", { method: "POST", body: form });
if (!response.ok) throw new Error((await response.json()).error.message);
const file = await response.blob();Python
import requests
files = [("file", open("document.pdf", "rb"))]
response = requests.post("https://api.dharun.dev/v1/pdf/compress", files=files, timeout=90)
if not response.ok:
raise RuntimeError(response.json()["error"]["message"])
open("out.pdf", "wb").write(response.content)Draw a page as a picture
POST/v1/pdf/render
Returns one page as PNG or JPEG, for previews and thumbnails. Options go in the query string, or as form fields when the file is sent as multipart/form-data.
Send: A PDF, up to 10 MB. Post the file as the request body, or as multipart/form-data. Try it with this sample.
The answer returns the image itself; errors are JSON as everywhere else.
What you send here is never written to the log, and the answer is not cached.
| Parameter | Description |
|---|---|
pagequery | Page number. Default 1. |
widthquery | Width in pixels, 50 to 3000. Default 1000. |
formatquery | Default png. One of: png, jpeg. |
curl
# a sample to try: https://api.dharun.dev/samples/document.pdf
curl -F "[email protected]" -o out.png "https://api.dharun.dev/v1/pdf/render?page=1&width=600"JavaScript
// input is an <input type="file"> element
const form = new FormData();
form.append("file", input.files[0]);
const response = await fetch("https://api.dharun.dev/v1/pdf/render?page=1&width=600", { method: "POST", body: form });
if (!response.ok) throw new Error((await response.json()).error.message);
const file = await response.blob();Python
import requests
files = [("file", open("document.pdf", "rb"))]
response = requests.post("https://api.dharun.dev/v1/pdf/render?page=1&width=600", files=files, timeout=90)
if not response.ok:
raise RuntimeError(response.json()["error"]["message"])
open("out.png", "wb").write(response.content)Using an AI assistant? Connect the MCP server and it can call this API by itself.