+ Start a Discussion

Visualforce Digital Signature --> Recurly + Force.com App integration

I'm trying to integrate Recurly subscription management with an application I am running on force.com. I'd like to host the payment and billing pages with VisualForce but use Recurly servers to process the transactions.

In order to do this I am using the Recurly.js files (https://docs.recurly.com/recurlyjs) However, I need a signature to be created - I have tried all of the different ways (Crypto.sign, Apex, doing a canvas app leveraging the prebuilt PHP libraries, etc) but I am wondering if there is an easier way to do this:

Here is the code from the php page that works leveraging the PHP libraries. Does anyone know how to do this in salesforce without having to have a completly different environment host the PHP/Ruby/Python libraries?


// Required for the API
Recurly_Client::$subdomain = 'subdomain';
Recurly_Client::$apiKey = '111111111111111111111111111';
Recurly_js::$privateKey = 'a111111111111111111111111111111';
$planCode = 'innovator-yearly';
$currency = 'USD';
$signature = Recurly_js::sign(array($planCode));   
<html lang="en">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Innovator Yearly Subscription</title>
  <link rel="stylesheet" href="css/recurly.css" type="text/css" />
<script src="js/jquery.js"></script>
<script src="js/recurly.js"></script>
        subdomain: 'subdomain'
        , currency: 'USD' // GBP | CAD | EUR, etc...

        target: '#recurly-subscribe',
        planCode: 'innovator-yearly',
        successURL: 'success.php',
        signature: '<?php echo $signature;?>',
distinguishContactFromBillingInfo: false,
    collectCompany: false,
    collectContact: true,
    termsOfServiceURL: 'http://subdomain.com/contact/terms-of-use/',
    acceptPaypal: false,
    acceptedCards: ['mastercard',

    <div id="recurly-subscribe">

keywords: digital signature, crypto, PHP, Recurly, Subscription service
Hi Sheri, 

You can try these App Exchange packages, 





Also see the links below with some sample code, 





Matt LunkesMatt Lunkes
Hi Sheri,

I am currently working on the exact same thing.  I don't think that Salesforce supports the use of PHP in Visualforce pages though.  Did you ever find a solution?  If not, how far along did you get in trying to generate a signature with Apex?

Paul BachmannPaul Bachmann
Hi Sheri,

This is more complex APEX than I am used to dealing with, but it is close to working (works in preview).  Maybe a collective effort can get us what we both need.
I need to have E-Sig functionality and then a png file on a Case record that I can call in a custom Print Preview.
Problem I have is this is a hodgepodge from different solutions/advice I've found online.  I think my last major issue is to incorporate a standard controller (need to be able to add in standard page layouts) and then tweak it to point to case instead of Account, I keep getting that wrong as the source code I used pointed to Accts

VisualForce Page

<apex:page docType="html-5.0" controller="CapturePSignatureController" showheader="false" sidebar="false" standardStylesheets="false" id="pg">
 <apex:includeScript value="/soap/ajax/28.0/connection.js"/>
  .container {
   text-align: center;
   font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
   color: cadetblue;
   font-weight: 500;
   font-size: 14px;
  .button {
   font-family: calibri;
   border-radius: 8px;
   background-color: rgb(51, 116, 116);
   height: 36px;
   color: azure;
   font-size: 17px;
   border-width: 0px;
   width: 116px;
 <apex:form id="pbform">
  <apex:pageMessages />
  <div class="container">
   <h1 class="labelCol vfLabelColTextWrap ">Record Patient Signature:</h1>
   <canvas id="PsignatureCanvas" height="100px" width="350px" style="border: 3px solid antiquewhite; border-radius: 8px;" ></canvas>
  <div style="margin-left: 41%;">
   <apex:commandButton value="Save Patient Signature" onclick="savePSignature();return false;" styleClass="button"/>&nbsp;&nbsp;&nbsp;
   <apex:commandButton value="Clear" onclick="clearSign();return false;" styleClass="button"/>

  var canvas;
  var context;
  var drawingUtil;
  var isDrawing = false;
  var accountId = '';
  var prevX, prevY, currX, currY = 0;
  var accountId;

   function DrawingUtil() {
   isDrawing = false;
   canvas.addEventListener("mousedown", start, false);
   canvas.addEventListener("mousemove", draw, false);
   canvas.addEventListener("mouseup", stop, false);
   canvas.addEventListener("mouseout", stop, false);
   canvas.addEventListener("touchstart", start, false);
   canvas.addEventListener("touchmove", draw, false);
   canvas.addEventListener("touchend", stop, false);
   w = canvas.width;
      h = canvas.height;

   function start(event) {
   isDrawing = true;
   prevX = currX;
   prevX = currY;
   currX = event.clientX - canvas.offsetLeft;
   currY = event.clientY - canvas.offsetTop;
   context.fillStyle = "cadetblue";
   context.fillRect(currX, currY, 2, 2);

   function draw(event) {
   if (isDrawing) {
    prevX = currX;
             prevY = currY;
             currX = event.clientX - canvas.offsetLeft;
             currY = event.clientY - canvas.offsetTop;
    context.moveTo(prevX, prevY);
    context.lineTo(currX, currY);
    context.strokeStyle = "cadetblue";
    context.lineWidth = "2";

   function stop(event) {
   if (isDrawing) {
    isDrawing = false;
  function clearSign() {

   canvas = document.getElementById("PsignatureCanvas");
  context = canvas.getContext("2d");
  context.strokeStyle = "black";
  context.lineWidth = "2";
  drawingUtil = new DrawingUtil(canvas);

   function savePSignature() {
   var strDataURI = canvas.toDataURL();
   strDataURI = strDataURI.replace(/^data:image\/(png|jpg);base64,/, "");
   var accId = location.href.split('=')[1];
   accountId = accId;
   var result = CapturePSignatureController.savePSignature(strDataURI, accId, processResult);

   function processResult(result) {
   window.location.href = '/'+accountId;




global with sharing class CapturePSignatureController {
 global static String savePSignature(String imageUrl, String accountId) {
  try {
   Attachment accSign = new Attachment();
   accSign.ParentID = accountId;
   accSign.Body = EncodingUtil.base64Decode(imageUrl);
   accSign.contentType = 'image/png';
   accSign.Name = 'Patient Signature Image';
   accSign.OwnerId = UserInfo.getUserId();
   insert accSign;
   return 'success';
  }catch(Exception e){
   system.debug('---------- ' + e.getMessage());
   return JSON.serialize(e.getMessage());
  return null;