FastSpring and SaaS

Hi,

is there any sample/manual of setting up fast spring for SaaS business model?especially setting update_expires (date) field on recurring basis?

Marcin

This is what I wrote for having automatic subscription renewals with FastSpring:

First off, you have to have two PHP scripts, one that gets run for the initial order and one that gets run when the subscription is renewed.

In my example, I have two plans (Lite and Pro) and I use the same scripts for each FastSpring product and populate some Checkbox custom license field according to the FastSpring product name so I know what features to enable in my app.

I like to store as much information as I can about the order in my LimeLM custom license fields so I try to get every possible FastSpring variable stored.

These are the custom license fields that I created in LimeLM:fastspring_company (String) (Desc: Company name on FastSpring checkout)fastspring_email (String) (Desc: Email on FastSpring checkout)fastspring_name (String) (Desc: Name on FastSpring checkout)fastspring_original_subscription_expiry (Date/Time) (Default Value: + 365 days) (Desc: Original Subscription end date. Set on initial order)fastspring_productName (String) (Desc: FastSpring Product Name that was purchased)fastspring_quantity (Integer) (Desc: Original quantity purchased on FastSpring checkout. This is the number of activations that were purchased. Script generates one product key with 'quantity' activations.)fastspring_reference (String) (Desc: FastSpring Order ID. Initial Order only. Useful for looking up order in FastSpring.)fastspring_subscription (String) (Desc: FastSpring Subscription ID. Consistent between initial order and rebills)fastspring_subscription_renew_count (Integer) (Default Value: 0) (Desc: Auto increments each time the subscription is renewed via FastSpring)fastspring_test (String) (Desc: Whether or not a test credit card was used to create the FastSpring order)is_lite_licese (Checkbox) (Readable in-app) (Desc: If the license has lite functionality. This depends on what plans you have)is_pro_license (Checkbox) (Readable in-app) (Desc: If the license has pro functionality. This depends on what plans you have)notes (String) (Desc: Extra notes about license that you can manually enter)subscription_expiry (Date/Time) (Default Value: + 365 days) (Readable in-app) (Desc: Actual subscription expiry that gets updated on rebills. Use this field in your app to check if subscription is still active.)

***Start of PHP Script for Initial Order<?php// TODO: set your API key found in http://wyday.com/limelm/settings/$api_key = 'TODO';

// TODO: set the version id to generate & find keys for// the version id is found in the url. For example http://wyday.com/limelm/version/100/// the version id is 100.$version_id = 'TODO';

date_default_timezone_set('America/Toronto');

$is_pro_license = ('my-product-name-pro' === $productName); //TODO

function urlEncodePostData($post_data){ $post_string = ''; foreach ($post_data as $key => $value) { if (is_array($value)) { foreach ($value as $sub_value) { $post_string .= $key.'[]='.urlencode($sub_value).'&'; } } else $post_string .= $key.'='.urlencode($value).'&'; } $post_string = rtrim($post_string, '& ');

$request = curl_init('https://wyday.com/limelm/api/rest/'); curl_setopt($request, CURLOPT_HEADER, 0); curl_setopt($request, CURLOPT_ENCODING, ""); curl_setopt($request, CURLOPT_RETURNTRANSFER, 1); curl_setopt($request, CURLOPT_POSTFIELDS, $post_string); curl_setopt($request, CURLOPT_SSL_VERIFYPEER, TRUE); return $request;}

