Woocommerce webhook order to deal

Hi, I use a woocommerce webhook and a php file in websites directory to create a deal from a woocommerce order. Until recently (about a week ago) it worked fine. But now there are no new deals and in the webhook log section I see thet the webhook is actually fired, but it not working as expected. The message is:

[Response] => Array
(
[Code] => 403
[Message] => Forbidden
[Headers] => WpOrg\Requests\Utility\CaseInsensitiveDictionary Object
(
[data:protected] => Array
(
[date] => Sat, 25 Nov 2023 22:51:40 GMT
[content-type] => text/html; charset=iso-8859-1
[cf-cache-status] => DYNAMIC
[report-to] => {“endpoints”:[{“url”:“https://a.nel.cloudflare.com/report/v3?s=yP5lpHdbN9OLQPRGZWs2KoQ7X2aJL26XYyMu6DPSCjAMVvN5%2FzrT8ifCR6RL9shBviiTGAWW8sw%2F5XlKg4dxRy73hI0x9jn6bmdZn4TdxCCyIcyQthgGH1Adwf77iH4TEA599rm8PYyH”}],“group”:“cf-nel”,“max_age”:604800}
[nel] => {“success_fraction”:0,“report_to”:“cf-nel”,“max_age”:604800}
[server] => cloudflare
[cf-ray] => 82bd75281a74b341-PRG
[content-encoding] => br
[alt-svc] => h3=“:443”; ma=86400
)

                    )

                [Body] => fiorita.cz
            )

    )

)

could you please advise on this matter.

Regards, kirgo123

Hello @kirgo123, welcome to the community!

Can you give us extra context? Here are some lingering questions:

  1. Is the issue related to a webhook created in Pipedrive?
  2. Is the issue related with calling Pipedrive’s endpoint to create deals?
  3. The object you posted, is a response to what kind of request?

Hi, thank you very much for your message.

  1. No, the webhook is created in Woocommerce. The purpose is to send woocommerce orders to Pipedrive and create deals based on order details automatically.

  2. Yes, the php file calls the Pipedrive’s endpoint according to Pipedrive’s documentation
    $url = ‘https://’ . $company_domain . ‘.pipedrive.com/api/v1/deals?api_token=’ . $api_token;

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $deal);

echo ‘Sending request…’ . PHP_EOL;

$output = curl_exec($ch);
curl_close($ch);

// Create an array from the data that is sent back from the API
// As the original content from server is in JSON format, you need to convert it to PHP array
$result = json_decode($output, true);

// Check if an ID came back, if did print it out
if (!empty($result[‘data’][‘id’])) {
echo ‘Deal was added successfully!’ . PHP_EOL;
}

foreach ($order_data as $key => $value) {
echo $key . PHP_EOL;
}

foreach ($deal as $key => $value) {
echo $key . PHP_EOL;
}

it all worked perfectly well untill about a week ago.

  1. I simulated new order in Woocommerce and checked error woocommerce log. Before that, I checked Cloudflare settings - there has not been any change or update since the problem started, so, I assume the problem is on Pipedrive’s side

Here is the full file sending info to the deals endpoint:

$api_token = ‘********************************’;

// Pipedrive company domain

