To prove that Karate does the right thing, try this:
* url 'https://httpbin.org'
* path 'anything'
* def id = 123
* param $filter = "startswith(Name,'" + id + "')"
* request { foo: 'bar' }
* method post
And Karate will make this request:
1 > POST https://httpbin.org/anything?%24filter=startswith%28Name%2C%27123%27%29
1 > Content-Type: application/json; charset=UTF-8
1 > Content-Length: 13
1 > Host: httpbin.org
1 > Connection: Keep-Alive
1 > User-Agent: Apache-HttpClient/4.5.13 (Java/1.8.0_231)
1 > Accept-Encoding: gzip,deflate
{"foo":"bar"}
And you will get an actual response from the server:
10:13:38.445 [main] DEBUG com.intuit.karate - response time in milliseconds: 1243
1 < 200
1 < Date: Tue, 13 Apr 2021 04:43:38 GMT
1 < Content-Type: application/json
1 < Content-Length: 589
1 < Connection: keep-alive
1 < Server: gunicorn/19.9.0
1 < Access-Control-Allow-Origin: *
1 < Access-Control-Allow-Credentials: true
{"args":{"$filter":"startswith(Name,'123')"},"headers": ""}
So I leave it up to you to figure if you got the wrapping of quotes wrong or if your server is not able to handle encoded URL or path / params.