Listings

Bulk Operations

Mass creation, updating, and management of up to 100 listings per request

Bulk operations let you process up to 100 listings in a single request. Use them for initial sync and mass updates.

Why Use Bulk

ApproachRequests for 100 listings
Individual requests100
Bulk operation1

Bulk reduces network overhead and speeds up synchronization.


Operation Types

Each operation must contain an op field defining the action type:

OperationDescription
upsertCreate or update a listing
linkLink external ID to an existing listing
unlinkUnlink external ID
deleteDelete a listing
validateCheck data without saving

Create or Update Listings

The upsert operation creates a new listing or updates an existing one by 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: 'Cozy apartment in the center...',
        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: 'Spacious apartment with balcony...',
        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(`Succeeded: ${result.summary.succeeded}/${result.summary.total}`);
Response
{
  "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
  }
}

The link operation connects your CRM ID with an existing Rentix listing. Use it for listings created via the web interface.

{
  "operations": [
    { "op": "link", "id": 42, "externalId": "apt-001" },
    { "op": "link", "id": 43, "externalId": "apt-002" }
  ]
}
Response
{
  "results": [
    { "op": "link", "id": 42, "externalId": "apt-001", "success": true, "linked": true },
    { "op": "link", "id": 43, "externalId": "apt-002", "success": true, "linked": true }
  ]
}

The unlink operation removes the connection between a listing and external ID.

{
  "operations": [
    { "op": "unlink", "id": 42 },
    { "op": "unlink", "externalId": "apt-002" }
  ]
}

Delete Listings

The delete operation removes listings.

{
  "operations": [
    { "op": "delete", "externalId": "apt-old-001" },
    { "op": "delete", "id": 99 }
  ]
}
Response
{
  "results": [
    { "op": "delete", "externalId": "apt-old-001", "success": true, "deleted": true }
  ]
}

Validate Data

The validate operation checks data without saving. Use it for form validation in your CRM.

{
  "operations": [
    {
      "op": "validate",
      "externalId": "apt-new",
      "announcementType": "rent",
      "propertyType": "residential",
      "propertySecondaryType": "apartment",
      "announcementValue": 500
    }
  ]
}
Response
{
  "results": [
    {
      "op": "validate",
      "externalId": "apt-new",
      "success": true,
      "valid": true,
      "errors": [],
      "warnings": []
    }
  ]
}

Combine Operations

You can perform different operation types in a single request:

{
  "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" }
  ]
}

Response Status Codes

The HTTP status code of a bulk response depends on the outcome of individual operations:

StatusConditionDescription
200All operations succeededEvery operation has success: true
207Partial successSome operations succeeded, some failed
422All operations failedEvery operation has success: false

Always check the summary field and individual results regardless of the HTTP status code.

Error Handling

An error in one operation doesn't stop the others. Check success for each result.

Response with Error
{
  "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
  }
}

Handle failed operations:

Node.js
const result = await response.json();

const failed = result.results.filter(r => !r.success);
if (failed.length > 0) {
  console.error('Errors:', failed);
  // Log or retry later
}

Recommendations

Send Sequentially

Send batches sequentially, not in parallel. The system processes operations in queue order — parallel sending won't speed up processing.

Update Only Changed Data

After initial sync, send only changed listings. Resending all listings without changes is an inefficient use of the API.

Use Partial Updates

Pass only changed fields. To clear a field, send null:

{
  "op": "upsert",
  "externalId": "apt-001",
  "announcementValue": 600,
  "propertyFloorNumber": null
}

Limits

ParameterValue
Maximum operations per request100
Operation upsert fieldssee PUT /listings

Error Codes

CodeDescriptionSolution
VALIDATION_ERRORField validation errorCheck required fields and formats
USER_RESOLUTION_FAILEDAgent not foundCheck userId or externalUserId
NOT_FOUNDListing not foundUse externalId for upsert
EXTERNAL_ID_ALREADY_LINKEDExternal ID already in useUse a unique external ID
Copyright © 2026