Creating webhook for Uninstalling an Shopify App in PHP

Luke_skywalker
Tourist
5 0 1

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

Replies 9 (9)

Evulse
Shopify Partner
411 0 64

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";

Want an app but can't find what you need? Let us know we custom build apps for Free

Luke_skywalker
Tourist
5 0 1

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

Evulse
Shopify Partner
411 0 64

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();

 

Want an app but can't find what you need? Let us know we custom build apps for Free

Luke_skywalker
Tourist
5 0 1

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. 

Evulse
Shopify Partner
411 0 64

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

  1. Customer clicks install app
  2. The app starts the oauth processes
  3. the app gets a code and asks for an access token
  4. recurring payment is requested
  5. recurring payment is approved
  6. uninstall webhook is registered via API
  7. other webhooks are registered against store via API
  8. app is now functional
Want an app but can't find what you need? Let us know we custom build apps for Free

Luke_skywalker
Tourist
5 0 1

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.

Evulse
Shopify Partner
411 0 64

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

 

Want an app but can't find what you need? Let us know we custom build apps for Free

Evulse
Shopify Partner
411 0 64

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);

}

 

Want an app but can't find what you need? Let us know we custom build apps for Free

Luke_skywalker
Tourist
5 0 1

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