diff --git a/pom.xml b/pom.xml
index 895127e0c3..9fb7ba43e4 100755
--- a/pom.xml
+++ b/pom.xml
@@ -128,6 +128,7 @@
         1.5.2
         5.8.2 
         2.6.0
+        5.13.1
         1.3.0 
         1.2.7 
         
@@ -1877,6 +1878,18 @@
                 ${zeroturnaround.version}
                 test
             
+            
+                org.mock-server
+                mockserver-netty
+                ${mock-server.version}
+                test
+            
+            
+                org.mock-server
+                mockserver-client-java
+                ${mock-server.version}
+                test
+            
             
                 org.opensmpp
                 opensmpp-core
diff --git a/rule-engine/rule-engine-components/pom.xml b/rule-engine/rule-engine-components/pom.xml
index 2606fc32d4..ebbfffc1b3 100644
--- a/rule-engine/rule-engine-components/pom.xml
+++ b/rule-engine/rule-engine-components/pom.xml
@@ -136,6 +136,15 @@
             awaitility
             test
         
+        
+            org.mock-server
+            mockserver-netty
+        
+        
+            org.mock-server
+            mockserver-client-java
+        
+
         
             org.cassandraunit
             cassandra-unit
diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java
index c2a6867f94..e035d415ed 100644
--- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java
+++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java
@@ -40,6 +40,7 @@ import org.springframework.util.concurrent.ListenableFuture;
 import org.springframework.util.concurrent.ListenableFutureCallback;
 import org.springframework.web.client.AsyncRestTemplate;
 import org.springframework.web.client.HttpClientErrorException;
+import org.springframework.web.util.UriComponentsBuilder;
 import org.thingsboard.rule.engine.api.TbContext;
 import org.thingsboard.rule.engine.api.TbNodeException;
 import org.thingsboard.rule.engine.api.TbRelationTypes;
@@ -54,6 +55,7 @@ import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLException;
 import java.net.Authenticator;
 import java.net.PasswordAuthentication;
+import java.net.URI;
 import java.nio.charset.StandardCharsets;
 import java.security.NoSuchAlgorithmException;
 import java.util.Deque;
@@ -189,8 +191,9 @@ public class TbHttpClient {
             entity = new HttpEntity<>(msg.getData(), headers);
         }
 
