Salesforce Integration
Generate PDFs from Salesforce records using the DataToPDF API.
Prerequisites
- A DataToPDF account with a Starter plan or higher (API access required)
- An API key generated from Settings > API Key
- A PDF template configured with Salesforce as the data source
- Add
https://datatopdf.appto your Salesforce Remote Site Settings
Setup
Add Remote Site Setting
- Go to Setup > Security > Remote Site Settings
- Click New Remote Site
- Enter:
- Remote Site Name:
DataToPDF - Remote Site URL:
https://datatopdf.app - Active:
checked
- Remote Site Name:
- Click Save
External Services (No-Code)
External Services allows you to call the DataToPDF API directly from Flows without writing any Apex code.
1. Create Named Credential
The new Named Credential framework separates the endpoint (Named Credential) from the authentication (External Credential).
Step 1: Create an External Credential
- Go to Setup > Security > Named Credentials
- Click the External Credentials tab
- Click New
- Configure:
| Field | Value |
|---|---|
| Label | DataToPDF_Auth |
| Name | DataToPDF_Auth |
| Authentication Protocol | Custom |
- Click Save
Step 2: Add a Custom Header for the API Key
- On the External Credential detail page, scroll to Custom Headers
- Click New
- Configure:
| Field | Value |
|---|---|
| Name | X-API-Key |
| Value | Your DataToPDF API key (e.g., pk_live_xxxxx) |
| Sequence Number | 1 |
- Click Save
Step 3: Create a Principal
- On the External Credential detail page, scroll to Principals
- Click New
- Configure:
| Field | Value |
|---|---|
| Parameter Name | DataToPDF_Principal |
| Sequence Number | 1 |
| Identity Type | Named Principal |
- Click Save
Step 4: Grant Permission Set Access
- Go to Setup > Permission Sets
- Create or edit a Permission Set for users who need to call the API
- Click External Credential Principal Access
- Click Edit
- Add
DataToPDF_Auth - DataToPDF_Principalto Enabled External Credential Principals - Click Save
- Assign this Permission Set to the appropriate users (or assign to the Integration User for Flows)
Step 5: Create the Named Credential
- Go to Setup > Security > Named Credentials
- On the Named Credentials tab, click New
- Configure:
| Field | Value |
|---|---|
| Label | DataToPDF |
| Name | DataToPDF |
| URL | https://datatopdf.app/api/v1 |
| Enabled for Callouts | Checked |
| External Credential | DataToPDF_Auth |
| Generate Authorization Header | Unchecked |
| Allow Formulas in HTTP Header | Checked |
| Allow Formulas in HTTP Body | Checked |
- Click Save
2. Register External Service
- Go to Setup > Integrations > External Services
- Click Add an External Service
- Select From API Specification
- Configure:
| Field | Value |
|---|---|
| External Service Name | DataToPDF |
| Select a Named Credential | DataToPDF |
| Service Schema | Select Complete URL and upload the OpenAPI file |
Download the OpenAPI specification file: https://datatopdf.app/docs/api/openapi.yaml
Then upload this file when prompted to create the External Service.
- Click Save & Next
- Select the
generatePdfoperation and click Next - Click Done
3. Using External Services in Flows
Once registered, you can use the DataToPDF API in any Flow:
Record-Triggered Flow Example
- Create a new Record-Triggered Flow
- Set the trigger: Object =
Opportunity, Trigger =A record is created or updated - Add Entry Conditions:
StageequalsClosed Won - Add an Action element
- Search for
DataToPDFand selectgeneratePdf - Configure the action inputs:
| Input | Value |
|---|---|
| templateId | Your template ID (e.g., clx1234567890) |
| recordId | {!$Record.Id} |
- Store the output in a variable (e.g.,
pdfResponse) - Add a Create Records element to save the PDF as a file
Saving the PDF as a File
Add a Create Records element after the External Service action:
| Field | Value |
|---|---|
| Object | ContentVersion |
| Title | Invoice_{!$Record.Name} |
| PathOnClient | Invoice.pdf |
| VersionData | {!pdfResponse.pdf} |
| FirstPublishLocationId | {!$Record.Id} |
Flow Use Cases
| Trigger | Template | Description |
|---|---|---|
| Opportunity Closed Won | Invoice template | Auto-generate invoice |
| Quote Approved | Quote PDF template | Generate quote document |
| Case Closed | Case Summary template | Create case resolution PDF |
| Contract Activated | Contract template | Generate signed contract PDF |
OpenAPI Specification
The OpenAPI specification for External Services is available at:
- URL:
https://datatopdf.app/docs/api/openapi.yaml
Apex Integration
For more control, complex logic, or batch processing, use the Apex class directly.
Deploy the Apex Class
Deploy the PdfGeneratorService class to your Salesforce org.
Download the Apex class files:
Deploy using Salesforce CLI:
sf project deploy start --source-dir salesforce/classes
Or copy the class contents manually in Setup > Apex Classes.
Apex Usage
Generate PDF and Get Base64 Data
String apiKey = 'pk_your_api_key_here';
String templateId = 'clx1234567890';
Id recordId = '001xx000003DGbYAAW'; // Account, Contact, or any Salesforce record
PdfGeneratorService.PdfResult result = PdfGeneratorService.generatePdf(apiKey, templateId, recordId);
if (result.success) {
// result.pdfBase64 contains the base64-encoded PDF
// result.contentType is 'application/pdf'
System.debug('PDF generated successfully!');
} else {
System.debug('Error: ' + result.errorCode + ' - ' + result.errorMessage);
}
Generate PDF and Save as File
String apiKey = 'pk_your_api_key_here';
String templateId = 'clx1234567890';
Id accountId = '001xx000003DGbYAAW';
String fileName = 'Invoice_2024.pdf';
try {
Id contentVersionId = PdfGeneratorService.generateAndSavePdf(
apiKey,
templateId,
accountId,
fileName
);
System.debug('File created with ID: ' + contentVersionId);
} catch (PdfGeneratorService.PdfGeneratorException e) {
System.debug('Error: ' + e.getMessage());
}
The PDF will be saved as a Salesforce File (ContentVersion) and automatically linked to the record.
Generate PDF as Blob
String apiKey = 'pk_your_api_key_here';
String templateId = 'clx1234567890';
Id recordId = '001xx000003DGbYAAW';
try {
Blob pdfBlob = PdfGeneratorService.generatePdfBlob(apiKey, templateId, recordId);
// Use the blob for email attachments, custom file handling, etc.
} catch (PdfGeneratorService.PdfGeneratorException e) {
System.debug('Error: ' + e.getMessage());
}
Apex API Reference
PdfGeneratorService.generatePdf(apiKey, templateId, recordId)
Generates a PDF and returns detailed result information.
Parameters:
| Parameter | Type | Description |
|---|---|---|
| apiKey | String | Your DataToPDF API key |
| templateId | String | The ID of the PDF template |
| recordId | Id | The Salesforce record ID |
Returns: PdfResult
PdfGeneratorService.generateAndSavePdf(apiKey, templateId, recordId, fileName)
Generates a PDF and saves it as a ContentVersion attached to the record.
Parameters:
| Parameter | Type | Description |
|---|---|---|
| apiKey | String | Your DataToPDF API key |
| templateId | String | The ID of the PDF template |
| recordId | Id | The Salesforce record ID |
| fileName | String | Name for the PDF file (.pdf extension added automatically if missing) |
Returns: Id - The ContentVersion ID
Throws: PdfGeneratorException on error
PdfGeneratorService.generatePdfBlob(apiKey, templateId, recordId)
Generates a PDF and returns it as a Blob.
Parameters:
| Parameter | Type | Description |
|---|---|---|
| apiKey | String | Your DataToPDF API key |
| templateId | String | The ID of the PDF template |
| recordId | Id | The Salesforce record ID |
Returns: Blob - The PDF data
Throws: PdfGeneratorException on error
PdfResult Class
| Property | Type | Description |
|---|---|---|
| success | Boolean | Whether the PDF was generated successfully |
| pdfBase64 | String | Base64-encoded PDF data (on success) |
| contentType | String | MIME type, always application/pdf (on success) |
| errorMessage | String | Human-readable error message (on failure) |
| errorCode | String | Error code for programmatic handling (on failure) |
Error Codes
| Code | Description |
|---|---|
INVALID_REQUEST | Missing required parameter |
UNAUTHORIZED | Missing or invalid API key |
RATE_LIMIT_EXCEEDED | Too many requests (30/minute) |
SUBSCRIPTION_REQUIRED | Active subscription required |
GENERATION_LIMIT_EXCEEDED | Monthly PDF limit reached |
TEMPLATE_NOT_FOUND | Template not found or not accessible |
CONNECTION_NOT_FOUND | Salesforce connection not configured |
DATA_FETCH_ERROR | Failed to fetch record data |
CALLOUT_ERROR | HTTP callout failed |
HTTP_ERROR | Non-200 HTTP response |
UNKNOWN_ERROR | Unexpected error |
Examples
Lightning Web Component Button
// generatePdfButton.js
import { LightningElement, api } from 'lwc';
import generatePdf from '@salesforce/apex/PdfGeneratorController.generatePdf';
export default class GeneratePdfButton extends LightningElement {
@api recordId;
@api templateId;
isLoading = false;
async handleClick() {
this.isLoading = true;
try {
const contentVersionId = await generatePdf({
recordId: this.recordId,
templateId: this.templateId
});
// Navigate to the file or show success message
} catch (error) {
// Handle error
} finally {
this.isLoading = false;
}
}
}
// PdfGeneratorController.cls
public with sharing class PdfGeneratorController {
@AuraEnabled
public static Id generatePdf(Id recordId, String templateId) {
// Retrieve API key from Custom Metadata or Custom Setting
String apiKey = PDF_Settings__c.getInstance().API_Key__c;
return PdfGeneratorService.generateAndSavePdf(
apiKey,
templateId,
recordId,
'Generated_Document.pdf'
);
}
}
Flow Action
// PdfGeneratorFlowAction.cls
public with sharing class PdfGeneratorFlowAction {
public class PdfRequest {
@InvocableVariable(required=true label='Record ID')
public Id recordId;
@InvocableVariable(required=true label='Template ID')
public String templateId;
@InvocableVariable(required=true label='File Name')
public String fileName;
}
public class PdfResponse {
@InvocableVariable(label='Content Version ID')
public Id contentVersionId;
@InvocableVariable(label='Success')
public Boolean success;
@InvocableVariable(label='Error Message')
public String errorMessage;
}
@InvocableMethod(label='Generate PDF' description='Generates a PDF from a template')
public static List<PdfResponse> generatePdfs(List<PdfRequest> requests) {
List<PdfResponse> responses = new List<PdfResponse>();
String apiKey = PDF_Settings__c.getInstance().API_Key__c;
for (PdfRequest req : requests) {
PdfResponse res = new PdfResponse();
try {
res.contentVersionId = PdfGeneratorService.generateAndSavePdf(
apiKey,
req.templateId,
req.recordId,
req.fileName
);
res.success = true;
} catch (Exception e) {
res.success = false;
res.errorMessage = e.getMessage();
}
responses.add(res);
}
return responses;
}
}
Best Practices
- Store API keys securely - Use Custom Metadata Types or Custom Settings with appropriate field-level security
- Handle errors gracefully - Always check
result.successor catchPdfGeneratorException - Respect rate limits - The API allows 30 requests per minute; implement queuing for bulk operations
- Use async processing - For bulk PDF generation, use Queueable Apex or Batch Apex