WayForPay Webhook JSON not parsing correctly — nested JSON string issue

Hi everyone,

I’m integrating WayForPay (a payment provider) with Make, and I’m running into a problem with how their webhook sends data.

When the webhook fires, Make receives the payload as a single JSON structure — but inside it, there’s a field (products or customFields) that contains another JSON string, not an actual object.

Here’s what it looks like in the webhook output:

{
  "merchantAccount": "example_com",
  "orderReference": "WFP-123456789",
  "email": "client@example.com",
  "products": "[{\"name\":\"\\u0406\\u043c'\\u044f\",\"value\":\"\\u0418\\u0432\\u0430\\u043d\"},{\"name\":\"\\u0415\\u043b\\u0435\\u043a\\u0442\\u0440\\u043e\\u043d\\u043d\\u0430 \\u043f\\u043e\\u0448\\u0442\\u0430\",\"value\":\"test@example.com\"}]"
}

As you can see, the products value is a string that contains escaped JSON inside it.

When I try to parse it with Parse JSON, the output looks like this:

{"{\"name\":\"\\u0406\\u043c'\\u044f\",\"value\":\"\\u0418\\u0432\\u0430\\u043d\"}":""}

So it doesn’t break into separate fields — it stays as one big string with escaped symbols (\u0418, \u0432, etc.).


What I tried

  • Adding a second “Parse JSON” module after the first one and feeding it the products field → didn’t help.

  • Manually creating a data structure → also fails, Make shows empty fields or repeats the same encoded string.


Question

How can I properly decode and parse this nested JSON string from WayForPay so I can access fields like name and value individually inside Make?

Is there a recommended approach (Text parser, double Parse JSON, or a function module workaround) for this kind of nested JSON problem?


Thank you in advance :folded_hands:

Hey there,

when I tested with the data you provided a double Parse JSON modules worked.

The second one seems to be getting the values properly.

Please tell me what settings you have in these modules.

None what so ever. I just copied your string in the first module and mapped it in the second. Here is a blueprint:

Integration JSON.blueprint.json (3.5 KB)

My data is transferred in one piece and I do not display any additional fields.

And when you run the module with this data mapped inside what do you get as an output bundle from it?

:puzzle_piece: Solution for Make.com users facing WayForPay RAW data issue

If you’re working with WayForPay → Make.com integration and your webhook receives unparsed RAW data, this post will help you.
WayForPay sends transaction notifications as a RAW encrypted string, which cannot be parsed using Make’s JSON tools (like Parse JSON).

Below is a working external PHP solution to handle this problem safely and efficiently.

:white_check_mark: Solution: Parsing RAW WayForPay data outside Make.com

Problem

The payment system WayForPay sends transaction data in an encrypted RAW format, which cannot be directly parsed in Make.com (there is no built-in decryption/decoder module).

Solution

Create a small PHP script on your own server to:

  1. Receive RAW data from WayForPay
  2. Decode and parse it into JSON
  3. Forward the clean, structured JSON to your Make webhook

:laptop: Universal PHP Script

Save this code as wayforpay-handler.php on your hosting:

<?php
// === ERROR & LOG SETTINGS ===
ini_set('display_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', __DIR__ . '/wayforpay_php_errors.log');
header('Content-Type: application/json; charset=UTF-8');

// 🔑 YOUR WAYFORPAY SECRET KEY
$merchantSecret = 'YOUR_SECRET_KEY_HERE';

// === READ RAW DATA ===
$raw = file_get_contents('php://input');
file_put_contents(__DIR__ . '/wayforpay_log.txt', date('c') . " RAW: $raw\n", FILE_APPEND);

$data = json_decode($raw, true);
if (json_last_error() !== JSON_ERROR_NONE) {
    file_put_contents(__DIR__ . '/wayforpay_log.txt', date('c') . " JSON ERROR\n", FILE_APPEND);
    http_response_code(400);
    echo json_encode(['status' => 'error']);
    exit;
}

// === EXTRACT CLIENT NAME ===
$clientName = $data['clientName'] ?? null;

