Shopify NetSuite Integration via Heroku
Functionality Overview
- Initial Heroku Setup and app creation
- GitHub implementation and deploying in Heroku
- Creating webhooks in Shopify
- Creating a script to connect to NetSuite (Restlet) and payload conversion
- Restlet in NetSuite to fetch payload and do updates
Initial Heroku Setup
Create a Heroku account and purchase a dyno (Eco), need to purchase a dyno for creating an app.
Dyno: The containers used at Heroku are called “dynos.” Dynos are isolated, virtualized Linux containers that are designed to execute code based on a user-specified command. Your app can scale to any specified number of dynos based on its resource demands. Heroku’s container management capabilities provide you with an easy way to scale and manage the number, size, and type of dynos your app may need at any given time.

Create a php app in Heroku by navigating from Heroku dashboard -> Create new app
After creating the app, create a private git hub repository and connect the repository to Heroku account.
Open the git hub account in the same browser and in Heroku deploy subtab click the GitHub icon.
Once you have connected to the repository, we need to deploy the branch to Heroku. For deploying the git hub needs to have files for developing the apps.
GitHub implementation and Deploying in Heroku
Files needed for Heroku PHP app
- composer.json
- composer.lock
- Procfile
- requirements.txt
- vendor
Composer.json :
- It resolves all dependencies listed in your composer.json file and writes all of the packages and their exact versions to the composer.lock file, locking the project to those specific versions. …
- It then implicitly runs the install command.
Example file content:
{
“require” : {
“silex/silex”: “^2.0.4”,
“monolog/monolog”: “^1.22”,
“twig/twig”: “^2.0”,
“symfony/twig-bridge”: “^3”
},
“require-dev”: {
“heroku/heroku-buildpack-php”: “dev-master”
},
“post-install-cmd”: [
“php artisan clear-compiled”,
“chmod -R 777 public/”
]
}
Composer.lock :
- The composer.lock file as its name suggests “locks” the dependencies for the corresponding project. Meaning, when the Composer has finished installing dependencies, it writes all of the packages and the exact versions of them that it downloaded to the composer.lock file.
- This file will be large and is automatically genarating.
Procfile :
- Procfile is a mechanism for declaring what commands are run by your application’s dynos on the Heroku platform. From Process Types and the Procfile, which is a good introduction, but basically you use the Procfile to tell Heroku how to run various pieces of your app.
- Example server
web: vendor/bin/heroku-php-apache2
Requirements.txt:
- The requirements.txt file lists the app dependencies together.
- Example file content:
bob-builder>=0.0.15
s3cmd>=1.6.0
Vendor:
- Git repository always contains the vendor directory. This directory should not be under version control. Only ‘composer.json’ and ‘composer.lock’ files need to be added because Heroku handles the installation of dependencies on each deploy.
- This folder will be automatically generated and contains all the required dependencies. The server file is contained in the vendor folder.
Implementing files through Heroku CLI
- Install a Heroku CLI on your computer and bring up the command prompt and run by administrator mode.
- Install a composer in your computer also for creating composer file. For installation, we need to have the xampp windows installer or any PHP installer.
- After installing type composer install in cmd to install the composer file. Specify the folder location before code execution
- Every time when we change anything in the composer file, we need to update the composer from the cmd, this will update the lock file and add dependencies accordingly.
- On installing composer.json and composer.lock and vendor file will be available in the current folder.
- Push the files to the git hub repository which we created as private for this sync.
- From cmd we can login to the Heroku account by “heroku login” this command. The user will navigate to a page showing login icon. Once connected, the user can create application from cmd also.
Deploying in Heroku
- Navigate to the Heroku app dashboard and click Deploy Branch button.
- All the updated files will be deploy in Heroku after successful deployment.
- If there is any issue persist in deploying, we can see it in the logs.
More -> view logs - Once deployment is completed and on successful, the log will be in status 200.
Create Webhook in Heroku
- Navigation More -> view webhook -> create new
- We need to create a webhook in Heroku to capture the request sent from the Shopify. If the payload is not being sent will be captured in the webhook and the issue will be shown in the log.
- The issue can be found out from here and the service unavailable means there is no dyno subscription to track this request.
- Make sure that you are added the build packs in Heroku. By this only we can deploy the application. App -> settings -> add build packs
Heroku to NetSuite Connection
Create integration record in NetSuite and generate access token for the application also.
By the details from NetSuite create a PHP file to call https request to NetSuite.
The example code is below:
<?php
class callNetsuiteApi{
// Training CREDENTIALS
const NETSUITE_CONSUMER_KEY = ‘************************’;
const NETSUITE_ACCOUNT = ‘*************’;
const NETSUITE_CONSUMER_SECRET = ‘**********************’;
const NETSUITE_TOKEN_ID = ‘****************************’;
const NETSUITE_TOKEN_SECRET = ‘************************’;
public function callRestApi($url,$data){
$oauth_nonce = md5(mt_rand());
$oauth_timestamp = time();
$oauth_signature_method = ‘HMAC-SHA256’;
$oauth_version = “1.0”;
// generate Signature
$baseString = $this->restletBaseString(“POST”,
$url,
self::NETSUITE_CONSUMER_KEY,
self::NETSUITE_TOKEN_ID,
$oauth_nonce,
$oauth_timestamp,
$oauth_version,
$oauth_signature_method,null);
$key = rawurlencode(self::NETSUITE_CONSUMER_SECRET) .’&’. rawurlencode(self::NETSUITE_TOKEN_SECRET);
$signature = base64_encode(hash_hmac(‘sha256’, $baseString, $key, true));
// GENERATE HEADER TO PASS IN CURL
$header = ‘Authorization: OAuth ‘
.’realm=”‘ .rawurlencode(self::NETSUITE_ACCOUNT) .'”, ‘
.’oauth_consumer_key=”‘ .rawurlencode(self::NETSUITE_CONSUMER_KEY) .'”, ‘
.’oauth_token=”‘ .rawurlencode(self::NETSUITE_TOKEN_ID) .'”, ‘
.’oauth_nonce=”‘ .rawurlencode($oauth_nonce) .'”, ‘
.’oauth_timestamp=”‘ .rawurlencode($oauth_timestamp) .'”, ‘
.’oauth_signature_method=”‘ .rawurlencode($oauth_signature_method) .'”, ‘
.’oauth_version=”‘ .rawurlencode($oauth_version) .'”, ‘
.’oauth_signature=”‘ .rawurlencode($signature) .'”‘;
return $this->callCurl($header,$url,$data);
}
public function callCurl($header,$url,$data){
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => “”,
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30000,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => “POST”,
CURLOPT_POSTFIELDS => json_encode($data),
CURLOPT_HTTPHEADER => array(
$header,
“accept: */*”,
“accept-language: en-US,en;q=0.8”,
“content-type: application/json”,
“User-Agent: Mozilla/5.0”
),
));
$response = curl_exec($curl);
curl_close($curl);
$product = json_decode($response, true);
return $product;
}
public function restletBaseString($httpMethod, $url, $consumerKey, $tokenKey, $nonce, $timestamp, $version, $signatureMethod, $postParams){
//http method must be upper case
$baseString = strtoupper($httpMethod) .’&’;
//include url without parameters, schema and hostname must be lower case
if (strpos($url, ‘?’)){
$baseUrl = substr($url, 0, strpos($url, ‘?’));
$getParams = substr($url, strpos($url, ‘?’) + 1);
} else {
$baseUrl = $url;
$getParams = “”;
}
$hostname = strtolower(substr($baseUrl, 0, strpos($baseUrl, ‘/’, 10)));
$path = substr($baseUrl, strpos($baseUrl, ‘/’, 10));
$baseUrl = $hostname . $path;
$baseString .= rawurlencode($baseUrl) .’&’;
//all oauth and get params. First they are decoded, next alphabetically sorted, next each key and values is encoded and finally whole parameters are encoded
$params = array();
$params[‘oauth_consumer_key’] = array($consumerKey);
$params[‘oauth_token’] = array($tokenKey);
$params[‘oauth_nonce’] = array($nonce);
$params[‘oauth_timestamp’] = array($timestamp);
$params[‘oauth_signature_method’] = array($signatureMethod);
$params[‘oauth_version’] = array($version);
foreach (explode(‘&’, $getParams .”&”. $postParams) as $param) {
$parsed = explode(‘=’, $param);
if ($parsed[0] != “”) {
$value = isset($parsed[1]) ? urldecode($parsed[1]): “”;
if (isset($params[urldecode($parsed[0])])) {
array_push($params[urldecode($parsed[0])], $value);
} else {
$params[urldecode($parsed[0])] = array($value);
}
}
}
//all parameters must be alphabetically sorted
ksort($params);
$paramString = “”;
foreach ($params as $key => $valueArray){
//all values must be alphabetically sorted
sort($valueArray);
foreach ($valueArray as $value){
$paramString .= rawurlencode($key) . ‘=’. rawurlencode($value) .’&’;
}
}
$paramString = substr($paramString, 0, -1);
$baseString .= rawurlencode($paramString);
return $baseString;
}
}
$_POST = json_decode(file_get_contents(‘php://input’), true);
$data = $_POST;
$details=(array)$data;
$finaldetails[‘payload’] = $data;
$finaldetails[‘event_type’]=’order_cancel’;
$finaldetails=(object)$finaldetails;
$obj = new callNetsuiteApi();
$url = “**************************************”;
$response = $obj->callRestApi($url,$finaldetails);
?>
- Add the script in the git hub and according to our preference change the event type in the code.
- By using this file name we are invoking this code and perform in Heroku to send pa the payload to NetSuite.
Creating webhook in Shopify
- Navigate to settings in Shopify and take the notification tab and the webhook section.
- Need to add our Heroku app URL followed by our git hub file name. Once all the configuration has done will be directly call the restlet via Heroku and sent payload from Shopify to NetSuite.