function generateProductKey($post_data){ $request = urlEncodePostData($post_data); $jObj = json_decode(curl_exec($request));

if ($jObj->stat == 'ok') { foreach ($jObj->pkeys->pkey as $pkey) { return $pkey->key; } } else { // Uncomment the next line to see the error LimeLM is giving you. //echo $jObj->message; } return null;}try{ $subscription_expiry = date('Y-m-d H:i:s', strtotime('+1 year')); $post_data = array ( 'method' => 'limelm.pkey.generate', 'api_key' => $api_key, 'version_id' => $version_id, 'num_keys' => 1, 'num_acts' => $quantity, 'email' => $email, 'feature_name' => array( 'is_lite_license', 'is_pro_license', 'subscription_expiry', 'fastspring_company', 'fastspring_email', 'fastspring_name', 'fastspring_original_subscription_expiry', 'fastspring_productName', 'fastspring_quantity', 'fastspring_reference', 'fastspring_subscription', 'fastspring_subscription_renew_count', 'fastspring_test' ), 'feature value' => array( !$is_pro_license, $is_pro_license, $subscription_expiry, $company, $email, $name, $subscription_expiry, $productName, $quantity, $reference, $subscription, 0, $test ), 'nojsoncallback' => 1, 'format' => 'json' ); $product_key = generateProductKey($post_data); echo $product_key . "\r\n";}catch (Exception $e){ // Uncomment the next line to see the exception. //echo 'Failure: '.$e->getMessage();}?>***END of PHP Script for Initial Order

***Start of PHP Script for Subscription Rebill<?php// TODO: set your API key found in http://wyday.com/limelm/settings/$api_key = 'TODO';

// TODO: set the version id to generate & find keys for// the version id is found in the url. For example http://wyday.com/limelm/version/100/// the version id is 100.$version_id = 'TODO';

date_default_timezone_set('America/Toronto');

function urlEncodePostData($post_data){ $post_string = ''; foreach ($post_data as $key => $value) { if (is_array($value)) { foreach ($value as $sub_value) { $post_string .= $key.'[]='.urlencode($sub_value).'&'; } } else $post_string .= $key.'='.urlencode($value).'&'; } $post_string = rtrim($post_string, '& ');

$request = curl_init('https://wyday.com/limelm/api/rest/'); curl_setopt($request, CURLOPT_HEADER, 0); curl_setopt($request, CURLOPT_ENCODING, ""); curl_setopt($request, CURLOPT_RETURNTRANSFER, 1); curl_setopt($request, CURLOPT_POSTFIELDS, $post_string); curl_setopt($request, CURLOPT_SSL_VERIFYPEER, TRUE); return $request;}

function getProductKeyDetails($post_data){ $request = urlEncodePostData($post_data); $jObj = json_decode(curl_exec($request));

if ($jObj->stat == 'ok') { foreach ($jObj->pkeys->pkey as $pkey) { return array ( 'key' => $pkey->key, 'id' => $pkey->id ); } } else { // Uncomment the next line to see the error LimeLM is giving you. //echo $jObj->message; } return null;}

function getSubscriptionExpiryAndRenewCount($post_data){ $request = urlEncodePostData($post_data); $jObj = json_decode(curl_exec($request));

if ($jObj->stat == 'ok') { $subscription_expiry = null; $fastspring_subscription_renew_count = 0; foreach ($jObj->pkey->features->feature as $feature) { if($feature->name == 'subscription_expiry') { $subscription_expiry = $feature->value; } else if($feature->name == 'fastspring_subscription_renew_count') { $fastspring_subscription_renew_count = $feature->value; if($subscription_expiry !== null) break; } } if($subscription_expiry !== null) { return array ( 'subscription_expiry' => $subscription_expiry, 'fastspring_subscription_renew_count' => $fastspring_subscription_renew_count ); } } else { // Uncomment the next line to see the error LimeLM is giving you. //echo $jObj->message; } return null;}

function setProductKeyDetails($post_data){ $request = urlEncodePostData($post_data); $jObj = json_decode(curl_exec($request));

if ($jObj->stat !== 'ok') { // Uncomment the next line to see the error LimeLM is giving you. //echo $jObj->message; }}try{ $post_data = array( 'method' => 'limelm.pkey.advancedSearch', 'api_key' => $api_key, 'version_id' => $version_id, 'email' => $email, 'feature_name' => array('fastspring_subscription'), 'feature_value' => array($subscription), 'feature_match' => array('exact'), 'nojsoncallback' => 1, 'format' => 'json' ); $product_key_details = getProductKeyDetails($post_data); if($product_key_details !== null) { $product_key = $product_key_details['key']; $product_key_id = $product_key_details['id']; $post_data = array( 'method' => 'limelm.pkey.getDetails', 'api_key' => $api_key, 'pkey_id' => $product_key_id, 'nojsoncallback' => 1, 'format' => 'json' ); $subscription_expiry_and_renew_count = getSubscriptionExpiryAndRenewCount($post_data); $subscription_expiry = $subscription_expiry_and_renew_count['subscription_expiry']; $fastspring_subscription_renew_count = $subscription_expiry_and_renew_count['fastspring_subscription_renew_count'] + 1; $current_date_time = date('Y-m-d H:i:s', time()); if($current_date_time > $subscription_expiry) { $new_subscription_expiry = date('Y-m-d H:i:s', strtotime($current_date_time . '+1 year')); } else { $new_subscription_expiry = date('Y-m-d H:i:s', strtotime($subscription_expiry . '+1 year')); } $post_data = array( 'method' => 'limelm.pkey.setDetails', 'api_key' => $api_key, 'pkey_id' => $product_key_id, 'feature_name' => array('subscription_expiry', 'fastspring_subscription_renew_count'), 'feature_value' => array($new_subscription_expiry, $fastspring_subscription_renew_count), 'nojsoncallback' => 1, 'format' => 'json' ); setProductKeyDetails($post_data); echo $product_key . "\r\n"; } }catch (Exception $e){ // Uncomment the next line to see the exception. //echo 'Failure: '.$e->getMessage();}?>***End of PHP Script for Subscription Rebill