I am using a webhook to store the data in Zoho CRM from Shopify using webhook on order-fulfillment(can be interpreted as saving data in the database from Shopify, if you don't know what Zoho CRM is), but for some reason, it gets deleted every 3-4 days.
According to the docs, I need to verify the webhook and send a response 200 within 5 seconds, or else it is interpreted as an error. If the webhook doesn't receive success response, it tries 19 more times and then deletes the webhook. I am fulfilling all of these steps and even then my webhook is deleted. What am I doing wrong and how can I solve this?
Following is my code(I am using PHP for this)-
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
// Buffer all upcoming output...
ob_start();
// Send your response.
// echo "Here be response";
http_response_code(200);
// Get the size of the output.
$size = ob_get_length();
// Disable compression (in case content length is compressed).
header("Content-Encoding: none");
// Set the content length of the response.
header("Content-Length: {$size}");
// Close the connection.
header("Connection: close");
// Flush all output.
ob_end_flush();
ob_flush();
flush();
// Close current session (if it exists).
if(session_id()) session_write_close();
usleep(5000000); // 5 seconds
Up until here, I am sending the response 200 and using sleep so that no other code is processed for 5 seconds, so it should always return 200 header, once the response is sent, I am processing the result
Code beyond this should be irrelevelant to the question -- Just matching various conditions to save data but if it is necessary, let me know, I will explain the logic
define('SHOPIFY_APP_SECRET', 'somesecret');
function verify_webhook($data, $hmac_header)
{
$calculated_hmac = base64_encode(hash_hmac('sha256', $data, SHOPIFY_APP_SECRET, true));
return hash_equals($hmac_header, $calculated_hmac);
}
$hmac_header = $_SERVER['HTTP_X_SHOPIFY_HMAC_SHA256'];
$data = file_get_contents('php://input');
$verified = verify_webhook($data, $hmac_header);
$log_file_data = 'request_' . date('Y-m-d H:i:s') . '.log';
file_put_contents($log_file_data, "verification webhook \r\n".print_r($verified, true)."\r\n");
if($verified){
include 'ZohoCrmClient.php';
include 'ShopifyClient.php';
$zoho_obj = new ZohoCrmClient();
$shopify_obj = new ShopifyClient;
// $response = file_get_contents('php://input');
$response = $data;
$response = json_decode($response, true);
// print_r($response); die;
file_put_contents($log_file_data, "shopify_data \r\n".print_r($response, true)."\r\n", FILE_APPEND);
// die;
// check if order already exists
$order_name = rawurlencode($response['name']);
// $order_name = rawurlencode('OS-5889');
$order_name = "Subject:equals:$order_name";
$exists = $zoho_obj->searchZohoCrmRecord('Sales_Orders', $order_name);
$tagArr = explode(", ", $response['customer']['tags']);
if(in_array('cafe-pending', $tagArr) || in_array('cafe-approved', $tagArr)){
// print_r($exists); die;
/*if(empty($exists)){*/
// echo $response['email'];
$productInfo = $response['line_items'];
$email = $response['email'];
$available_prod = [];
$avail_prod_ids = [];
$postData = array();
$proceed = 0;
$postData['Product_Details'] = array();
foreach($productInfo as $key => $product_info){
if(!$proceed){
$proceed = 1;
// $tagArr = explode(", ", $response['customer']['tags']);
$lead = $zoho_obj->searchZohoRecordByEmail('Leads', $email);
$lead_data = json_decode($lead);
// print_r($lead_data);
file_put_contents($log_file_data, "\r\nlead_data \r\n".print_r($lead_data, true)."\r\n", FILE_APPEND);
if(isset($lead_data->data[0]) && !empty($lead_data->data[0])){
$recordArray = array();
$recordObject = array();
$recordObject["overwrite"] = true;
$recordObject["notify_lead_owner"] = true;
$recordObject["notify_new_entity_owner"]= true;
$recordArray[] = $recordObject;
$requestBody["data"] = $recordArray;
$convert = $zoho_obj->convertLead($lead_data->data[0]->id, $requestBody);
$convert = json_decode($convert, true);
file_put_contents($log_file_data, "\r\nconvert_data \r\n".print_r($convert, true)."\r\n", FILE_APPEND);
// print_r($convert); die;
// if(isset($convert['data'][0]) && !empty($convert['data'][0]) && !isset($convert['data'][0]['status'])){
$contact_id = isset($convert['data'][0]['Contacts']) ? $convert['data'][0]['Contacts'] : '';
$account_id = isset($convert['data'][0]['Accounts']) ? $convert['data'][0]['Accounts'] : '';
// }
// print_r($convert);
}else{
$account = $zoho_obj->searchZohoRecordByEmail('Accounts', $email);
$account = json_decode($account, true);
file_put_contents($log_file_data, "\r\naccount_data \r\n".print_r($account, true)."\r\n", FILE_APPEND);
// print_r($account);
// echo $account['data'][0]['id'];
// die;
if(isset($account['data'][0]) && !empty($account['data'][0])){
$account_id = $account['data'][0]['id'];
}else{
// create account
$createAccountData = array();
$createAccountData[0]['Account_Name'] = $response['customer']['default_address']['company'];
$createAccountData[0]['Contact_Name'] = $response['customer']['first_name'];
$createAccountData[0]['Last_Name'] = isset($response['customer']['last_name']) && !empty($response['customer']['last_name']) ? $response['customer']['last_name'] : $response['customer']['first_name'];
$createAccountData[0]['Phone'] = $response['phone'];
$createAccountData[0]['Email'] = $response['email'];
$createAccountData[0]['Shopify_Customer_ID'] = (string)$response['customer']['id'];
$createAccountData[0]['Account_Type'] = 'Shopify';
$createAccountData[0]['Account_Status'] = 'Active';
$createAccountArr = array('data' => $createAccountData);
$createAccount = $zoho_obj->createZohoCrmRecord('Accounts', $createAccountArr);
$createAccount = json_decode($createAccount, true);
// print_r($createAccount);
file_put_contents($log_file_data, "\r\create_account \r\n".print_r($createAccount, true)."\r\n", FILE_APPEND);
$account_id = $createAccount['data'][0]['details']['id'];
}
// convert to contact
$contact = $zoho_obj->searchZohoRecordByEmail('Contacts', $email);
$contact = json_decode($contact, true);
// print_r($contact);
file_put_contents($log_file_data, "\r\ncontact_data \r\n".print_r($contact, true)."\r\n", FILE_APPEND);
if(isset($contact['data'][0]) && !empty($contact['data'][0])){
$contact_id = $contact['data'][0]['id'];
}else{
// create contact
$createContactData = array();
$createContactData[0]['Account_Name'] = $account_id;
$createContactData[0]['First_Name'] = $response['customer']['first_name'];
$createContactData[0]['Last_Name'] = isset($response['customer']['last_name']) && !empty($response['customer']['last_name']) ? $response['customer']['last_name'] : $response['customer']['first_name'];
$createContactData[0]['Phone'] = $response['phone'];
$createContactData[0]['Email'] = $response['email'];
$createContactArr = array('data' => $createContactData);
$createContact = $zoho_obj->createZohoCrmRecord('Contacts', $createContactArr);
$createContact = json_decode($createContact, true);
// print_r($createContact);
file_put_contents($log_file_data, "\r\create_contact \r\n".print_r($createContact, true)."\r\n", FILE_APPEND);
$contact_id = $createContact['data'][0]['details']['id'];
}
}
// echo $response['billing_address']['city'];
$postData['Account_Name'] = $account_id;
$postData['Billing_City'] = $response['billing_address']['city'] ?? '';
$postData['Billing_Code'] = $response['billing_address']['zip'] ?? '';
$postData['Billing_Country'] = $response['billing_address']['country'] ?? '';
$postData['Billing_State'] = $response['billing_address']['province'] ?? '';
$postData['Billing_Street'] = $response['billing_address']['address2'] ?? '';
// $postData['Carrier'] = '';
$postData['Contact_Name'] = $contact_id;
// $postData['Created_By'] = '';
$postData['Customer_No'] = !empty($response['customer']['id']) ? (string)$response['customer']['id'] : '';
$postData['Shipping_City'] = $response['shipping_address']['city'] ?? '';
$postData['Shipping_Code'] = $response['shipping_address']['zip'] ?? '';
$postData['Shipping_Country'] = $response['shipping_address']['country'] ?? '';
$postData['Shipping_State'] = $response['shipping_address']['province'] ?? '';
$postData['Shipping_Street'] = $response['shipping_address']['address2'] ?? '';
// $postData['SO_Number'] = '';
$postData['Status'] = 'Fulfilled';
$postData['Subject'] = $response['name'];
$postData['Discount'] = !empty($response['total_discounts']) ? (float)$response['total_discounts'] : (float)0;
$postData['Tax'] = !empty($response['total_tax']) ? (float)$response['total_tax'] : (float)0;
$postData['Adjustment'] = !empty($response['total_shipping_price_set']) ? (float)$response['total_shipping_price_set']['shop_money']['amount'] : (float)0;
// $postData['Terms_and_Conditions'] = '';
// $postData['shopifyextension__Lead_Name'] = $contact_id;
$postData['shopifyextension__Order_Shopify_Id'] = (string)$response['id'];
$postData['shopifyextension__Shopify_Order_Created_Date'] = $response['created_at'];
$postData['shopifyextension__Shopify_Fulfillment_Status'] = $response['fulfillment_status'];
$postData['shopifyextension__Shopify_Financial_Status'] = $response['financial_status'];
$postData['shopifyextension__Shopify_Reference_Id'] = (string)$response['id'];
$postData['shopifyextension__Source'] = 'Shopify';
}
// print_r($product_info);
// file_put_contents($log_file_data, "product_name \r\n".addcslashes($product_info['name'], '()')."\r\n", FILE_APPEND);
$productName = $product_name = $product_info['name'];
$product_name = rawurlencode(addcslashes($product_name, '(),'));
$product = "Product_Name:equals:$product_name";
// echo $product; die;
file_put_contents($log_file_data, "product_name \r\n".$product_name."\r\n", FILE_APPEND);
$zoho_product_record = $zoho_obj->searchZohoCrmRecord('Products', $product);
// print_r($zoho_product_record);
// die;
$product_record = json_decode($zoho_product_record);
file_put_contents($log_file_data, "\r\nproduct_record \r\n".print_r($product_record, true)."\r\n", FILE_APPEND);
// die;
if(isset($product_record->data[0]) && !empty($product_record->data[0])){
$product_id = $product_record->data[0]->id;
// shopify sku code, product id and shopify variant id should be saved
if(empty($product_record->data[0]->Product_Code) || empty($product_record->data[0]->Shopify_id) || empty($product_record->data[0]->Shopify_Variant_id) || empty($product_record->data[0]->Product_Active)) {
$updateProductData = array();
$updateProductData[0]['Product_Code'] = $product_info['sku'];
$updateProductData[0]['Product_Active'] = true;
$updateProductData[0]['Shopify_id'] = (int)$product_info['id'];
$updateProductData[0]['Shopify_Variant_id'] = (int)$product_info['variant_id'];
$updateProductArr = array('data' => $updateProductData);
$updateProduct = $zoho_obj->updateZohoCrmRecord('Products', $product_id, $updateProductArr);
$updateProduct = json_decode($updateProduct, true);
// print_r($updateProduct);
file_put_contents($log_file_data, "\r\nupdate_product \r\n".print_r($updateProduct, true)."\r\n", FILE_APPEND);
}
}else{
$productData = $shopify_obj->searchRecord('products', $product_info['product_id']);
file_put_contents($log_file_data, "\r\nproduct_id \r\n".$product_info['product_id']."\r\n", FILE_APPEND);
$productData = json_decode($productData, true);
file_put_contents($log_file_data, "\r\nproduct_data_shopify \r\n".print_r($productData, true)."\r\n", FILE_APPEND);
$Vendor_Name = $productData['product']['vendor'];
$Vendor_Name = rawurlencode(addcslashes($Vendor_Name, '(),'));
$vendor = "Vendor_Name:equals:$Vendor_Name";
$vendorData = $zoho_obj->searchZohoCrmRecord('Vendors', $vendor);
$vendorData = json_decode($vendorData, true);
$vendor_id = '';
if(isset($vendorData['data'][0]) && !empty($vendorData['data'][0])) {
$vendor_id = $vendorData['data'][0]['id'];
}
$variantData = $shopify_obj->searchRecord('variants', $product_info['variant_id']);
$variantData = json_decode($variantData, true);
file_put_contents($log_file_data, "\r\nvariant_data_shopify \r\n".print_r($variantData, true)."\r\n", FILE_APPEND);
$createProductData = array();
$createProductData[0]['Product_Name'] = $productName;
$createProductData[0]['Description'] = $productData['product']['body_html'];
$createProductData[0]['Product_Active'] = true;
$createProductData[0]['Product_Category'] = $productData['product']['product_type'];
$createProductData[0]['Product_Code'] = isset($variantData['variant']['sku']) ? $variantData['variant']['sku'] : $product_info['sku'];
// $createProductData[0]['Owner'] = 2466207000000114009;
// $createProductData[0]['Qty_Ordered'] = 'Shopify';
// $createProductData[0]['Qty_in_Demand'] = 'Active';
$createProductData[0]['Qty_in_Stock'] = isset($variantData['variant']['inventory_quantity']) ? $variantData['variant']['inventory_quantity'] : $productData['product']['variants'][0]['inventory_quantity'];
// $createProductData[0]['Reorder_Level'] = 'Active';
$createProductData[0]['Taxable'] = isset($variantData['variant']['taxable']) ? (bool)$variantData['variant']['taxable'] : (bool)$productData['product']['variants'][0]['taxable'];
$createProductData[0]['Unit_Price'] = isset($variantData['variant']['price']) ? $variantData['variant']['price'] : $productData['product']['variants'][0]['price'];
$createProductData[0]['Usage_Unit'] = 'Active';
$createProductData[0]['Vendor_Name'] = $vendor_id; // lookup
$createProductData[0]['Shopify_id'] = (int)$productData['product']['id'];
$createProductData[0]['Shopify_Variant_id'] = isset($variantData['variant']['id']) ? (int)$variantData['variant']['id'] : (int)$productData['product']['variants'][0]['id'];
$createProductArr = array('data' => $createProductData);
$createProduct = $zoho_obj->createZohoCrmRecord('Products', $createProductArr);
$createProduct = json_decode($createProduct, true);
print_r($createProduct);
file_put_contents($log_file_data, "\r\ncreate_product \r\n".print_r($createProduct, true)."\r\n", FILE_APPEND);
$product_id = $createProduct['data'][0]['details']['id'];
}
// create product
$product_details_temp = [];
$product_details_temp['product'] = $product_id;
$product_details_temp['list_price'] = (double)$product_info['price'];
// $product_details_temp['total'] = (double)$Amount;
/*
** product wise tax and discount **
$product_details_temp['Tax'] = !empty($product_info['tax_lines']) ? (float)$product_info['tax_lines'][0]['price'] : (float)0;
$product_details_temp['Discount'] = !empty($product_info['discount_allocations']) ? (float)$product_info['discount_allocations'][0]['amount'] : (float)0;*/
$product_details_temp['quantity'] = (double)$product_info['quantity'];
array_push($postData['Product_Details'], $product_details_temp);
}
file_put_contents($log_file_data, "\r\npost_data \r\n".print_r($postData, true)."\r\n", FILE_APPEND);
// echo 'here';
// die;
if($proceed){
$zohoData = ['data' => array($postData)];
if(empty($exists)){
$create = $zoho_obj->createZohoCrmRecord('Sales_Orders', $zohoData);
// print_r($create);
file_put_contents($log_file_data, "\r\ncreate_data \r\n".$create."\r\n", FILE_APPEND);
}else{
$exists = json_decode($exists, true);
$sales_id = $exists['data'][0]['id'];
$update = $zoho_obj->updateZohoCrmRecord('Sales_Orders', $sales_id, $zohoData);
// print_r($update);
file_put_contents($log_file_data, "\r\nupdate_data \r\n".$update."\r\n", FILE_APPEND);
}
}else{
// echo 'No products found!';
file_put_contents($log_file_data, "\r\ncreate_data \r\n".'No products found!'."\r\n", FILE_APPEND);
}
}else{
// echo 'customer tag is not cafe-approved or cafe-pending';
file_put_contents($log_file_data, "\r\ncustomer tag is not: \r\n".'cafe-approved or cafe-pending'."\r\n", FILE_APPEND);
}
}else{
error_log('Webhook verified: '.var_export($verified, true)); //check error.log to see the result
}
Reference-
Shopify Webhook - https://shopify.dev/tutorials/manage-webhooks
Question in shopify community- https://community.shopify.com/c/Shopify-APIs-SDKs/Web-hook-getting-deleted-every-other-day-from-store-admin/td-p/532972
Sending response and keep running script- continue processing php after sending http response