Custom SDK
Build a custom SDK for your preferred language using the Pogodoc REST API
Create Your Own SDK
If an official SDK doesn't exist for your preferred programming language, you can easily build your own by wrapping the Pogodoc REST API. This guide explains the API call patterns and workflows used in our official SDKs.
API Reference
Complete REST API documentation
This guide follows the implementation patterns from the TypeScript SDK. You can reference it while building your own SDK.
Built an SDK? We'd love to feature it! Submit a PR to add your SDK to our official documentation, or reach out to us at [email protected].
Authentication
All API requests require authentication using a Bearer token:
Authorization: Bearer YOUR_API_TOKENSet the base URL to:
https://api.pogodoc.comSecurity Best Practice: Never hardcode API tokens. Use environment variables or secure configuration management.
Core Workflows
There are three main workflows for document generation:
- Standard Generation - Initialize job, upload data/template, start render, poll for completion
- Immediate Render - Single API call for quick, synchronous rendering
- Template Management - Upload, extract, preview, and save templates
1. Standard Document Generation
This is the recommended workflow for most use cases. It provides reliability and handles larger documents well.
High-Level Flow
Initialize Render Job
Create a new render job and get presigned URLs for uploading data and templates.
Endpoint: POST /documents/init → API Reference
- Use
templateIdfor saved templates presignedTemplateUploadUrlis only provided if you're using an inline template (not a saved template)formatOptsis optional
Upload Data to S3 Upload your template data as JSON to the presigned S3
URL.
This is a direct S3 upload - do not include the Authorization header.
Upload Template (if inline) If you're using an inline template (not a
saved template), upload it to S3.
Skip this step if you're using a templateId - the template is already
stored.
Start Render Job
Trigger the actual rendering process.
Endpoint: POST /documents/{jobId}/render → API Reference
Set shouldWaitForRenderCompletion: true for synchronous rendering, but
note this may timeout for large documents.
Poll for Job Completion
Repeatedly check the job status until it's complete.
Endpoint: GET /jobs/{jobId} → API Reference
Polling Strategy:
- Wait 1 second before first poll
- Poll every 500ms
- Maximum 60 attempts (30 seconds total)
- Return final status even if not "done"
Implementation Example (Pseudocode)
async function generateDocument(config) {
// Step 1: Initialize
const initResponse = await POST("/documents/init", {
type: config.renderConfig.type,
target: config.renderConfig.target,
templateId: config.templateId,
formatOpts: config.renderConfig.formatOpts,
});
// Step 2: Upload data to S3
await PUT(initResponse.presignedDataUploadUrl, JSON.stringify(config.data), {
"Content-Type": "application/json",
});
// Step 3: Upload template to S3 (if inline)
if (config.template && initResponse.presignedTemplateUploadUrl) {
await PUT(initResponse.presignedTemplateUploadUrl, config.template, {
"Content-Type": "text/html",
});
}
// Step 4: Start render
await POST(`/documents/${initResponse.jobId}/render`, {
shouldWaitForRenderCompletion: false,
});
// Step 5: Poll for completion
return await pollForCompletion(initResponse.jobId);
}
async function pollForCompletion(jobId, maxAttempts = 60, intervalMs = 500) {
await sleep(1000); // Initial wait
for (let i = 0; i < maxAttempts; i++) {
const job = await GET(`/jobs/${jobId}`);
if (job.status === "done") {
return job;
}
await sleep(intervalMs);
}
// Return final status even if not complete
return await GET(`/jobs/${jobId}`);
}2. Immediate Render
For small documents that need quick, synchronous rendering, use the immediate render endpoint.
Single API Call
Endpoint: POST /documents/immediate-render → API Reference
Limitations: - May timeout for large or complex documents - No progress tracking - Not recommended for production use cases Use the standard generation workflow for reliability.
Implementation Example (Pseudocode)
async function generateDocumentImmediate(config) {
const response = await POST("/documents/immediate-render", {
template: config.template,
templateId: config.templateId,
data: config.data,
type: config.renderConfig.type,
target: config.renderConfig.target,
formatOpts: config.renderConfig.formatOpts,
});
return response;
}3. Template Management
Save and update templates for reuse across multiple document generations.
Saving a New Template
Initialize Template Creation
Get a template ID and presigned S3 upload URL.
Endpoint: GET /templates/init → API Reference
Extract Template Files Trigger extraction of the ZIP file. Endpoint:
PATCH /templates/{templateId}/unzip → API
Reference
Generate Previews Create PDF and PNG previews using sample data.
Endpoint: POST /templates/{templateId}/render-previews → API
Reference
Finalize Template
Save the template with metadata and get templateId.
Endpoint: POST /templates/{templateId} → API Reference
Implementation Example (Pseudocode)
async function saveTemplate(filePath, metadata) {
// Step 1: Initialize
const initResponse = await GET("/templates/init");
const templateId = initResponse.templateId;
// Step 2: Upload ZIP to S3
const fileData = readFile(filePath);
const fileSize = getFileSize(filePath);
await PUT(initResponse.presignedTemplateUploadUrl, fileData, {
"Content-Type": "application/zip",
"Content-Length": fileSize,
});
// Step 3: Extract files
await POST(`/templates/${templateId}/unzip`);
// Step 4: Generate previews
const previews = await POST(`/templates/${templateId}/render-previews`, {
type: metadata.type,
data: metadata.sampleData,
});
// Step 5: Finalize template
await POST(`/templates/${templateId}`, {
templateInfo: {
title: metadata.title,
description: metadata.description,
type: metadata.type,
categories: metadata.categories,
sampleData: metadata.sampleData,
sourceCode: metadata.sourceCode,
},
previewIds: {
pdfJobId: previews.pdfPreview.jobId,
pngJobId: previews.pngPreview.jobId,
},
});
return templateId;
}Updating a Template
The update flow is identical to saving, except:
- You get a new
contentIdinstead oftemplateIdfrom init - Use
PUT /templates/{templateId}(API Reference) instead ofPOST - Pass the original
templateIdin the URL, and the newcontentIdin the body
async function updateTemplate(templateId, filePath, metadata) {
// Get new content ID
const initResponse = await GET("/templates/init");
const contentId = initResponse.templateId;
// Upload, extract, preview (same as save)
// ...
// Update template
await PUT(`/templates/${templateId}`, {
contentId: contentId,
templateInfo: {
/* metadata */
},
previewIds: {
/* preview job IDs */
},
});
return contentId;
}Type Definitions
Template Types
react- React/Vue/Angular/Svelte templatesejs- Embedded JavaScript templateshtml- Plain HTML templateslatex- LaTeX documents (🚧 coming soon)docx- Word documents (🚧 coming soon)xlsx- Excel spreadsheets (🚧 coming soon)pptx- PowerPoint presentations (🚧 coming soon)
Render Targets
pdf- PDF documentspng- PNG imagesjpg- JPEG images (🚧 coming soon)html- HTML output (🚧 coming soon)docx- Word documents (🚧 coming soon)xlsx- Excel spreadsheets (🚧 coming soon)pptx- PowerPoint presentations (🚧 coming soon)
Format Options
{
format?: 'A3' | 'A4' | 'A5' | 'Letter' | 'Legal' | 'Tabloid';
waitForSelector?: string; // CSS selector to wait for
fromPage?: number; // Starting page (partial render)
toPage?: number; // Ending page (partial render)
}Job Status
initialized- Job created but not startedin-progress- Currently renderingdone- Rendering completefailed- Rendering failed (check error details)
Built an SDK? We'd love to feature it! Submit a PR to add your SDK to our official documentation, or reach out to us at [email protected].