Bulk операции
Bulk-операции позволяют обрабатывать до 100 объявлений за один запрос. Используйте их для первичной синхронизации и массовых обновлений.
Зачем использовать bulk
| Подход | Запросов на 100 объявлений |
|---|---|
| Отдельные запросы | 100 |
| Bulk-операция | 1 |
Bulk снижает накладные расходы на сеть и ускоряет синхронизацию.
Типы операций
Каждая операция должна содержать поле op, определяющее тип действия:
| Операция | Описание |
|---|---|
upsert | Создать или обновить объявление |
link | Привязать external ID к существующему объявлению |
unlink | Отвязать external ID |
delete | Удалить объявление |
validate | Проверить данные без сохранения |
Создайте или обновите объявления
Операция upsert создаёт новое объявление или обновляет существующее по externalId.
const response = await fetch('https://crm.rentix.md/api/v1/listings/bulk', {
method: 'POST',
headers: {
'Authorization': 'ApiKey YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
operations: [
{
op: 'upsert',
externalId: 'apt-001',
announcementType: 'rent',
propertyType: 'residential',
propertySecondaryType: 'apartment',
announcementValue: 500,
announcementCurrency: 'EUR',
announcementDescription: 'Уютная квартира в центре...',
files: [
{ url: 'https://example.com/photo1.jpg', externalFileId: 'apt-001-photo-1' },
{ url: 'https://example.com/photo2.jpg', externalFileId: 'apt-001-photo-2' },
{ url: 'https://example.com/photo3.jpg', externalFileId: 'apt-001-photo-3' }
],
announcementStatus: 'active'
},
{
op: 'upsert',
externalId: 'apt-002',
announcementType: 'rent',
propertyType: 'residential',
propertySecondaryType: 'apartment',
announcementValue: 700,
announcementCurrency: 'EUR',
announcementDescription: 'Просторная квартира с балконом...',
files: [
{ url: 'https://example.com/photo4.jpg', externalFileId: 'apt-002-photo-1' },
{ url: 'https://example.com/photo5.jpg', externalFileId: 'apt-002-photo-2' },
{ url: 'https://example.com/photo6.jpg', externalFileId: 'apt-002-photo-3' }
],
announcementStatus: 'active'
}
]
})
});
const result = await response.json();
console.log(`Успешно: ${result.summary.succeeded}/${result.summary.total}`);
curl -X POST https://crm.rentix.md/api/v1/listings/bulk \
-H "Authorization: ApiKey YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"operations": [
{
"op": "upsert",
"externalId": "apt-001",
"announcementStatus": "active",
"announcementType": "rent",
"propertyType": "residential",
"propertySecondaryType": "apartment",
"announcementValue": 500,
"announcementCurrency": "EUR",
"files": [
{ "url": "https://example.com/photo1.jpg", "externalFileId": "apt-001-photo-1" }
]
}
]
}'
$data = [
'operations' => [
[
'op' => 'upsert',
'externalId' => 'apt-001',
'announcementType' => 'rent',
'propertyType' => 'residential',
'propertySecondaryType' => 'apartment',
'announcementValue' => 500,
'announcementCurrency' => 'EUR',
'announcementStatus' => 'active',
'files' => [
['url' => 'https://example.com/photo1.jpg', 'externalFileId' => 'apt-001-photo-1']
]
]
]
];
$ch = curl_init('https://crm.rentix.md/api/v1/listings/bulk');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: ApiKey YOUR_API_KEY',
'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
{
"results": [
{
"op": "upsert",
"externalId": "apt-001",
"id": 42,
"success": true,
"created": true,
"updated": false
},
{
"op": "upsert",
"externalId": "apt-002",
"id": 43,
"success": true,
"created": true,
"updated": false
}
],
"summary": {
"total": 2,
"succeeded": 2,
"failed": 0
}
}
Привяжите external ID
Операция link связывает ваш ID из CRM с существующим объявлением в Rentix. Используйте её для объявлений, созданных через веб-интерфейс.
{
"operations": [
{ "op": "link", "id": 42, "externalId": "apt-001" },
{ "op": "link", "id": 43, "externalId": "apt-002" }
]
}
{
"results": [
{ "op": "link", "id": 42, "externalId": "apt-001", "success": true, "linked": true },
{ "op": "link", "id": 43, "externalId": "apt-002", "success": true, "linked": true }
]
}
Отвяжите external ID
Операция unlink удаляет связь между объявлением и external ID.
{
"operations": [
{ "op": "unlink", "id": 42 },
{ "op": "unlink", "externalId": "apt-002" }
]
}
Удалите объявления
Операция delete удаляет объявления.
{
"operations": [
{ "op": "delete", "externalId": "apt-old-001" },
{ "op": "delete", "id": 99 }
]
}
{
"results": [
{ "op": "delete", "externalId": "apt-old-001", "success": true, "deleted": true }
]
}
Проверьте данные
Операция validate проверяет данные без сохранения. Используйте для валидации форм в CRM.
{
"operations": [
{
"op": "validate",
"externalId": "apt-new",
"announcementType": "rent",
"propertyType": "residential",
"propertySecondaryType": "apartment",
"announcementValue": 500
}
]
}
{
"results": [
{
"op": "validate",
"externalId": "apt-new",
"success": true,
"valid": true,
"errors": [],
"warnings": []
}
]
}
Комбинируйте операции
В одном запросе можно выполнить разные типы операций:
{
"operations": [
{ "op": "upsert", "externalId": "apt-001", "announcementValue": 550 },
{ "op": "upsert", "externalId": "apt-002", "announcementStatus": "hidden" },
{ "op": "link", "id": 99, "externalId": "apt-003" },
{ "op": "delete", "externalId": "apt-old" }
]
}
HTTP-статусы ответа
HTTP-статус ответа bulk-запроса зависит от результата отдельных операций:
| Статус | Условие | Описание |
|---|---|---|
| 200 | Все операции успешны | Каждая операция имеет success: true |
| 207 | Частичный успех | Часть операций успешна, часть — нет |
| 422 | Все операции неуспешны | Каждая операция имеет success: false |
Всегда проверяйте поле summary и отдельные results независимо от HTTP-статуса.
Обработка ошибок
Ошибка в одной операции не останавливает остальные. Проверяйте success для каждого результата.
{
"results": [
{ "op": "upsert", "externalId": "apt-001", "id": 42, "success": true },
{
"op": "upsert",
"externalId": "apt-002",
"id": null,
"success": false,
"error": {
"statusCode": 400,
"body": {
"error": "propertyType is required",
"error_code": "VALIDATION_ERROR"
}
}
},
{ "op": "upsert", "externalId": "apt-003", "id": 44, "success": true }
],
"summary": {
"total": 3,
"succeeded": 2,
"failed": 1
}
}
Обработайте неуспешные операции:
const result = await response.json();
const failed = result.results.filter(r => !r.success);
if (failed.length > 0) {
console.error('Ошибки:', failed);
// Логировать или повторить позже
}
Рекомендации
Отправляйте последовательно
Отправляйте пакеты последовательно, а не параллельно. Система обрабатывает операции в порядке очереди — параллельная отправка не ускорит обработку.
Обновляйте только изменённые данные
После первичной синхронизации отправляйте только изменённые объявления. Повторная отправка всех объявлений без изменений — неэффективное использование API.
Используйте частичные обновления
Передавайте только изменённые поля. Чтобы очистить поле, отправьте null:
{
"op": "upsert",
"externalId": "apt-001",
"announcementValue": 600,
"propertyFloorNumber": null
}
Ограничения
| Параметр | Значение |
|---|---|
| Максимум операций в запросе | 100 |
Поля операции upsert | см. PUT /listings |
Коды ошибок
| Код | Описание | Решение |
|---|---|---|
VALIDATION_ERROR | Ошибка валидации полей | Проверьте обязательные поля и форматы |
USER_RESOLUTION_FAILED | Агент не найден | Проверьте userId или externalUserId |
NOT_FOUND | Объявление не найдено | Используйте externalId для upsert |
EXTERNAL_ID_ALREADY_LINKED | External ID уже используется | Используйте уникальный external ID |