How to Use DocRaptor to Generate Bulk Payslip PDFs in India
Generate one secure, print-ready payslip PDF per employee with DocRaptor. This guide covers the API workflow, a Python worker, testing, security, and India wage-slip context.
Use DocRaptor’s document API from a server-side worker and submit one document request for each employee and pay period. Render each approved payroll record into its own HTML payslip, enqueue the job, generate a PDF with DocRaptor, and store the result against a stable employee/pay-period identifier in access-controlled storage. The documentation describes the document API; it does not establish a universal bulk endpoint, concurrency limit, or throughput target, so confirm account limits and benchmark your workload before choosing batch size.
This guide shows a Python implementation and cURL and Node.js request examples. It also covers retries, privacy, print rendering, testing, and relevant Indian wage-slip rules. DocRaptor converts the supplied document; it does not calculate payroll or verify legal correctness.
1. Understand the workflow
- Read approved payroll records for a specific pay period from your payroll system.
- Render one employee-specific HTML document per record using an escaped template.
- Queue one generation task per payslip. Keep the API key on the server.
- POST the HTML to
https://api.docraptor.com/docsand receive PDF bytes, or use the documented hosted or asynchronous workflow when appropriate. - Validate the result, store it privately, and record success or failure for that employee and pay period.
- Make the payslip available only to the authorized employee through your application’s authenticated access flow.
This is an application-side design inferred from DocRaptor’s document-level API. It is not a vendor-published bulk recipe. The sources do not define a universal concurrency setting, per-minute throughput, queue design, or idempotency guarantee.
2. Prepare a print-ready payslip template
Start with a semantic HTML document and CSS designed for paper. DocRaptor uses print media by default, so styles that look right in a browser’s screen view may produce a different PDF. Keep the layout predictable: label each earning and deduction, show the period and employee identifier, and check totals using payroll calculations from your trusted payroll system.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<style>
@page { size: A4; margin: 14mm; }
body { font: 10pt Arial, sans-serif; color: #18212b; }
h1 { font-size: 18pt; margin: 0 0 12pt; }
.meta { margin-bottom: 18pt; }
table { width: 100%; border-collapse: collapse; }
th, td { border-bottom: 1px solid #ccd3da; padding: 7pt; text-align: left; }
.amount { text-align: right; }
.total { font-weight: bold; }
</style>
</head>
<body>
<h1>Payslip</h1>
<div class="meta">
<div>Employee: {{ employee_name }}</div>
<div>Employee ID: {{ employee_id }}</div>
<div>Pay period: {{ pay_period }}</div>
</div>
<table>
<thead><tr><th>Description</th><th class="amount">Amount</th></tr></thead>
<tbody>
{{ earning_rows }}
{{ deduction_rows }}
<tr class="total"><td>Net pay</td><td class="amount">{{ net_pay }}</td></tr>
</tbody>
</table>
</body>
</html>
The braces above are template placeholders, not literal values to send. Use an HTML template engine that escapes values by default; do not concatenate untrusted employee names or other record fields into markup. Format money consistently using the payroll system’s approved currency and rounding rules. Include only the employee data required for the payslip.
3. Generate one PDF per employee with Python
Install the HTTP client in the environment where the worker runs:
python -m pip install requests
Set the API key as a server-side environment secret. The following example renders a minimal document for each record and writes returned PDF bytes to a local output directory. In production, replace local file storage with your access-controlled document store, and use your application’s template and payroll calculations.
import os
from pathlib import Path
from html import escape
import requests
API_KEY = os.environ["DOCRAPTOR_API_KEY"]
API_URL = "https://api.docraptor.com/docs"
OUT_DIR = Path("private-payslips")
OUT_DIR.mkdir(mode=0o700, parents=True, exist_ok=True)
# Example input only. In production, load approved records from the payroll system.
records = [
{
"employee_id": "E-1042",
"employee_name": "Asha Rao",
"pay_period": "2026-09",
"earnings": [("Basic pay", "50000.00"), ("Allowance", "8000.00")],
"deductions": [("Tax", "5000.00")],
"net_pay": "53000.00",
}
]
def money_rows(items):
return "".join(
f"<tr><td>{escape(label)}</td>"
f"<td style='text-align:right'>{escape(amount)}</td></tr>"
for label, amount in items
)
def render_html(record):
return f"""<!doctype html>
<html lang='en'><head><meta charset='utf-8'>
<style>@page{{size:A4;margin:14mm}}body{{font:10pt Arial,sans-serif}}
table{{width:100%;border-collapse:collapse}}td,th{{padding:7pt;border-bottom:1px solid #ccd3da}}
.amount{{text-align:right}}</style></head><body>
<h1>Payslip</h1>
<p>Employee: {escape(record['employee_name'])}<br>
Employee ID: {escape(record['employee_id'])}<br>
Pay period: {escape(record['pay_period'])}</p>
<table><thead><tr><th>Description</th><th>Amount</th></tr></thead>
<tbody>{money_rows(record['earnings'])}{money_rows(record['deductions'])}
<tr><th>Net pay</th><th>{escape(record['net_pay'])}</th></tr></tbody></table>
</body></html>"""
def generate_payslip(record):
# Test mode is useful during template development. Test PDFs are watermarked.
payload = {
"type": "pdf",
"document_content": render_html(record),
"test": True,
}
response = requests.post(
API_URL,
json=payload,
auth=(API_KEY, ""), # DocRaptor documents the key as Basic Auth username.
timeout=(10, 120),
)
response.raise_for_status()
if not response.content.startswith(b"%PDF-"):
raise RuntimeError("DocRaptor response was not PDF data")
# Use a stable internal identifier; never accept an output path from a client.
safe_id = "".join(c for c in record["employee_id"] if c.isalnum() or c in "-_")
safe_period = "".join(c for c in record["pay_period"] if c.isalnum() or c in "-_")
output = OUT_DIR / f"{safe_id}-{safe_period}.pdf"
output.write_bytes(response.content)
output.chmod(0o600)
return output, response.headers.get("X-DocRaptor-Num-Pages")
for row in records:
path, pages = generate_payslip(row)
print(f"Generated {path.name}; page count={pages or 'not provided'}")
The example uses test mode so generated PDFs carry a watermark and are unsuitable for employee distribution. After validating your template and account configuration, set test to false or omit it for production, subject to the current API reference. A production worker should also enforce retry limits, retain a per-document status, and avoid printing sensitive data into logs.
4. Call the API with cURL
DocRaptor documents JSON POST requests and HTTP Basic Authentication, with the API key as the username and a blank password. Save the response body as a PDF and inspect the HTTP status and response headers:
curl --fail-with-body \
--user "$DOCRAPTOR_API_KEY:" \
-H 'Content-Type: application/json' \
-d '{"type":"pdf","document_content":"<html><body><h1>Payslip</h1></body></html>","test":true}' \
-D response-headers.txt \
https://api.docraptor.com/docs \
-o sample-payslip.pdf
For real records, generate the HTML on the server and send it in document_content. The API also accepts a document URL. A URL must be reachable by DocRaptor and must not expose a payslip through an unauthenticated public route. The reference also documents query-parameter authentication, but Basic Auth avoids placing the key in the URL where it can leak through logs or monitoring.
5. Call the API with Node.js
This Node.js example uses built-in fetch and writes the response bytes to a file. Set the API key in the server environment, never in browser JavaScript.
import { writeFile } from "node:fs/promises";
const key = process.env.DOCRAPTOR_API_KEY;
if (!key) throw new Error("DOCRAPTOR_API_KEY is required");
const html = "<!doctype html><html><body><h1>Payslip</h1></body></html>";
const auth = Buffer.from(`${key}:`).toString("base64");
const response = await fetch("https://api.docraptor.com/docs", {
method: "POST",
headers: {
"Authorization": `Basic ${auth}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ type: "pdf", document_content: html, test: true }),
signal: AbortSignal.timeout(120_000),
});
if (!response.ok) {
const detail = await response.text();
throw new Error(`DocRaptor HTTP ${response.status}: ${detail}`);
}
const bytes = Buffer.from(await response.arrayBuffer());
if (bytes.subarray(0, 5).toString() !== "%PDF-") {
throw new Error("Response did not contain a PDF");
}
await writeFile("sample-payslip.pdf", bytes, { mode: 0o600 });
Wrap this call in a server-side queue consumer for bulk work. Fetch is synchronous from the worker’s perspective; for long rendering workloads or larger batches, DocRaptor’s asynchronous workflow can return a status identifier for later retrieval. Follow the current reference for exact async parameters and result retrieval.
6. Choose synchronous, hosted, or asynchronous results
| Workflow | What it does | Considerations |
|---|---|---|
| Synchronous PDF bytes | The POST response body is the PDF. | Convenient for a worker that can wait for each document. Apply timeouts and persist each completed result promptly. |
| Hosted document | The response provides a hosted download URL. | Treat the URL as sensitive if it grants access. The API reference says hosted documents are public URLs; test hosted documents have a five-download limit and expire after one day. |
| Asynchronous request | The request returns a status identifier; retrieve the document when processing completes. | Persist the identifier and state, poll or use the documented completion flow, and handle expiration or failed jobs according to the current reference. |
Use the mode that fits your worker’s execution window and storage model. Do not assume that a hosted URL is private or that a timed-out client request means DocRaptor did not finish processing. Record enough job state to reconcile uncertain outcomes.
7. Print, JavaScript, assets, and rendering options
- Print media: print styles apply by default. The API reference documents
prince_options.mediafor choosing a different media mode where needed. Design and review the actual printed output. - JavaScript: JavaScript is disabled by default. Leave it disabled for static payslip templates; the documentation notes this is faster when JavaScript is unnecessary. Enable it only when client-side rendering is required. For asynchronous JavaScript, use the documented completion callback mechanism.
- Pipeline: Pipeline 10.1 is documented as the default for accounts on the newest pipeline, with earlier pipeline options also listed. Confirm the live default for your account. Pin a pipeline if stable rendering across deployments matters, then review output before changing it.
- Resources: external CSS and image errors are ignored by default, and resources may be fetched for up to ten seconds. A request can succeed while a logo, font, or stylesheet is missing. Use stable assets, consider embedding required resources, and configure strict resource-error handling when appropriate.
- Output type: the reference lists PDF, XLS, and XLSX output types. This workflow uses PDF, with HTML input.
For batch consistency, keep the template version, CSS, fonts, and relevant pipeline configuration consistent for all employees in a pay run. Store a template version or deployment identifier with each job if you need to explain later how a particular PDF was produced.
8. Build a reliable bulk queue
- Freeze the input set. Use approved payroll records for one pay period and record a stable internal job ID for each employee-period pair.
- Validate before submission. Check required fields, numeric amounts, currency formatting, and expected totals before rendering. Reject or quarantine incomplete records rather than generating ambiguous slips.
- Enqueue one document task per person. Keep the queue payload minimal; where possible, reference a protected payroll record rather than copying salary data into a general-purpose queue.
- Limit concurrency deliberately. Start conservatively, measure completion times and errors for your account, and confirm service limits with DocRaptor. The cited docs establish no universal safe concurrency value.
- Persist results independently. Save each PDF and its status before acknowledging the queue message. A failure for one person should not discard completed documents for others.
- Retry carefully. Retry transient network and service failures with bounded exponential backoff and jitter. Do not blindly retry malformed requests or invalid credentials. Reconcile timeouts before resubmitting if an earlier request may have completed.
- Prevent mismatches and duplicates. Use a stable unique key such as employee ID plus pay period plus payroll-run version. Verify the record-to-file association before making the payslip available.
- Monitor without exposing payroll data. Log job IDs, status codes, page counts, and timing where useful, but do not log API keys, full HTML, bank information, or salary breakdowns.
DocRaptor’s cited materials do not state an idempotency guarantee. Treat retries as potentially creating another document request, and make your own job processing and storage idempotent.
9. Security and employee access
- Keep the API key in a secret manager or protected server environment. DocRaptor warns that its JavaScript library exposes the key in page source and recommends a referrer-based API or server-side agent.
- Do not put the API key into browser code, client-visible HTML, source control, or a public URL.
- Authorize the employee in your application before allowing access to a payslip. A client-supplied employee ID is not proof of authorization.
- Store PDF files in private storage and serve them through authenticated, short-lived access mechanisms appropriate to your application. If using DocRaptor-hosted documents, account for the documented public URL behavior.
- Limit access to payroll records and generated documents to the systems and staff that need it. Avoid logging document contents and remove temporary files under your organization’s retention policy.
These access-control practices are prudent system design recommendations; the cited DocRaptor documentation does not prescribe an Indian payroll access-control design.
10. Test before the first real pay run
DocRaptor test mode does not count test documents against monthly limits, according to its API reference. Test PDFs are watermarked. Hosted test documents have a five-download limit and expire after one day, so test mode output is not suitable for employee distribution.
- Use records with long names, punctuation, and multilingual characters your workforce requires.
- Check zero values, large values, negative adjustments if your payroll model permits them, and rounding at the boundaries your payroll rules define.
- Test a payslip with many earnings and deductions, plus any case that could span pages.
- Verify page breaks, margins, totals, currency labels, and whether repeated table headings behave as expected.
- Test missing or slow external fonts, CSS, and images. Confirm the output itself; HTTP success alone does not prove all assets loaded.
- Confirm that a failure for one record does not stop the rest of the batch and that retries cannot attach a PDF to the wrong employee.
- After test-mode review, generate a controlled production-mode sample and verify the actual account configuration before distributing the batch.
11. India wage-slip context
The Ministry of Labour and Employment’s Code on Wages Central Rules, Rule 52, states that employers covered by the rule issue wage slips electronically or physically in Form V on or before wage payment. Rule 51(4) states that registers required under those rules are preserved for five years after the date of the last entry. See the Ministry of Labour and Employment’s Code on Wages Central Rules.
Those cited central rules are not a complete jurisdiction-by-jurisdiction legal analysis. Confirm the applicable Code, rules, forms, commencement position, state requirements, and employee coverage with qualified counsel or the relevant authority before treating this workflow as a compliance determination. DocRaptor produces the PDF; it does not determine whether your payroll calculations or form satisfy applicable law.
12. Performance, reliability, and cost
Performance: total batch time depends on the number of employee documents, document complexity, external resources, and account behavior. Static HTML avoids unnecessary JavaScript rendering. Keep assets reliable, measure your own worker’s latency, and increase parallelism only after confirming account limits. The research does not establish a DocRaptor throughput benchmark.
Reliability: separate per-document job state, retain the returned page-count header (X-DocRaptor-Num-Pages) when useful, validate that the response is a PDF, and inspect output samples. Handle timeouts as uncertain outcomes until reconciled. Use bounded retries and preserve enough metadata to investigate a failed pay run without retaining excessive sensitive content.
Cost: the cited materials do not provide verified plan prices or a cost calculation for a specific payroll volume. Check DocRaptor’s current account pricing and limits directly, then estimate expected document volume and any retry or test needs. Test mode documents are not counted against monthly limits per the API reference, but test PDFs are watermarked.
13. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| 401 or 403 response | Missing, invalid, or incorrectly supplied key; API key placed in the wrong authentication field. | Use the account’s current API key with HTTP Basic Auth as username and blank password. Confirm the server secret is present; rotate exposed credentials. |
| 400 response or rejected document | Malformed JSON, invalid document type, missing content or URL, or invalid options. | Check the request payload against the current API reference. Reproduce with a minimal HTML document, then add fields and options incrementally. |
| Request times out | Complex rendering, slow resources, network interruption, or a client timeout shorter than processing time. | Set suitable connection and read timeouts for the worker. Consider the documented async workflow. Reconcile job state before resubmitting to avoid duplicate work. |
| PDF is missing CSS, logo, or font | External resource failed, was unreachable, or exceeded the documented resource fetch window; errors may be ignored by default. | Use stable reachable resources or embed required assets. Consider strict resource-error handling and inspect the PDF visually. |
| Layout differs from browser preview | Print media is applied by default, and screen styles may differ. | Use print-specific CSS, review page size and margins, and check the generated PDF rather than relying on a screen preview. |
| Dynamic fields are blank | JavaScript is disabled by default or asynchronous rendering was not allowed to finish. | Prefer server-rendered HTML. If JavaScript is essential, enable it using the documented option and use the completion callback for asynchronous work. |
| Unexpected page count or clipping | Long text, large tables, fixed heights, or unsuitable page-break rules. | Test realistic edge records, remove restrictive fixed heights, and tune print CSS and page-break behavior. |
| Output is watermarked | The request used test mode. | Use test mode only for validation. Generate production documents without the test flag after confirming the template and account settings. |
| Hosted test link no longer works | Hosted test documents expire after one day and are limited to five downloads. | Generate another test document or store test bytes in your own controlled test environment. |
| Employee receives another person’s PDF | Incorrect job-to-file association, unsafe client-supplied identifier, or race condition in storage naming. | Use stable employee-period-run identifiers, authorize access server-side, and verify ownership before publishing each document. |
14. Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. It captures a page from one GET request and returns an image or PDF; it is useful when a workflow needs a visual capture of a rendered page, but it does not replace payroll calculation, payslip templating, or DocRaptor’s HTML-to-PDF document workflow. See the ScreenshotNeo API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Before capture, ScreenshotNeo accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits cost nothing, and response headers identify the page verdict and billing. Its MCP server gives AI agents tools to take screenshots, get page information, and capture PDFs. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000, and every feature is on every plan.
Sign up free for 1,000 screenshots a month with no card.
15. FAQ
Can I send one request containing every employee’s payslip?
The cited API documentation describes document-level requests and does not establish a universal multi-payslip bulk endpoint. Design your application to create one employee-specific document task per payslip unless your verified account integration documents another supported pattern.
Does DocRaptor calculate salary, tax, or statutory deductions?
No such payroll calculation capability is established by the cited materials. Calculate and approve payroll in your payroll system, then render the resulting figures.
Can I use a hosted URL for private employee delivery?
The API reference describes hosted documents as public URLs. Do not assume they are private; evaluate the access implications and use a storage and delivery design that meets your organization’s privacy requirements.
Can a successful API response still produce an incorrect payslip?
Yes. A successful PDF response confirms document generation, not correctness of payroll inputs, legal compliance, or completeness of external assets. Validate calculations upstream and review representative PDFs.


