Salesforce Integration

Generate PDFs from Salesforce records using the DataToPDF API.

Prerequisites

  1. A DataToPDF account with a Starter plan or higher (API access required)
  2. An API key generated from Settings > API Key
  3. A PDF template configured with Salesforce as the data source
  4. Add https://datatopdf.app to your Salesforce Remote Site Settings

Setup

Add Remote Site Setting

  1. Go to Setup > Security > Remote Site Settings
  2. Click New Remote Site
  3. Enter:
    • Remote Site Name: DataToPDF
    • Remote Site URL: https://datatopdf.app
    • Active: checked
  4. 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

  1. Go to Setup > Security > Named Credentials
  2. Click the External Credentials tab
  3. Click New
  4. Configure:
FieldValue
LabelDataToPDF_Auth
NameDataToPDF_Auth
Authentication ProtocolCustom
  1. Click Save

Step 2: Add a Custom Header for the API Key

  1. On the External Credential detail page, scroll to Custom Headers
  2. Click New
  3. Configure:
FieldValue
NameX-API-Key
ValueYour DataToPDF API key (e.g., pk_live_xxxxx)
Sequence Number1
  1. Click Save

Step 3: Create a Principal

  1. On the External Credential detail page, scroll to Principals
  2. Click New
  3. Configure:
FieldValue
Parameter NameDataToPDF_Principal
Sequence Number1
Identity TypeNamed Principal
  1. Click Save

Step 4: Grant Permission Set Access

  1. Go to Setup > Permission Sets
  2. Create or edit a Permission Set for users who need to call the API
  3. Click External Credential Principal Access
  4. Click Edit
  5. Add DataToPDF_Auth - DataToPDF_Principal to Enabled External Credential Principals
  6. Click Save
  7. Assign this Permission Set to the appropriate users (or assign to the Integration User for Flows)

Step 5: Create the Named Credential

  1. Go to Setup > Security > Named Credentials
  2. On the Named Credentials tab, click New
  3. Configure:
FieldValue
LabelDataToPDF
NameDataToPDF
URLhttps://datatopdf.app/api/v1
Enabled for CalloutsChecked
External CredentialDataToPDF_Auth
Generate Authorization HeaderUnchecked
Allow Formulas in HTTP HeaderChecked
Allow Formulas in HTTP BodyChecked
  1. Click Save

2. Register External Service

  1. Go to Setup > Integrations > External Services
  2. Click Add an External Service
  3. Select From API Specification
  4. Configure:
FieldValue
External Service NameDataToPDF
Select a Named CredentialDataToPDF
Service SchemaSelect 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.

  1. Click Save & Next
  2. Select the generatePdf operation and click Next
  3. Click Done

3. Using External Services in Flows

Once registered, you can use the DataToPDF API in any Flow:

Record-Triggered Flow Example

  1. Create a new Record-Triggered Flow
  2. Set the trigger: Object = Opportunity, Trigger = A record is created or updated
  3. Add Entry Conditions: Stage equals Closed Won
  4. Add an Action element
  5. Search for DataToPDF and select generatePdf
  6. Configure the action inputs:
InputValue
templateIdYour template ID (e.g., clx1234567890)
recordId{!$Record.Id}
  1. Store the output in a variable (e.g., pdfResponse)
  2. 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:

FieldValue
ObjectContentVersion
TitleInvoice_{!$Record.Name}
PathOnClientInvoice.pdf
VersionData{!pdfResponse.pdf}
FirstPublishLocationId{!$Record.Id}

Flow Use Cases

TriggerTemplateDescription
Opportunity Closed WonInvoice templateAuto-generate invoice
Quote ApprovedQuote PDF templateGenerate quote document
Case ClosedCase Summary templateCreate case resolution PDF
Contract ActivatedContract templateGenerate 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:

ParameterTypeDescription
apiKeyStringYour DataToPDF API key
templateIdStringThe ID of the PDF template
recordIdIdThe 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:

ParameterTypeDescription
apiKeyStringYour DataToPDF API key
templateIdStringThe ID of the PDF template
recordIdIdThe Salesforce record ID
fileNameStringName 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:

ParameterTypeDescription
apiKeyStringYour DataToPDF API key
templateIdStringThe ID of the PDF template
recordIdIdThe Salesforce record ID

Returns: Blob - The PDF data

Throws: PdfGeneratorException on error

PdfResult Class

PropertyTypeDescription
successBooleanWhether the PDF was generated successfully
pdfBase64StringBase64-encoded PDF data (on success)
contentTypeStringMIME type, always application/pdf (on success)
errorMessageStringHuman-readable error message (on failure)
errorCodeStringError code for programmatic handling (on failure)

Error Codes

CodeDescription
INVALID_REQUESTMissing required parameter
UNAUTHORIZEDMissing or invalid API key
RATE_LIMIT_EXCEEDEDToo many requests (30/minute)
SUBSCRIPTION_REQUIREDActive subscription required
GENERATION_LIMIT_EXCEEDEDMonthly PDF limit reached
TEMPLATE_NOT_FOUNDTemplate not found or not accessible
CONNECTION_NOT_FOUNDSalesforce connection not configured
DATA_FETCH_ERRORFailed to fetch record data
CALLOUT_ERRORHTTP callout failed
HTTP_ERRORNon-200 HTTP response
UNKNOWN_ERRORUnexpected 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

  1. Store API keys securely - Use Custom Metadata Types or Custom Settings with appropriate field-level security
  2. Handle errors gracefully - Always check result.success or catch PdfGeneratorException
  3. Respect rate limits - The API allows 30 requests per minute; implement queuing for bulk operations
  4. Use async processing - For bulk PDF generation, use Queueable Apex or Batch Apex