Initial Sync
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:
- Log in to rentix.md
- Open Menu → Agency Name → Invitations
- Enter the agent's email and send the invitation
Link After Registration
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;
}
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:
- Downloads photos from the specified URLs
- Optimizes images — compression, conversion, thumbnail creation
- Analyzes photos — detects property features (amenities, furniture, etc.)
- Translates description to all platform languages
- 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.