+        URI uri = buildEncodedUri(endpointUrl);
         ListenableFuture> future = httpClient.exchange(
-                endpointUrl, method, entity, String.class);
+                uri, method, entity, String.class);
         future.addCallback(new ListenableFutureCallback>() {
             @Override
             public void onFailure(Throwable throwable) {
@@ -214,6 +217,28 @@ public class TbHttpClient {
         }
     }
 
+    public URI buildEncodedUri(String endpointUrl) {
+        if (endpointUrl == null) {
+            throw new RuntimeException("Url string cannot be null!");
+        }
+        if (endpointUrl.isEmpty()) {
+            throw new RuntimeException("Url string cannot be empty!");
+        }
+
+        URI uri = UriComponentsBuilder.fromUriString(endpointUrl).build().encode().toUri();
+        if (uri.getScheme() == null || uri.getScheme().isEmpty()) {
+            throw new RuntimeException("Transport scheme(protocol) must be provided!");
+        }
+
+        boolean authorityNotValid = uri.getAuthority() == null || uri.getAuthority().isEmpty();
+        boolean hostNotValid = uri.getHost() == null || uri.getHost().isEmpty();
+        if (authorityNotValid || hostNotValid) {
+            throw new RuntimeException("Url string is invalid!");
+        }
+
+        return uri;
+    }
+
     private TbMsg processResponse(TbContext ctx, TbMsg origMsg, ResponseEntity response) {
         TbMsgMetaData metaData = origMsg.getMetaData();
         metaData.putValue(STATUS, response.getStatusCode().name());
diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbHttpClientTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbHttpClientTest.java
index 9834ef631d..f5c6977dd5 100644
--- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbHttpClientTest.java
+++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbHttpClientTest.java
@@ -18,16 +18,38 @@ package org.thingsboard.rule.engine.rest;
 
 import io.netty.channel.EventLoopGroup;
 import io.netty.channel.nio.NioEventLoopGroup;
+import org.awaitility.Awaitility;
 import org.junit.After;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+import org.mockserver.integration.ClientAndServer;
+import org.springframework.web.client.AsyncRestTemplate;
+import org.thingsboard.rule.engine.api.TbContext;
+import org.thingsboard.server.common.data.id.DeviceId;
+import org.thingsboard.server.common.data.id.EntityId;
+import org.thingsboard.server.common.msg.TbMsg;
+import org.thingsboard.server.common.msg.TbMsgMetaData;
 
+import java.net.URI;
+import java.util.concurrent.TimeUnit;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.instanceOf;
 import static org.hamcrest.Matchers.is;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.BDDMockito.willCallRealMethod;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockserver.integration.ClientAndServer.startClientAndServer;
+import static org.mockserver.model.HttpRequest.request;
+import static org.mockserver.model.HttpResponse.response;
 
 public class TbHttpClientTest {
 
@@ -58,4 +80,128 @@ public class TbHttpClientTest {
         eventLoop = client.getSharedOrCreateEventLoopGroup(null);
         assertThat(eventLoop, instanceOf(NioEventLoopGroup.class));
     }
+
+    @Test
+    public void testBuildSimpleUri() {
+        Mockito.when(client.buildEncodedUri(any())).thenCallRealMethod();
+        String url = "http://localhost:8080/";
+        URI uri = client.buildEncodedUri(url);
+        Assert.assertEquals(url, uri.toString());
+    }
+
+    @Test
+    public void testBuildUriWithoutProtocol() {
+        Mockito.when(client.buildEncodedUri(any())).thenCallRealMethod();
+        String url = "localhost:8080/";
+        assertThatThrownBy(() -> client.buildEncodedUri(url));
+    }
+
+    @Test
+    public void testBuildInvalidUri() {
+        Mockito.when(client.buildEncodedUri(any())).thenCallRealMethod();
+        String url = "aaa";
+        assertThatThrownBy(() -> client.buildEncodedUri(url));
+    }
+
+    @Test
+    public void testBuildUriWithSpecialSymbols() {
+        Mockito.when(client.buildEncodedUri(any())).thenCallRealMethod();
+        String url = "http://192.168.1.1/data?d={\"a\": 12}";
+        String expected = "http://192.168.1.1/data?d=%7B%22a%22:%2012%7D";
+        URI uri = client.buildEncodedUri(url);
+        Assert.assertEquals(expected, uri.toString());
+    }
+
+    @Test
+    public void testProcessMessageWithJsonInUrlVariable() throws Exception {
+        String host = "localhost";
+        String path = "/api";
+        String paramKey = "data";
+        String paramVal = "[{\"test\":\"test\"}]";
+        String successResponseBody = "SUCCESS";
+
+        var server = setUpDummyServer(host, path, paramKey, paramVal, successResponseBody);
+
+        String endpointUrl = String.format(
+                "http://%s:%d%s?%s=%s",
+                host, server.getPort(), path, paramKey, paramVal
+        );
+        String method = "GET";
+
+
+        var config = new TbRestApiCallNodeConfiguration()
+                .defaultConfiguration();
+        config.setRequestMethod(method);
+        config.setRestEndpointUrlPattern(endpointUrl);
+        config.setUseSimpleClientHttpFactory(true);
+
+        var asyncRestTemplate = new AsyncRestTemplate();
+
+        var httpClient = new TbHttpClient(config, eventLoop);
+        httpClient.setHttpClient(asyncRestTemplate);
+
+        var msg = TbMsg.newMsg(
+                "Main", "GET", new DeviceId(EntityId.NULL_UUID),
+                TbMsgMetaData.EMPTY, "{}"
+        );
+        var successMsg = TbMsg.newMsg(
+                "SUCCESS", msg.getOriginator(),
+                msg.getMetaData(), msg.getData()
+        );
+
+        var ctx = mock(TbContext.class);
+        when(ctx.transformMsg(
+                eq(msg), eq(msg.getType()),
+                eq(msg.getOriginator()),
+                eq(msg.getMetaData()),
+                eq(msg.getData())
+        )).thenReturn(successMsg);
+
+        var capturedData = ArgumentCaptor.forClass(String.class);
+
+        when(ctx.transformMsg(
+                eq(msg), eq(msg.getType()),
+                eq(msg.getOriginator()),
+                any(),
+                capturedData.capture()
+        )).thenReturn(successMsg);
+
+        httpClient.processMessage(ctx, msg);
+
+        Awaitility.await()
+                .atMost(30, TimeUnit.SECONDS)
+                .until(() -> {
+                    try {
+                        verify(ctx, times(1)).tellSuccess(any());
+                        return true;
+                    } catch (Exception e) {
+                        return false;
+                    }
+                });
+
+        verify(ctx, times(1)).tellSuccess(any());
+        verify(ctx, times(0)).tellFailure(any(), any());
+        Assert.assertEquals(successResponseBody, capturedData.getValue());
+    }
+
+    private ClientAndServer setUpDummyServer(String host, String path, String paramKey, String paramVal, String successResponseBody) {
+        var server = startClientAndServer(host, 1080);
+        createGetMethodExpectations(server, path, paramKey, paramVal, successResponseBody);
+        return server;
+    }
+
+    private void createGetMethodExpectations(ClientAndServer server, String path, String paramKey, String paramVal, String successResponseBody) {
+        server.when(
+                request()
+                        .withMethod("GET")
+                        .withPath(path)
+                        .withQueryStringParameter(paramKey, paramVal)
+        ).respond(
+                response()
+                        .withStatusCode(200)
+                        .withBody(successResponseBody)
+        );
+    }
+
+
 }
\ No newline at end of file