// Extract the JSON payload from the incoming request
$payload = file_get_contents(‘php://input’);

$order_data = json_decode($payload, true);

$company_domain = ‘fioritaflowers’;
$order_id = $order_data[‘id’];
$customer_name = $order_data[‘shipping’][‘first_name’] . ’ ’ . $order_data[‘shipping’][‘last_name’];
$customer_phone = $order_data[‘shipping’][‘phone’];
$customer_address = $order_data[‘shipping’][‘address_1’] . ’ ’ . $order_data[‘shipping’][‘address_2’];
$customer_postcode = $order_data[‘shipping’][‘postcode’];
$sender_name = $order_data[‘billing’][‘first_name’]. ’ ’ . $order_data[‘billing’][‘last_name’];
$sender_phone = $order_data[‘billing’][‘phone’];
$sender_email = $order_data[‘billing’][‘email’];
$order_total = $order_data[‘total’];
$order_date = $order_data[‘date_created’];

// Initialize a counter for the occurrence of “_wc_eco_fields_value”
$value_counter = 0;

// Check if the “fee_lines” key exists in the data
// if (isset($order_data[‘fee_lines’]) && is_array($order_data[‘fee_lines’])) {
// // Loop through the fee lines to find occurrences of “_wc_eco_fields_value”
// foreach ($order_data[‘fee_lines’] as $fee_line) {
// // Check if the fee line has the “_wc_eco_fields_value” key
// if (isset($fee_line[‘meta_data’]) && is_array($fee_line[‘meta_data’])) {
// foreach ($fee_line[‘meta_data’] as $meta) {
// if (isset($meta[‘key’]) && $meta[‘key’] === ‘_wc_eco_fields_value’) {
// $value_counter++;

// // Check if this is the third occurrence
// if ($value_counter === 2) {
// $delivery_date_string = is_array($meta[‘value’]) ? reset($meta[‘value’]) : ‘’;

// // Output the value of the third occurrence

// break 2; // Exit both loops
// }
// }
// }
// }
// }
// }

// Convert the date string to a valid date format (YYYYMMDD)
// $parts = explode(‘/’, $delivery_date_string);

// if (count($parts) === 3) {
// $day = str_pad($parts[0], 2, ‘0’, STR_PAD_LEFT);
// $month = str_pad($parts[1], 2, ‘0’, STR_PAD_LEFT);
// $year = substr($parts[2], -2); // Get the last two digits of the year
// $year_full = $parts[2];

// // $delivery_date = $year . $month . $day;
// // $exp_close_day = $day . ‘.’ . $month . ‘.’ . $year_full;

// } else {
// echo “Invalid date format: $delivery_date_string”;
// }

$deal_title = $delivery_date . ’ ’ . $order_id . ’ ’ . $customer_name;

// Initialize an empty array to store product data
$products_bought = array();
$line_items = $order_data[‘line_items’];

foreach ($line_items as $item) {
$product_name = $item[‘name’];
$product_quantity = $item[‘quantity’];
$product_price = $item[‘price’];
$product_image_url = isset($item[‘image’][‘src’]) ? $item[‘image’][‘src’] : ‘’;

// Create an array to represent the product
$product = array(
    'name' => $product_name,
    'quantity' => $product_quantity,
    'price' => $product_price,
    'image_url' => $product_image_url, // Include the product image URL here
);

// Add the product to the list of products bought
$products_bought[] = $product;

}

$products_bought_plain = “”;
foreach ($products_bought as $product) {
// Format each product entry
$productText = “{$product[‘name’]} (Quantity: {$product[‘quantity’]}, Price: {$product[‘price’]})”;

// Add the product image URL as a link
$productText .= "\nImage URL: {$product['image_url']}\n";

// Append this product to the plain text list
$products_bought_plain .= $productText . "\n";

}

// Output the plain text list
echo $products_bought_plain;

// Deal title and Organization ID
$deal = array(
‘title’ => $deal_title,
‘value’ => $order_total,
‘pipeline_id’ => 2,

‘expected_close_date’ => $order_date,
‘31d16193cdf2f40ad0d079ba6ce125cca6d5318f’ => $sender_name,
‘dbf4a6d8283c506241d4c3e9f42b08717b28c7bf’ => $customer_name,
‘person_id’ => $customer_name,
‘ca34cc84eb3345bec0ca84ea385f5fe3a8c51242’ => $customer_phone,
‘85721ee018ee6e54097d5e7ca53ad39757e74ee7’ => $customer_address,
‘b708db8c32a00e67c354eda18d2d3f287b6cca1b’ => $customer_postcode,
// ‘8e2203728f8c4e21c0770146c63339ae0313563c’ => $exp_close_day,
‘535052f880ae4f50a5180b171cc62561c7f2b2e0’ => $sender_phone,
‘a04d63d7fb0aa8ed9f49068f7e056b1c19d6114a’ => $sender_email,
‘353ae4a6aa4f7bbe86bb846c65107ea255539e76’ => $products_bought_plain,
// ‘products_bought’ => $products_bought, // Include the products bought here

);

$url = ‘https://’ . $company_domain . ‘.pipedrive.com/api/v1/deals?api_token=’ . $api_token;

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $deal);

