Topics covering webhook creation & management, event handling, Pub/Sub, and Eventbridge, in Shopify apps.
Hello
I am not able to connect the dots for creating a webhook using api in PHP when any shop-user un-installs a shopify app.
When i use the term webhook, i assume there will be some UI to set the resource url which will trigger when the un-install event fires.
In shopify app dashboard it is clueless to find the same concept.
Please help me out how i can configure or code the webhook un-install app in PHP.
Help will be very much appreciated.
Thanks
You can only do this with an api call the webhook is called "app/uninstalled" documentation on registering a webhook can be found here
http://docs.shopify.com/api/webhook
One thing to be mindful of is it can take a few minutes to come through and you can't use an address only your machine can handle such as "http://localhost";
Hello.
Thanks for replying back.
How i can register a webhook for "app/uninstall".
In the shopify partner dashboard, i didn't get a clue to register for the same.
Is the webhook need to be set from our server side?
Thanks
It needs to be server side. We put it as part of the installation flow. We also use PHP so the below example is using Silex and Guzzle.
$uninstallRequest = $app['guzzle.client']->post('https://'.$request->get('shop').'/admin/webhooks.json';); $uninstallRequest->addHeader('X-Shopify-Access-Token', $response['access_token']); $uninstallRequest->addHeader('Content-Type', 'application/json'); $uninstallRequest->addHeader('Accept', 'application/json'); $uninstallRequest->setBody(json_encode(array("webhook" => array( 'topic' => "app/uninstalled", 'address' => $app['shopify']['credentials']['return_url']."uninstall", 'format' => "json" )))); $uninstallResponse = $uninstallRequest->send()->json();
Thanks Ryan.
But I am using Cakephp framework and my server is hosted by Amazon.
I am still not cleared about the point.
My impression about webhook is when a client uninstalls app, the notification of the event will be sent to the app developer. As we can see whenever the there is install/uninstall there is a listing of the same in the Partner account.
So how my server will get notified whenever a shopify client uninstalls my app.
Wouldn't it should be like there must be some url to be set in the app dashboard that will be called whenever the app gets uninstalled. And that is called "WEBHOOK"
Please correct me if i am wrong in the flow or missed some point.
Luke there is no UI for setting this you need to send a POST request to the client store who installed the app with the
Topic : app/uninstalled
Address : the url you want to receive the webhook
Format : json
So the installation of our app looks like below
Hey Ryan
Thanks for the flow you explained, It was really awesome of you.
I change my Shopify Oauth Flow a bit.
Whenever user installs my app, after receiving the Access Code..i try to register "app/uninstall" webhook to the shop_domain.
Below is the code i Used in Php
function registerShopifyAppUninstallWebhook($shop_domain, $access_token){ $API_KEY = SHOPIFY_API_KEY; $SECRET = SHOPIFY_SHARED_SECRET; $TOKEN = $access_token; $STORE_URL = $shop_domain; $url = 'https://'; . $API_KEY . ':' . md5($SECRET . $TOKEN) . '@' . $STORE_URL . '/admin/webhooks.json'; $params = '{"webhook": { "topic": "app/uninstalled", "address": '.SITE_URL.'"users/setShopifyUninstall", "format": "json" }}'; $session = curl_init(); curl_setopt($session, CURLOPT_URL, $url); curl_setopt($session, CURLOPT_HTTPPOST, 1); // Tell curl that this is the body of the POST curl_setopt($session, CURLOPT_POSTFIELDS, $params); curl_setopt($session, CURLOPT_HEADER, false); curl_setopt($session, CURLOPT_HTTPHEADER, array('Accept: application/json', 'Content-Type: application/json')); curl_setopt($session, CURLOPT_RETURNTRANSFER, true); if(ereg("^(https)",$url)) curl_setopt($session,CURLOPT_SSL_VERIFYPEER,false); $response = curl_exec($session); curl_close($session); $body =json_decode($response); if($body) return $body; else return "0"; }
I get this error in response
"{"error":"795: unexpected token at '------------------------------a311830a7bdb\r\nContent-Disposition: form-data; name=\"topic\"\r\n\r\napp/uninstalled\r\n------------------------------a311830a7bdb\r\nContent-Disposition: form-data; name=\"address\"\r\n\r\nhttps://digicorp.contentplum.com/users/setShopifyUninstall\r\n------------------------------a311830a...: form-data; name=\"format\"\r\n\r\njson\r\n------------------------------a311830a7bdb--\r\n'"}"
Do you have any idea where i am getting wrong.
There are a few little things such as the SITE_URL being outside the brackets and the use of curl HTTPPOST. I tested the below request and it looks ok. Also ereg is depreciated so I switched that out.
function registerShopifyAppUninstallWebhook($shop_domain, $access_token){ $API_KEY = SHOPIFY_API_KEY; $SECRET = SHOPIFY_SHARED_SECRET; $TOKEN = $access_token; $STORE_URL = $shop_domain; $url = 'https://'; . $STORE_URL . '/admin/webhooks.json'; $params = '{"webhook": { "topic": "app/uninstalled", "address": "'.SITE_URL.'users/setShopifyUninstall", "format": "json" }}'; $session = curl_init(); curl_setopt($session, CURLOPT_URL, $url); curl_setopt($session, CURLOPT_POST, 1); // Tell curl that this is the body of the POST curl_setopt($session, CURLOPT_POSTFIELDS, $params); curl_setopt($session, CURLOPT_HEADER, false); curl_setopt($session, CURLOPT_HTTPHEADER, array('Accept: application/json', 'Content-Type: application/json', 'X-Shopify-Access-Token: '.$TOKEN)); curl_setopt($session, CURLOPT_RETURNTRANSFER, true); if(preg_match("/^(https)/",$url)) curl_setopt($session,CURLOPT_SSL_VERIFYPEER,false); $response = curl_exec($session); curl_close($session); $body =json_decode($response); if($body) return $body; else return "0"; }
Also I just looked at what request libraries are available for cake as using curl is very messy and leads to issues. It looks like it has a built in HttpSocket
http://book.cakephp.org/2.0/en/core-utility-libraries/httpsocket.html
I found a good example of HttpSocket and sending JSON.
public function actiontooutbound($idUser, $course, $price){ $HttpSocket = new HttpSocket(); $data = array( "api_key" => "API KEY", "user_id" => $idUser, "event" => "other", "extra" => array( "course" => $course, "price"=> $price ) ); $request = array( 'header' => array( 'Content-Type' => 'application/json', ), ); $data = json_encode($data); $response = $HttpSocket->post('http://api.outbound.io/api/v1/track';, $data, $request); }
Hey Ryan..
Thanks a lot.
I finally succeeded "Registering a app/uninstall webhook" in my shopify app.
I took reference from Cakephp Plugin for Shopify App.
It was worth a experience. 🙂
Thanks for your support.
Below is code i used :
function registerShopifyAppUninstallWebhook($shop_domain, $access_token){ $method = "POST"; $path = "/admin/webhooks.json"; $params = array("webhook" => array( "topic"=>"app/uninstalled", "address"=> SITE_URL."users/setShopifyUninstall", "format"=> "json")); $password = md5(SHOPIFY_SHARED_SECRET.$access_token);//If your shopify app is public $baseurl = "https://".SHOPIFY_API_KEY.":".$password."@".$shop_domain."/";; $url = $baseurl.ltrim($path, '/'); $query = in_array($method, array('GET','DELETE')) ? $params : array(); $payload = in_array($method, array('POST','PUT')) ? stripslashes(json_encode($params)) : array(); $request_headers = in_array($method, array('POST','PUT')) ? array("Content-Type: application/json; charset=utf-8", 'Expect:') : array(); $request_headers[] = 'X-Shopify-Access-Token: ' . $access_token; list($response_body, $response_headers) = $this->Curl->HttpRequest($method, $url, $query, $payload, $request_headers); $this->last_response_headers = $response_headers; $response = json_decode($response_body, true); if (isset($response['errors']) or ($this->last_response_headers['http_status_code'] >= 400)) $body = $response['errors']; else $body = $response_body; /*Debug the output in a text_file*/ $destination = realpath('../../app/webroot/execution_log') . '/'; $fh = fopen($destination."shopify_app.txt",'a') or die("can't open file"); date_default_timezone_set('GMT'); fwrite($fh, "\n\nDATE: ".date("Y-m-d H:i:s")."\n".$body); fclose($fh); /*Debug Code Ends*/ return (is_array($response) and (count($response) > 0)) ? array_shift($response) : $response; }
Thanks