A REST API and an MCP server. Render thousands of docs from your code, your AI agent, or your CRM in three lines.
All API requests require a platform API key sent in the
X-API-Key
header. API access is available on all plans, including Free. Usage is billed per document credit.
Create and manage keys in Settings, Platform API Keys.
Keys use the format
br_live_....
The full key is shown only once at creation time. Store it securely.
curl -X POST https://api.bulkrender.com/api/documents/generate \ -H "Content-Type: application/json" \ -H "X-API-Key: YOUR_API_KEY"
/api/documents/generate Generate a single document from a template. Pass the template ID and a data object with key-value pairs matching your template variables.
| Field | Type | Required | Description |
|---|---|---|---|
| templateId | string (uuid) | Yes | Template to generate from |
| data | object | Yes | Key-value pairs for template variables. For loop blocks, use arrays of objects. |
| outputFormat | string | No | "docx" (default, 1 credit) or "pdf" (2 credits) |
| name | string | No | Custom filename. Auto-generated if omitted. |
| recipientEmailField | string | No | Field name in data containing recipient email for auto-delivery. Defaults to "email". |
curl -X POST https://api.bulkrender.com/api/documents/generate \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_API_KEY" \
-d '{
"templateId": "c5f2e8a1-...",
"data": {
"name": "John Doe",
"company": "Acme Inc",
"items": [
{ "product": "Widget", "quantity": "10", "price": "$9.99" }
]
},
"outputFormat": "docx"
}' {
"status": "success",
"data": {
"id": "d4e5f6a7-...",
"name": "Invoice - John Doe",
"file_type": "docx",
"file_size": 24832,
"url": "https://download.bulkrender.com/document-templates/docs/Invoice-John-Doe.docx?X-Amz-Expires=3600&...",
"created_at": "2026-05-17T10:30:00.000Z",
"expires_at": "2026-06-16T10:30:00.000Z"
}
} url in the response is a signed download link that expires in 1 hour. The underlying file remains stored for your plan's retention period. Call GET /documents/:id/refresh-url to get a fresh URL.
/api/documents/generate-batch Generate multiple documents from the same template. Each record in the array produces one document. The result is a downloadable ZIP archive.
| Field | Type | Required | Description |
|---|---|---|---|
| templateId | string (uuid) | Yes | Template to generate from |
| records | array | Yes | Array of data objects, one per document |
| outputFormat | string | No | "docx" (default) or "pdf" |
| Plan | Max Records per Batch |
|---|---|
| Pro | 100 |
| Enterprise | 500 |
| Custom | 1,000 |
curl -X POST https://api.bulkrender.com/api/documents/generate-batch \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_API_KEY" \
-d '{
"templateId": "c5f2e8a1-...",
"records": [
{ "name": "Alice Smith", "email": "alice@example.com" },
{ "name": "Bob Jones", "email": "bob@example.com" }
],
"outputFormat": "docx"
}' {
"status": "success",
"data": {
"batchId": "b8c9d0e1-...",
"url": "https://download.bulkrender.com/document-templates/batches/batch-b8c9d0e1.zip?X-Amz-Expires=3600&...",
"count": 2,
"totalSize": 49152,
"documents": [
{ "name": "Alice Smith", "key": "...", "size": 24576 },
{ "name": "Bob Jones", "key": "...", "size": 24576 }
]
}
} 202 Accepted and a body like { "jobId": "...", "status": "processing", "progress": { "completed": 0, "total": 50, "failed": 0 } }. Poll GET /api/documents/batch-jobs/:jobId to track progress and retrieve the ZIP download URL when the job completes. Batches of 10 or fewer records return the synchronous 201 response shown above.
#N/A, #REF!, #VALUE!, and similar) are skipped before generation and never charged a credit. When any rows are skipped, the response includes a skippedRecords array ({ "index": 2, "reason": "..." } per row) and originalCount, both on the 201/202 response only, alongside the fields shown above. If every record fails validation, the request returns 422 with the same skippedRecords list and no generation or charge happens at all.
201 response is cached like any other success, so retrying with the same Idempotency-Key after fixing the bad rows returns the stale cached result, not a fresh generation. Use a new key when resubmitting corrected data. 422 responses are never cached.
Everything you need for a full workflow without opening the dashboard: list your templates to find a
templateId,
inspect its variables to build the data object, check your credit balance, generate, and refresh download links later.
| Endpoint | What it returns |
|---|---|
| GET /api/templates | All templates in your organization, newest first |
| GET /api/templates/:id | One template's details |
| GET /api/templates/:id/variables | Placeholder variables, blocks, and per-block groupings |
| GET /api/templates/:id/download | Signed URL for the template file (1 hour) |
| POST /api/templates | Upload a DOCX/XLSX template (multipart: file, name; needs an editor-or-above key) |
| PUT /api/templates/:id | Update metadata: name, description, is_active (editor+) |
| PUT /api/templates/:id/file | Replace the template file; variables re-extracted (editor+) |
| DELETE /api/templates/:id | Soft delete, idempotent (editor+) |
| POST /api/templates/:id/restore | Restore a soft-deleted template (admin/manager) |
| Endpoint | What it returns |
|---|---|
| GET /api/documents | Generated documents, cursor-paginated (limit, after) |
| GET /api/documents/:id/refresh-url | Fresh signed download URL (expiresIn 1s to 24h, default 1h) |
| GET /api/documents/batch-jobs/:jobId | Async batch progress; includes the ZIP url when completed |
curl https://api.bulkrender.com/api/billing/credits -H "X-API-Key: YOUR_API_KEY"
{ "status": "success", "data": { "plan": "pro", "subscriptionCredits": 500,
"purchasedCredits": 100, "totalCredits": 600, "purchasedCreditPacks": [...] } } POST /api/feedback
with { "type": "bug", "message": "..." } sends feedback to the team. Auth optional; limited to 5 per hour per IP.
MCP parity note: every BulkRender MCP tool maps to one of these endpoints, except search_templates (fetches the template list and filters locally) and estimate_cost (client-side math: DOCX is 1 credit per document, PDF is 2). Neither needs a server route.
GET /api/templates/public belong to the ACP walk-in checkout flow and cannot be used with POST /api/documents/generate and an organization API key. Generation with an API key requires a template from your own organization: list them with GET /api/templates or upload one with POST /api/templates.
All API responses follow a consistent JSON structure.
{ "status": "success", "data": { ... } } { "status": "error", "message": "Description of what went wrong" } Generation endpoints return credit information in response headers:
| Header | Description |
|---|---|
| X-Credits-Used | Credits consumed by this request |
| X-Credits-Remaining | Credits remaining after this request |
The API uses standard HTTP status codes. Errors always return a JSON body with
status: "error"
and a message field.
| Code | Meaning | Common Causes |
|---|---|---|
| 400 | Bad Request | Missing templateId or data, data payload too large (>1MB), batch size exceeds plan limit |
| 401 | Unauthorized | Missing X-API-Key header, invalid or expired API key |
| 402 | Payment Required | Insufficient credits (single document generation) |
| 403 | Forbidden | Permission denied (role too low), insufficient credits on batch generation |
| 429 | Too Many Requests | Rate limit exceeded (30 requests/minute) |
| 500 | Server Error | Internal error during document generation |
HTTP/1.1 402 Payment Required
{
"status": "error",
"message": "Insufficient credits. You need 2 credits for PDF. You have 0 credits."
} Generation and mutation endpoints are rate-limited to 30 requests per minute per organization. The limit applies across all API keys in your organization.
Rate limit headers are included in every response:
RateLimit-Limit,
RateLimit-Remaining,
RateLimit-Reset.
Each document generation costs credits based on format:
| Format | Cost | Notes |
|---|---|---|
| docx | 1 credit | Native Word format |
| 2 credits | Includes DOCX generation + PDF conversion |
For batch requests, total credits = number of records × credit cost per format. Example: 50 PDF documents = 100 credits.
To safely retry requests without generating duplicate documents, include an
Idempotency-Key
header with a unique value (e.g., a UUID).
If the same key is sent again within 24 hours, the API returns the original response instead of generating a new document. No additional credits are charged.
curl -X POST https://api.bulkrender.com/api/documents/generate \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
-d '{ "templateId": "c5f2e8a1-...", "data": { "name": "John Doe" } }' BulkRender ships a native, hosted MCP server so you can generate documents directly from Claude (Claude.ai, Claude Desktop, Claude Code), with more MCP-compatible assistants coming soon. No API calls, no boilerplate, no package to install: just ask.
Sign in with your BulkRender account, no token setup needed. Go to Settings, Connectors, Add custom connector and paste the BulkRender endpoint:
https://api.bulkrender.com/mcp
Claude opens a BulkRender sign-in page. Log in, approve access, done. Manage or disconnect apps any time from Settings, Integrations, Connected apps.
For tools where a sign-in flow is not practical (CLI, headless agents), generate a personal MCP URL instead: go to Settings, Integrations, open the AI Assistants section, and click Generate MCP URL. Copy it immediately, it is only shown once, and treat it like a password. In config files, use it via mcp-remote:
{
"mcpServers": {
"bulkrender": {
"command": "npx",
"args": ["mcp-remote", "YOUR_MCP_URL"]
}
}
} claude mcp add --transport http bulkrender YOUR_MCP_URL --scope user
Verify: claude mcp list should show bulkrender ✓ Connected
BulkRender speaks standard MCP, but we have only fully tested Claude clients so far. Verified setup guides for Cursor, Windsurf and Cline are coming soon.
| Tool | Description | Credits |
|---|---|---|
| list_templates | List all templates with their variable schemas | 0 |
| search_templates | Filter templates by name or description | 0 |
| get_template | Get template details and variable schema | 0 |
| estimate_cost | Estimate credit cost with live balance check before generating | 0 |
| generate_document | Generate a single document (DOCX or PDF) | 1-2 |
| generate_batch | Generate documents for multiple records (up to 500) | 1-2 each |
| get_batch_status | Check batch progress. Accepts async job IDs and sync batch IDs | 0 |
| check_credits | Check remaining credits | 0 |
| refresh_document_url | Get a fresh signed download URL for an existing document | 0 |
| create_template_from_docx | Create a reusable template from a DOCX URL. Google Drive, Google Docs and Dropbox share links accepted as-is | 0 |
| delete_template | Soft-delete a template. Restorable for 90 days | 0 |
| restore_template | Restore a deleted template (admin or manager role) | 0 |
| submit_feedback | Report feature requests or issues to the support team | 0 |
DOCX = 1 credit. PDF = 2 credits. Rate limit: 100 requests per 15 minutes per IP on the MCP endpoint. Generation calls also count toward the 30/min organisation limit.
Templates support two kinds of blocks, and each expects a different data shape:
{#items}...{/items}): pass an array of objects. Each element renders the block once with its own values.{#isVIP}...{/isVIP}): pass a boolean to toggle. Variables inside the block resolve from the top level of your data, so supply them there, not nested inside the block name.Example: {"discount": true, "discountAmount": "100.00"} renders the discount section with its amount. Nesting the amount inside a discount object leaves it blank.
Agents with no BulkRender account can generate documents and pay per session. Connect using the public MCP URL, no API key needed:
https://api.bulkrender.com/mcp/acp
| Tool | Description | Cost |
|---|---|---|
| acp_list_public_templates | List 5 built-in templates (invoice, quote, contract, report, proposal) with field names | Free |
| acp_create_session | Create a checkout session. Pass records[] with one data object per document. Returns checkout_url for browser payment | - |
| acp_get_session | Poll until completed. Returns download_url per doc and zip_download_url (24h expiry) | Free |
| submit_feedback | Report feature requests or issues to the support team | Free |
Pricing: $0.10/credit. DOCX = 1 credit, PDF = 2 credits. Minimum charge $1.00 (covers up to 10 DOCX or 5 PDF docs). Unused credit is yours if you sign up.
The assistant calls list_templates to find the template, then generate_document or generate_batch, and returns a signed download URL valid for 1 hour.
Need an agent to self-register and maintain its own API key and credit balance over time? See the Agent Provisioning guide for the full flow: autonomous registration, human operator OTP verification, credit top-up, and spend limits.
Create an account, upload your first template, and generate your first document in under five minutes.