Sometimes we want to generate SIGN Requests with documents that come from outside of Salesforce, from software like ERP or tools that our team uses normally. This is possible via Manual Signing V2, however, if we want to automate the process, it is now possible via APEX.
To achieve this, you have to follow these Two Steps:
Step 1:
// ============================================================
// STEP 1 — PREPARE the Sign Request for the external document
// (this creates the SR record but does NOT launch it yet)
// ============================================================
// Load your PDF as Base64 — replace with your actual source
// e.g. from a ContentVersion, a Blob, or a PDF Butler generation
ContentVersion cv = [SELECT Id, VersionData, Title FROM ContentVersion WHERE Id = '068WU00000JNrWvYAL' LIMIT 1]; // You have to indicate the ContentVersion of the file here
String pdfBase64 = EncodingUtil.base64Encode(cv.VersionData);
String pdfFileName = cv.Title + '.pdf'; // PDF Name
// IDs you must replace with your real values
String signRequestTemplateId = 'a0DJ8000001ycmGMAQ'; // Your SIGN Request Template Id
Id recordId = '0010900000Dy1FjAAJ'; // The Salesforce record to link the SR to
// prepareSignRequest returns the new Sign Request Id
Id srId = (new cadmus_sign2.SignButlerClientApi())
.prepareSignRequest(pdfBase64, pdfFileName, signRequestTemplateId, recordId);
System.debug('New Sign Request Id (srId): ' + srId);
Step 2:
// ============================================================
// STEP 2 — ADD the signing placeholder and LAUNCH the SR
// (must be in the same transaction as Step 1)
// ============================================================
Id SrId = 'a0CWU00001WZYww2AH'; // Sign Request ID generated in the first step
ContentVersion cv = [SELECT Id, VersionData, Title FROM ContentVersion WHERE Id = '068WU00000JNrWvYAL' LIMIT 1]; // Content Version ID
RrLaunchSignRequest.LaunchSignRequestVo lsrVo = new RrLaunchSignRequest.LaunchSignRequestVo();
lsrVo.signRequestId = srId;
// --- Placeholder positioning ---
// Point to the ContentVersion that holds the PDF page where the placeholder goes
DnDPlaceholderController.DnDPlaceholderContentData cvData =
new DnDPlaceholderController.DnDPlaceholderContentData();
cvData.contentVersionId = '068WU00000JNrWvYAL'; // same CV used above
DnDPlaceholderController.DnDPlaceholderNode loc =
new DnDPlaceholderController.DnDPlaceholderNode();
loc.page = 0; // 0-based page index
loc.x = 85.207825; // X coordinate on the page
loc.y = 495.2145; // Y coordinate on the page
loc.sbId = 'SIG001'; // Placeholder identifier defined in your SR Template
cvData.locations = new List<DnDPlaceholderController.DnDPlaceholderNode>{ loc };
lsrVo.contentVersions = new List<DnDPlaceholderController.DnDPlaceholderContentData>{ cvData };
// --- Signer / Stakeholder ---
SignButlerConfigDataModal.stakeholder sh = new SignButlerConfigDataModal.stakeholder();
sh.id = '003J8000008xUPQIA2'; // Contact or User Id of the signer
sh.firstName = 'Joe';
sh.lastName = 'Doe';
sh.email = 'joe.doe@pdfbutler.com';
sh.locale = 'en';
sh.signingMethods = new SignButlerConfigDataModal.signingMethods(
true, // handwritten
true, // drawn
true, // mailOtp
true, // upload
false // smsOtp
); //Sign Methods enabled
lsrVo.stakeholders = new List<SignButlerConfigDataModal.stakeholder>{ sh };
// This call adds the placeholder AND launches the Sign Request
cadmus_sign2.SignButlerClientApi.addPlaceholderAndLaunchSignRequestStatic(lsrVo);
System.debug('Sign Request launched with Id: ' + srId);
Each piece of code should be executed separatelly.
This Apex code could be invoked from a flow or any other Apex class. For more information about our API, please check this article: SIGN BUTLER V2 – API Overview – PDF Butler.