Guides

Initial Sync

Upload all listings from CRM on first connection

When connecting CRM for the first time, you need to upload all existing listings to Rentix. Thanks to built-in photo import by URL, this is done in one step.

Process Overview

1. Preparation        → Verify API key
2. Agents (optional)  → Invite and link agents
3. Sync               → Bulk upload listings with photos and status

The system automatically processes photos, translates descriptions, and publishes listings. You don't need to track the status of each operation.


Step 1. Preparation

Verify Connection

const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://crm.rentix.md/api/v1';

async function checkConnection() {
  const response = await fetch(`${BASE_URL}/agency`, {
    headers: { 'Authorization': `ApiKey ${API_KEY}` }
  });

  if (!response.ok) {
    throw new Error('Connection error. Check API key.');
  }

  const agency = await response.json();
  console.log(`Connected: ${agency.name}`);
  console.log(`Listing limit: ${agency.limits.monthlyListings.limit}`);

  return agency;
}

Step 2. Agents (Optional)

Listings can be published without linking to a specific agent — in this case, agency information is displayed. This is convenient during transition while not all agents are registered on the platform.

Invite Agents

Agents must be invited through the web interface — they need phone verification:

  1. Log in to rentix.md
  2. Open MenuAgency NameInvitations
  3. Enter the agent's email and send the invitation

After agents accept invitations, link them to records in your CRM:

async function linkAgents(crmAgents) {
  // Get agents from Rentix
  const response = await fetch(`${BASE_URL}/users`, {
    headers: { 'Authorization': `ApiKey ${API_KEY}` }
  });
  const { items: rentixAgents } = await response.json();

  // Prepare link operations
  const operations = [];

  for (const crmAgent of crmAgents) {
    const match = rentixAgents.find(r => r.phone === crmAgent.phone);
    if (match && !match.externalId) {
      operations.push({
        op: 'link',
        id: match.id,
        externalId: crmAgent.id
      });
    }
  }

  if (operations.length === 0) return;

  // Bulk link
  await fetch(`${BASE_URL}/users/bulk`, {
    method: 'POST',
    headers: {
      'Authorization': `ApiKey ${API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ operations })
  });

  console.log(`Agents linked: ${operations.length}`);
}

After linking, you can specify agents in listings by their external ID from your CRM.


Step 3. Sync Listings

Send listings in batches of 100. Pass photos by URL — the system will download them automatically.

Transform Data

function transformListing(crmListing) {
  return {
    op: 'upsert',
    externalId: crmListing.id,

    // Type
    announcementType: crmListing.type === 'sale' ? 'sale' : 'rent',
    propertyType: 'residential',
    propertySecondaryType: mapPropertyType(crmListing.category),

    // Price
    announcementValue: crmListing.price,
    announcementCurrency: crmListing.currency || 'EUR',
    announcementPayPeriod: crmListing.type === 'rent' ? 'monthly' : undefined,

    // Characteristics
    propertyArea: crmListing.area,
    propertyFloorNumber: crmListing.floor,
    propertyFloorsTotal: crmListing.totalFloors,

    // Description
    announcementDescription: crmListing.description,

    // Photos — pass URL and externalFileId for tracking
    files: crmListing.photos.map((photo, index) => ({
      url: photo.url,
      externalFileId: photo.id,
    })),

    // Agent (if linked)
    user: { externalUserId: crmListing.agentId },

    // Publish immediately
    announcementStatus: 'active'
  };
}

function mapPropertyType(category) {
  const map = {
    'apartment': 'apartment',
    'house': 'house',
    'room': 'room',
  };
  return map[category];
}

Send in Batches

function chunkArray(array, size) {
  const chunks = [];
  for (let i = 0; i < array.length; i += size) {
    chunks.push(array.slice(i, i + size));
  }
  return chunks;
}

async function syncListings(crmListings) {
  const operations = crmListings.map(transformListing);
  const chunks = chunkArray(operations, 100);

  let total = 0;

  // Send batches sequentially
  for (const chunk of chunks) {
    const response = await fetch(`${BASE_URL}/listings/bulk`, {
      method: 'POST',
      headers: {
        'Authorization': `ApiKey ${API_KEY}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ operations: chunk })
    });

    const result = await response.json();
    total += result.summary.succeeded;

    console.log(`Processed: ${total}/${crmListings.length}`);

    // Log errors
    const failed = result.results.filter(r => !r.success);
    for (const f of failed) {
      console.error(`Error ${f.externalId}: ${f.error?.message}`);
    }
  }

  return total;
}
Send batches sequentially, not in parallel. The system queues all operations — parallel sending won't speed up processing but may cause errors.

Full Script

async function fullSync() {
  console.log('=== Initial Sync ===');

  // 1. Verify connection
  console.log('\n1. Verifying connection...');
  await checkConnection();

  // 2. Get data from CRM
  console.log('\n2. Getting data from CRM...');
  const crmListings = await getListingsFromCRM(); // your function
  console.log(`Found: ${crmListings.length} listings`);

  // 3. Sync listings
  console.log('\n3. Syncing listings...');
  const synced = await syncListings(crmListings);

  console.log('\n=== Sync Complete ===');
  console.log(`Sent: ${synced} listings`);
  console.log('Listings will appear on the site after processing.');
}

fullSync().catch(console.error);

What Happens After Submission

After sending data, the system automatically:

  1. Downloads photos from the specified URLs
  2. Optimizes images — compression, conversion, thumbnail creation
  3. Analyzes photos — detects property features (amenities, furniture, etc.)
  4. Translates description to all platform languages
  5. Publishes listing — status changes to active

You don't need to track the status of each operation. If an error occurs, you'll see it in the bulk request result.


What's Next

After initial sync, set up continuous sync for regular data updates.

Copyright © 2026