Data Encoding
When sending REST requests, special characters in parameters can disrupt the URL structure. This can lead to errors or incorrect data.
For example, if you need to create a lead with the name John&Martin via an incoming webhook, according to the documentation for the method crm.lead.add, the request URL should look like this:
https://b24-abcdef.bitrix24.com/rest/1/xxxxxxx/crm.lead.add?fields[TITLE]=John&Martin
After executing the request, you may find that the lead's name only contains John. This happened because the & character separates query parameters. If it appears within a value, the server interprets it as the start of a new parameter rather than part of the data.
As a result, the request has two parameters:
fields[TITLE]with the valueJohn- a new parameter
Martinwithout a value
To ensure the method works correctly, you need to replace the special character with its encoded equivalent. For &, this is %26. This transformation is known as URL encoding.
The correct URL for the task at hand is:
https://b24-abcdef.bitrix24.com/rest/1/xxxxxxx/crm.lead.add?fields[TITLE]=John%26Martin
Which Characters Need Encoding
In a URL, special characters such as &, ?, %, [, ], #, and others play a significant role. If they appear in a parameter value, they must be encoded. Otherwise, the server will interpret them as control characters, and the result of the request will become unpredictable.
How to Encode in Different Languages
Each programming language provides a built-in function:
- JavaScript —
encodeURIComponent - PHP —
urlencode - Python —
urllib.parse.quote_plus - Java —
URLEncoder.encode
If you are forming a request manually, you can use any online service by searching for "URL encoding online."
You can check the correctness of the request using the service https://webhook.site. It shows the complete request, including headers and parameters.
Double Encoding for Batch Requests
The batch method allows you to execute multiple requests in a single call. Requests are passed in the cmd parameter as strings: method?parameter1=value¶meter2=7. However, each of these strings becomes a parameter value itself. Therefore, it also needs to be encoded.
- First, encode the values inside the nested request.
- Then, encode the entire string of the nested request.
If you needed to create a lead from the example above as part of a batch request, the URL would look like this:
https://b24-abcdef.bitrix24.com/rest/1/xxxxxxx/batch?cmd[0]=crm.lead.add%3Ffields%5BTITLE%5D%3DJohn%2526Martin
Note: %26 has turned into %2526 because the % character itself was encoded as %25.
To avoid manual encoding and other complexities, use ready-made SDKs. They handle all the work with URLs, encoding, and error handling.
Official Bitrix24 SDKs:
- B24PhpSdk and CRest PHP SDK for PHP
- B24JsSDK for JavaScript
How to Pass Complex Structures
Many REST API methods accept nested data, such as a list of contact phone numbers or an array of fields. In such cases, it is recommended to send POST requests with the body in JSON format. This way, the structure is preserved, and you don't have to worry about encoding individual parameters.
Example of a lead with multiple phone numbers:
curl -X POST \
-H "Content-Type: application/json" \
-d '{
"fields": {
"TITLE": "My company",
"PHONE": [
{
"VALUE": "112233",
"VALUE_TYPE": "WORK"
},
{
"VALUE": "555888112",
"VALUE_TYPE": "OTHER"
}
]
}
}' \
https://***/rest/***/crm.lead.add
$data = [
"fields" => [
"TITLE" => "My company",
"PHONE" => [
[
"VALUE" => "112233",
"VALUE_TYPE" => "WORK"
],
[
"VALUE" => "555888112",
"VALUE_TYPE" => "OTHER"
]
]
]
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_USERAGENT, 'php script');
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_URL, 'https://***/rest/***/crm.lead.add');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
$raw = curl_exec($ch);
curl_close($ch);
data = {
fields: {
TITLE: 'My company',
PHONE: [
{
VALUE: '112233',
VALUE_TYPE: 'WORK'
},
{
VALUE: '555888112',
VALUE_TYPE: 'OTHER'
}
]
}
};
fetch('https://***/rest/***/crm.lead.add', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
import requests
data = {
'fields': {
'TITLE': 'My company',
'PHONE': [
{
'VALUE': '112233',
'VALUE_TYPE': 'WORK'
},
{
'VALUE': '555888112',
'VALUE_TYPE': 'OTHER'
}
]
}
}
r = requests.post('https://***/rest/***/crm.lead.add', json=data)
If sending JSON is not possible, use a GET request or a standard POST request. Data should be passed in the query parameters, following the encoding rules.
GET Request
The GET request for the example above:
https://***/rest/***/crm.lead.add.json?fields[TITLE]=My%20company&fields[PHONE][0][VALUE]=112233&fields[PHONE][0][VALUE_TYPE]=WORK&fields[PHONE][1][VALUE]=555888112&fields[PHONE][1][VALUE_TYPE]=OTHER
How to programmatically assemble such a string:
- PHP — the
http_build_queryfunction converts an array into a properly encoded string. - JavaScript — you can use the
qslibrary or write your own function.
POST Request
For a POST request, you need to specify the correct Content-Type header and format the request body.
application/x-www-form-urlencoded— data is converted into a single stringmultipart/form-data— data is split into parts, each with its own headers and separated by a boundary stringboundary=SomeBoundary
fields[TITLE]=My%20company&fields[PHONE][0][VALUE]=112233&fields[PHONE][0][VALUE_TYPE]=WORK&fields[PHONE][1][VALUE]=555888112&fields[PHONE][1][VALUE_TYPE]=OTHER
--SomeBoundary
Content-Disposition: form-data; name="fields[TITLE]"
My company
--SomeBoundary
Content-Disposition: form-data; name="fields[PHONE][0][VALUE]"
112233
--SomeBoundary
Content-Disposition: form-data; name="fields[PHONE][0][VALUE_TYPE]"
WORK
--SomeBoundary
Content-Disposition: form-data; name="fields[PHONE][1][VALUE]"
555888112
--SomeBoundary
Content-Disposition: form-data; name="fields[PHONE][1][VALUE_TYPE]"
OTHER
--SomeBoundary
Order of Parameters
Some methods, such as task.commentitem.add and task.checklistitem.complete, require strict adherence to the order of parameter transmission. In such cases, parameters cannot be passed by name — as an object in JavaScript or an associative array in PHP. Otherwise, the execution result will be unpredictable, or the method will return an error.
To pass such parameters, use an array with numeric indices. The indices should start from 0.
Example of incorrect comment addition to a task:
curl 'https://***/rest/***/task.commentitem.add?TASKID=123&FIELDS[POST_MESSAGE]=test'
CRest::call(
'task.commentitem.add',
[
'TASKID' => 123,
'FIELDS' => ['POST_MESSAGE' => 'text']
]
);
BX24.callMethod(
'task.commentitem.add',
{
TASKID: 123,
FIELDS: { 'POST_MESSAGE': 'text' }
}
);
Example of correct comment addition to a task:
curl 'https://***/rest/***/task.commentitem.add?0=123&1[POST_MESSAGE]=test'
CRest::call(
'task.commentitem.add',
[
123,
['POST_MESSAGE' => 'text']
]
);
BX24.callMethod(
'task.commentitem.add',
[
123,
{ 'POST_MESSAGE': 'text' }
]
);