Setting Up a Delivery Service for CRM
Scope:
saleWho can execute methods: administrator
If you are developing integrations for Bitrix24 using AI tools (Codex, Claude Code, Cursor), connect to the MCP server so that the assistant can utilize the official REST documentation.
You can connect external delivery services to Bitrix24. This allows managers to work with the delivery service within CRM cards: calculating costs and tracking status.
To set up the delivery service, we will sequentially execute the following methods:
-
sale.delivery.handler.add — register the delivery handler,
-
sale.delivery.add — create the parent service and profiles linked to the handler,
-
sale.shipmentproperty.add — add shipment properties for addresses,
-
sale.propertyrelation.add — link properties to delivery profiles.
-
sale.delivery.extra.service.add — connect additional services.
1. Create a Delivery Handler
We will register the handler using sale.delivery.handler.add. We will pass four parameters to the method.
-
CODE— the symbolic code of the delivery handler. For example, we will specifyuber. -
NAME— the name of the delivery handler. We will passUber. -
SETTINGS— an object containing information about the handler's settings.-
CALCULATE_URL— the URL for calculating delivery costs, for example,https://gateway.bx/calculate.php. -
CREATE_DELIVERY_REQUEST_URL— the URL for creating a delivery request. We will specifyhttps://gateway.bx/create_delivery_request.php. -
CANCEL_DELIVERY_REQUEST_URL— the URL for canceling a delivery, for example,https://gateway.bx/cancel_delivery_request.php. -
HAS_CALLBACK_TRACKING_SUPPORT— an indicator of whether the service will send notifications. We will set it toY. Notifications can be created using sale.delivery.request.sendmessage. -
CONFIG— a list of settings. We will specifyMY_FIRST_SETTINGandMY_SECOND_SETTINGwith the typeSTRING.
-
-
PROFILES— an array of delivery profiles. The handler must have at least one profile. We will setTaxiandCargo.
The delivery service at the specified URLs must accept the request, process it, and return a response in the format expected by the CRM.
For more details on the request and response formats, refer to the section Webhooks for Delivery Operations.
How to Use Examples in Documentation
BX24.callMethod(
'sale.delivery.handler.add',
{
CODE: "uber",
NAME: "Uber",
SETTINGS: {
CALCULATE_URL: "https://gateway.bx/calculate.php",
CREATE_DELIVERY_REQUEST_URL: "https://gateway.bx/create_delivery_request.php",
CANCEL_DELIVERY_REQUEST_URL: "https://gateway.bx/cancel_delivery_request.php",
HAS_CALLBACK_TRACKING_SUPPORT: "Y",
CONFIG: [
{
TYPE: "STRING",
CODE: "MY_FIRST_SETTING",
NAME: "My first setting",
},
{
TYPE: "STRING",
CODE: "MY_SECOND_SETTING",
NAME: "My second setting",
},
],
},
PROFILES: [
{
NAME: "Taxi",
CODE: "TAXI",
DESCRIPTION: "Taxi Delivery",
},
{
NAME: "Cargo",
CODE: "CARGO",
DESCRIPTION: "Cargo Delivery",
},
],
},
function(result) {
if (result.error()) {
console.error(result.error());
} else {
console.info(result.data());
}
}
);
require_once('crest.php');
$result = CRest::call(
'sale.delivery.handler.add',
[
'CODE' => 'uber',
'NAME' => 'Uber',
'SETTINGS' => [
'CALCULATE_URL' => 'https://gateway.bx/calculate.php',
'CREATE_DELIVERY_REQUEST_URL' => 'https://gateway.bx/create_delivery_request.php',
'CANCEL_DELIVERY_REQUEST_URL' => 'https://gateway.bx/cancel_delivery_request.php',
'HAS_CALLBACK_TRACKING_SUPPORT' => 'Y',
'CONFIG' => [
[
'TYPE' => 'STRING',
'CODE' => 'MY_FIRST_SETTING',
'NAME' => 'My first setting',
],
[
'TYPE' => 'STRING',
'CODE' => 'MY_SECOND_SETTING',
'NAME' => 'My second setting',
},
],
},
'PROFILES' => [
[
'NAME' => 'Taxi',
'CODE' => 'TAXI',
'DESCRIPTION' => 'Taxi Delivery',
],
[
'NAME' => 'Cargo',
'CODE' => 'CARGO',
'DESCRIPTION' => 'Cargo Delivery',
],
],
]
);
echo '<PRE>';
print_r($result);
echo '</PRE>';
from b24pysdk import BitrixWebhook, Client
from b24pysdk.errors import BitrixAPIError
client = Client(
BitrixWebhook(
domain="your-domain.bitrix24.com",
auth_token="your-webhook-token",
)
)
try:
response = client.sale.delivery.handler.add(
code="uber",
name="Uber",
settings={
"CALCULATE_URL": "https://gateway.bx/calculate.php",
"CREATE_DELIVERY_REQUEST_URL": "https://gateway.bx/create_delivery_request.php",
"CANCEL_DELIVERY_REQUEST_URL": "https://gateway.bx/cancel_delivery_request.php",
"HAS_CALLBACK_TRACKING_SUPPORT": "Y",
"CONFIG": [
{
"TYPE": "STRING",
"CODE": "MY_FIRST_SETTING",
"NAME": "My first setting",
},
{
"TYPE": "STRING",
"CODE": "MY_SECOND_SETTING",
"NAME": "My second setting",
},
],
},
profiles=[
{
"NAME": "Taxi",
"CODE": "TAXI",
"DESCRIPTION": "Taxi Delivery",
},
{
"NAME": "Cargo",
"CODE": "CARGO",
"DESCRIPTION": "Cargo Delivery",
},
],
).response
print(response.result)
except BitrixAPIError as error:
print(error)
If the handler is successfully added, the method will return its identifier. If you receive an error, refer to the documentation for possible errors in the method sale.delivery.handler.add.
{
"result": 23,
"time": {
"start": 1714736790.260814,
"finish": 1714736791.896773,
"duration": 1.6359591484069824,
"processing": 0.03880000114440918,
"date_start": "2024-05-03T14:46:30+03:00",
"date_finish": "2024-05-03T14:46:31+03:00"
}
}
2. Create a Delivery Service
We will create a delivery service using the method sale.delivery.add. We will pass the following parameters to the method:
-
REST_CODE— the symbolic code of the delivery handler. We will specifyuber, which we set in the first step. -
NAME— the name of the delivery service, for example,Uber Taxi. -
CURRENCY— the symbolic code of the currency. We will passUSD. You can get a list of currencies using the method crm.currency.list. -
ACTIVE— the flag indicating whether the delivery service is active. We will set it toY. -
CONFIG— the values of the handler's settings. We will pass the values forMY_FIRST_SETTINGandMY_SECOND_SETTINGthat we set in the first step.
BX24.callMethod(
'sale.delivery.add',
{
REST_CODE: "uber",
NAME: "Uber Taxi",
CURRENCY: "USD",
ACTIVE: "Y",
CONFIG: [
{
CODE: "MY_FIRST_SETTING",
VALUE: "My first setting value",
},
{
CODE: "MY_SECOND_SETTING",
VALUE: "My second setting value",
},
]
},
function(result) {
if (result.error()) {
console.error(result.error());
} else {
console.info(result.data());
}
}
);
require_once('crest.php');
$result = CRest::call(
'sale.delivery.add',
[
'REST_CODE' => 'uber',
'NAME' => 'Uber Taxi',
'CURRENCY' => 'USD',
'ACTIVE' => 'Y',
'CONFIG' => [
[
'CODE' => 'MY_FIRST_SETTING',
'VALUE' => 'My first setting value',
},
[
'CODE' => 'MY_SECOND_SETTING',
'VALUE' => 'My second setting value',
},
]
]
);
echo '<PRE>';
print_r($result);
echo '</PRE>';
try:
response = client.sale.delivery.add(
rest_code="uber",
name="Uber Taxi",
currency="USD",
active=True,
config=[
{
"CODE": "MY_FIRST_SETTING",
"VALUE": "My first setting value",
},
{
"CODE": "MY_SECOND_SETTING",
"VALUE": "My second setting value",
},
],
).response
print(response.result)
except BitrixAPIError as error:
print(error)
If the delivery service is successfully created, the method will return the parent service object and an array of profiles. If you receive an error, refer to the documentation for possible errors in the method sale.delivery.add.
{
"result": {
"parent": {
"NAME": "Uber Taxi",
"ACTIVE": "Y",
"DESCRIPTION": "",
"CURRENCY": "USD",
"ID": 226,
"PARENT_ID": null,
"SORT": 100,
"LOGOTYPE": null
},
"profiles": [
{
"NAME": "Taxi",
"ACTIVE": "Y",
"DESCRIPTION": "Taxi Delivery",
"CURRENCY": "USD",
"ID": 227,
"PARENT_ID": 226,
"SORT": 100,
"LOGOTYPE": null
},
{
"NAME": "Cargo",
"ACTIVE": "Y",
"DESCRIPTION": "Cargo Delivery",
"CURRENCY": "USD",
"ID": 228,
"PARENT_ID": 226,
"SORT": 100,
"LOGOTYPE": null
}
]
},
"time": {
"start": 1714737122.600765,
"finish": 1714737122.894801,
"duration": 0.2940359115600586,
"processing": 0.0942530632019043,
"date_start": "2024-05-03T14:52:02+03:00",
"date_finish": "2024-05-03T14:52:02+03:00"
}
}
3. Create Shipment Properties
In the shipment, the manager specifies the shipping address and the delivery address. We will sequentially create two properties, Address From and Address To, using the method sale.shipmentproperty.add.
Property Address From
We will pass an object fields with the values for the Address From property.
-
personTypeId— the identifier of the payer type. We will pass3. You can get a list of types using the method sale.persontype.list. -
propsGroupId— the identifier of the property group. We will specify6. You can get a list of groups using the method sale.propertygroup.list. -
name— the name of the shipment property. We will specifyAddress From. -
active— the active flag. We will passY. -
sort— sorting. -
type— the type of the shipment property. We will passADDRESS. You can find a list of possible values in the documentation for the method sale.shipmentproperty.add. -
required— the flag indicating whether the property is required. We will set it toY. -
isAddressFrom— the flag indicating whether the shipment property is used as the sender's address. We will passY.
BX24.callMethod(
'sale.shipmentproperty.add', {
fields: {
personTypeId: 3,
propsGroupId: 6,
name: "Address From",
active: "Y",
sort: "100",
type: "ADDRESS",
required: "Y",
isAddressFrom: "Y"
}
},
function(result) {
if (result.error()) {
console.error(result.error());
} else {
console.info(result.data());
}
}
);
require_once('crest.php');
$result = CRest::call(
'sale.shipmentproperty.add',
[
'fields' => [
'personTypeId' => 3,
'propsGroupId' => 6,
'name' => 'Address From',
'active' => 'Y',
'sort' => '100',
'type' => 'ADDRESS',
'required' => 'Y',
'isAddressFrom' => 'Y'
]
]
);
echo '<PRE>';
print_r($result);
echo '</PRE>';
try:
response = client.sale.shipmentproperty.add(
fields={
"personTypeId": 3,
"propsGroupId": 6,
"name": "Address From",
"active": "Y",
"sort": "100",
"type": "ADDRESS",
"required": "Y",
"isAddressFrom": "Y",
},
).response
print(response.result)
except BitrixAPIError as error:
print(error)
If the property is successfully added, the method will return a property object with the property identifier. If you receive an error, refer to the documentation for possible errors in the method sale.shipmentproperty.add.
{
"result": {
"property": {
"active": "Y",
"code": "",
"defaultValue": "",
"description": "",
"id": 102,
"isAddressFrom": "Y",
"isAddressTo": "N",
"maxLength": "",
"name": "Address From",
"personTypeId": 3,
"propsGroupId": 6,
"required": "Y",
"settings": [],
"sort": 100,
"type": "ADDRESS",
"xmlId": ""
}
},
"time": {
"start": 1714741422.531968,
"finish": 1714741422.644666,
"duration": 0.11269783973693848,
"processing": 0.06191205978393555,
"date_start": "2024-05-03T15:43:42+03:00",
"date_finish": "2024-05-03T15:43:42+03:00"
}
}
Property Address To
In the fields object for the Address To property, we will pass the name Address To. The other parameters will be similar to those for Address From.
BX24.callMethod(
'sale.shipmentproperty.add', {
fields: {
personTypeId: 3,
propsGroupId: 6,
name: "Address To",
active: "Y",
sort: "100",
type: "ADDRESS",
required: "Y",
isAddressTo: "Y"
}
},
function(result) {
if (result.error()) {
console.error(result.error());
} else {
console.info(result.data());
}
}
);
require_once('crest.php');
$result = CRest::call(
'sale.shipmentproperty.add',
[
'fields' => [
'personTypeId' => 3,
'propsGroupId' => 6,
'name' => 'Address To',
'active' => 'Y',
'sort' => '100',
'type' => 'ADDRESS',
'required' => 'Y',
'isAddressTo' => 'Y'
]
]
);
echo '<PRE>';
print_r($result);
echo '</PRE>';
try:
response = client.sale.shipmentproperty.add(
fields={
"personTypeId": 3,
"propsGroupId": 6,
"name": "Address To",
"active": "Y",
"sort": "100",
"type": "ADDRESS",
"required": "Y",
"isAddressTo": "Y",
},
).response
print(response.result)
except BitrixAPIError as error:
print(error)
If the property is successfully added, the method will return a property object with the property identifier. If you receive an error, refer to the documentation for possible errors in the method sale.shipmentproperty.add.
{
"result": {
"property": {
"active": "Y",
"code": "",
"defaultValue": "",
"description": "",
"id": 103,
"isAddressFrom": "N",
"isAddressTo": "Y",
"maxLength": "",
"name": "Address To",
"personTypeId": 3,
"propsGroupId": 6,
"required": "Y",
"settings": [],
"sort": 100,
"type": "ADDRESS",
"xmlId": ""
}
},
"time": {
"start": 1714741719.195657,
"finish": 1714741719.368018,
"duration": 0.17236113548278809,
"processing": 0.0712430477142334,
"date_start": "2024-05-03T15:48:39+03:00",
"date_finish": "2024-05-03T15:48:39+03:00"
}
}
4. Link Shipment Properties to the Delivery Service
To link the properties Address From and Address To to the profiles Taxi and Cargo, we will call the method sale.propertyrelation.add four times. We will pass an object fields with the values for linking the properties.
-
entityId— the identifier of the delivery profile. For theTaxiprofile, we will pass227, and forCargo, we will pass228, which were obtained in the second step. -
entityType— the type of object. Possible values:P— payment system,D— delivery,L— landing,T— trading platform. We will specify the valueD. -
propertyId— the identifier of the property. ForAddress From, we will specify102, and forAddress To, we will specify103, which were obtained in the third step.
BX24.callMethod(
'sale.propertyrelation.add',
{
fields: {
entityId: 227,
entityType: 'D',
propertyId: 102
}
},
function(result) {
if (result.error()) {
console.error(result.error());
} else {
console.info(result.data());
}
}
);
require_once('crest.php');
$result = CRest::call(
'sale.propertyrelation.add',
[
'fields' => [
'entityId' => 227,
'entityType' => 'D',
'propertyId' => 102
]
]
);
try:
response = client.sale.propertyrelation.add(
fields={
"entityId": 227,
"entityType": "D",
"propertyId": 102,
},
).response
print(response.result)
except BitrixAPIError as error:
print(error)
We will call the method sale.propertyrelation.add in sequence.
-
For the
Taxiservice, propertyAddress From— passentityId: 227, propertyId: 102. -
For the
Taxiservice, propertyAddress To— passentityId: 227, propertyId: 103. -
For the
Cargoservice, propertyAddress From— passentityId: 228, propertyId: 102. -
For the
Cargoservice, propertyAddress To— passentityId: 228, propertyId: 103.
If the bindings are successfully added, the method will return objects with information about them. If you receive an error, refer to the documentation for possible errors in the method sale.propertyrelation.add.
{
"result": {
"propertyRelation": {
"entityId": 227,
"entityType": "D",
"propertyId": 102
}
},
"time": {
"start": 1712244475.495277,
"finish": 1712244476.402808,
"duration": 0.9075310230255127,
"processing": 0.08538603782653809,
"date_start": "2024-05-03T18:27:55+03:00",
"date_finish": "2024-05-03T18:27:56+03:00"
}
}
5. Add Services to Delivery Services
To add an additional service to the delivery service, we will call the method sale.delivery.extra.service.add. We will pass the following parameters:
-
DELIVERY_ID— the identifier of the delivery service to which the service will be linked. For theTaxiprofile, we will specify the identifier227, which was obtained in the second step. For other profiles, substitute your own identifier. You can get a list of delivery service identifiers using the method sale.delivery.getlist. -
ACTIVE— the flag indicating whether the service is active. Possible values:Y— yes,N— no. We will passY. -
CODE— the symbolic code of the service. We will specifydoor_delivery. -
NAME— the name of the service, for example,Door Delivery. -
TYPE— the type of service. Possible values:enum— list,checkbox— single service,quantity— quantitative service. We will specifycheckbox. -
PRICE— the cost of the service type in the currency of the delivery service. We will specify1000.For services of type
enum, the cost is specified using theITEMSparameter. For more details, refer to the documentation for the method sale.delivery.extra.service.add.
BX24.callMethod(
'sale.delivery.extra.service.add', {
DELIVERY_ID: 227,
ACTIVE: "Y",
CODE: "door_delivery",
NAME: "Door Delivery",
TYPE: "checkbox",
PRICE: 1000
},
function(result) {
if (result.error()) {
console.error(result.error());
} else {
console.info(result.data());
}
}
);
require_once('crest.php');
$result = CRest::call(
'sale.delivery.extra.service.add',
[
'DELIVERY_ID' => 227,
'ACTIVE' => 'Y',
'CODE' => 'door_delivery',
'NAME' => 'Door Delivery',
'TYPE' => 'checkbox',
'PRICE' => 1000,
]
);
echo '<PRE>';
print_r($result);
echo '</PRE>';
try:
response = client.sale.delivery.extra.service.add(
delivery_id=227,
type="checkbox",
name="Door Delivery",
active=True,
code="door_delivery",
price=1000,
).response
print(response.result)
except BitrixAPIError as error:
print(error)
If the service is added, the method will return the identifier in the result parameter. If you receive an error, refer to the documentation for possible errors in the method sale.delivery.extra.service.add.
{
"result": 140,
"time": {
"start": 1714739042.228152,
"finish": 1714739042.50093,
"duration": 0.2727780342102051,
"processing": 0.09131193161010742,
"date_start": "2024-05-03T15:24:02+03:00",
"date_finish": "2024-05-03T15:24:02+03:00"
}
}
Notifications about Delivery Statuses
To send notifications about the progress of delivery, you can use the methods from the group sale.delivery.request.*.
| Method | Description |
|---|---|
| sale.delivery.request.update | Updates the delivery order object: status and set of its properties |
| sale.delivery.request.sendmessage | Sends a message to the manager or recipient about the current status of the delivery order |
| sale.delivery.request.delete | Notifies about the cancellation of the delivery order on the external system side and attempts to cancel the delivery order on the Bitrix24 side |