if ($clientName === 'NoCLIENT NAME' || empty($clientName)) {
    $clientName = null;
}

if (!$clientName && !empty($data['clientFields'])) {
    foreach ($data['clientFields'] as $field) {
        if (!empty($field['name']) && !empty($field['value'])) {
            $fieldName = mb_strtolower($field['name'], 'UTF-8');
            if (strpos($fieldName, 'ім') !== false || strpos($fieldName, 'им') !== false || strpos($fieldName, 'name') !== false) {
                $clientName = $field['value'];
                break;
            }
        }
    }
}

if (!$clientName) {
    $firstName = $data['clientFirstName'] ?? '';
    $lastName = $data['clientLastName'] ?? '';
    $clientName = trim("$firstName $lastName");
}

$clientName = $clientName ?: 'Client';
$data['clientName'] = $clientName;

// === ROUTE BY PRODUCT ===
$webhooks = [
    'product_1' => 'https://hook.eu2.make.com/YOUR_WEBHOOK_ID_1',
    'product_2' => 'https://hook.eu2.make.com/YOUR_WEBHOOK_ID_2',
];

$productName = trim($data['products'][0]['name'] ?? '');
$productLower = mb_strtolower($productName, 'UTF-8');
$hook_url = '';

$productMapping = [
    'product_1_name_lowercase' => $webhooks['product_1'],
    'product_2_name_lowercase' => $webhooks['product_2'],
];

foreach ($productMapping as $pattern => $url) {
    if (strpos($productLower, $pattern) !== false) {
        $hook_url = $url;
        break;
    }
}

if (!$hook_url) {
    file_put_contents(__DIR__ . '/wayforpay_log.txt', date('c') . " ⚠️ UNKNOWN PRODUCT: '$productName'\n", FILE_APPEND);
}

// === SEND RESPONSE TO WAYFORPAY ===
$orderReference = $data['orderReference'] ?? '';
$status = 'accept';
$time = time();

$signString = implode(';', [$orderReference, $status, $time]);
$signature = hash_hmac('md5', $signString, $merchantSecret);

$wayforpayResponse = [
    'orderReference' => $orderReference,
    'status' => $status,
    'time' => $time,
    'signature' => $signature
];

http_response_code(200);
echo json_encode($wayforpayResponse);
flush();

if (function_exists('fastcgi_finish_request')) {
    fastcgi_finish_request();
}

// === SEND TO MAKE.COM ===
if ($hook_url) {
    $ch = curl_init($hook_url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 10);
    curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json; charset=UTF-8']);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_UNICODE));
    
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    file_put_contents(__DIR__ . '/wayforpay_log.txt', date('c') . " SENT TO MAKE: $hook_url | PRODUCT: $productName | CLIENT: $clientName | HTTP $httpCode\n", FILE_APPEND);
}
?>

:gear: Setup Steps

  1. On your server
  • Upload the PHP script to your hosting
  • Replace YOUR_SECRET_KEY_HERE with your WayForPay secret key
  • Add your Make webhook URLs
  • Set up product routing in $productMapping
  1. In WayForPay Merchant Account
  • Go to merchant settings
  • Set serviceUrl to your script URL (e.g., https://yourdomain.com/wayforpay-handler.php)
  1. In Make.com
  • Create a Webhook module to receive incoming data
  • You’ll now get clean, structured JSON ready for further automation

:green_square: Benefits

:white_check_mark: Correct WayForPay acknowledgment → no duplicate notifications
:white_check_mark: Parsed and ready-to-use JSON in Make
:white_check_mark: Full Unicode support (Ukrainian, Cyrillic, etc.)
:white_check_mark: Auto client name detection
:white_check_mark: Multi-product routing
:white_check_mark: Detailed logging for debugging

:receipt: Logging

Example from wayforpay_log.txt:

2025-10-14T01:10:57+03:00 RAW: {...}
2025-10-14T01:10:57+03:00 SENT TO MAKE: https://hook... | PRODUCT: ... | CLIENT: ... | HTTP 200

:speech_balloon: Questions?

If you face any issues, check wayforpay_log.txt or wayforpay_php_errors.log for details.