echo ‘Sending request…’ . PHP_EOL;

$output = curl_exec($ch);
curl_close($ch);

// Create an array from the data that is sent back from the API
// As the original content from server is in JSON format, you need to convert it to PHP array
$result = json_decode($output, true);

// Check if an ID came back, if did print it out
if (!empty($result[‘data’][‘id’])) {
echo ‘Deal was added successfully!’ . PHP_EOL;
}

foreach ($order_data as $key => $value) {
echo $key . PHP_EOL;
}

foreach ($deal as $key => $value) {
echo $key . PHP_EOL;
}

I commented out some code that might be debatable although it worked a week ago, but still no progress

Here are some sugestions:

  1. The first step would be to check if the api_token is correct.
  2. Next, I try a plain request to the Pipedrive API endpoint to test it, either with curl or Postman, to see if it’s working properly.
  3. If it’s working with a plain (direct) request but not with your integration, the might be a bottleneck in the middle preventing the request. You can try to get help here: https://community.cloudflare.com/search?q=woocommerce%20403

Another tip: have you considered using the SDK? It might save you from writing and maintaining a lot of code:

Hi, thank you very much for trying to help me.

  1. this is correct

  2. I tried postman and it posts the deal alright, so it is visible in my app. SO…

  3. … the problem is with some changes in Cloudflare configurattion (since it worked and then stopped working without any action from my side) that gives 403 error. Too bad as I have not found any working solution to my problem.

Anyway, this is most probably not Pipedrive’s fault

Thank you very much and have a nice day

Some random thoughts.

If you are using Cloudflare cache, create an exception in the Page Rules for the url.

It is possible for cloudflare to fail to forward query parameters (e.g. the api_token), check for changes in rewrite rules, or firewall settings. A 403 should if implemented correctly mean that the server understood the request but just failed to authenticate.

after executing the curl log the curl_error($ch) to see more info about the request (although it looks like just an authentication error)

Magnus, thank you very much for your assistance. I just wonder if I have to create a page rule for mycompany.com or mycompany.pipedrive.com or pipedrive.com - what you think? And also, what action should Cloudflare perform in this case - skip?

I think that I should choose mycompany.pipedrive.com and an action “Disabl Security” - what do you think?

Hi. No don’t do that.

I have to be honest and I kind of skimmed through your text before my last answer, sorry about that. I got the direction of the entire thing wrong and thought the trigger was a request from Pipedrive but I see that this is a local trigger and then a request to pipedrive to Cloudflare on YOUR end has nothing to do with this. Let’s think about this.

  1. Cloudflare seem to have banned your servers IP-address from reaching the API. They will give a 403 error to a banned ID,

What is wrong

Lets look at the 403 response you posted. I created a 403 response from the Pipedrive API and we see differences right away. The headers [report-to] is a give away that this is Cloudflare. Pipedrive also have content-type application/json not text/html plus lots of other differences. It is Cloudflare that blocked your server.

How can you test it.

Change the IP number of the server. Depending on your hosting you might need to ask them. It can happen that the hosts change the IP when rebooting the machines etc… Perhaps they transferred you workload to another machine.
Try to access the Pipedrive API from the server. You should get a 403 error.

What to do.

If my theory is correct. Check that the server is not infected and change IP

Possible causes

Sometimes you share IP with other hosting customers, where one customer does something stupid and get the IP banned. It might be that the server is rebooted and changes to an IP that is already banned.

It might also be that your server have a “virus”, that might or might not be unrelated to your website. Check for outgoing traffic that should not be there.

Pipedrive 403.

For reference the Pipedrive response body looked like this when I tried to delete a person as a regular user:

{
  "success": false,
  "error": "You do not have permissions to do this.",
  "error_info": "Please check developers.pipedrive.com for more information about Pipedrive API.",
  "data": null,
  "additional_data": null
}