Errors

Error Handling

HTTP status codes, rate limiting, retry strategies, and common errors

The API uses standard HTTP codes to signal errors. All errors return JSON with a problem description.

Error Format

{
  "statusCode": 400,
  "message": "Error description",
  "error": "Bad Request"
}

For validation errors, message may be an array:

{
  "statusCode": 400,
  "message": [
    "announcementDescription must be at least 40 characters",
    "propertyType must be one of: residential, commercial, parking"
  ],
  "error": "Bad Request"
}

HTTP Status Codes

CodeTypeDescriptionRetry?
400Bad RequestInvalid request parametersNo — fix the data
401UnauthorizedAPI key issueNo — check the key
403ForbiddenNo access to resourceNo — check permissions
404Not FoundResource not foundNo — check ID
415Unsupported Media TypeWrong Content-TypeNo — use application/json
422Unprocessable EntityAll bulk operations failedNo — fix the data
429Too Many RequestsRate limit exceededYes — after pause
500Server ErrorInternal errorYes — with exponential backoff

Request Requirements

Content-Type

All requests with a body (POST, PUT, PATCH) must include the Content-Type: application/json header. Requests with other content types receive a 415 Unsupported Media Type response.

Body Size Limit

Request body size is limited to 512 KB. Requests exceeding this limit receive a 413 Payload Too Large response.

Rate Limiting

The API limits request count to protect against overload. Each response includes headers with limit information.

Endpoint typeLimit
Global (all endpoints)300 requests / minute
Bulk endpoints30 requests / minute

Limit Headers

X-RateLimit-Limit: 300
X-RateLimit-Remaining: 295
X-RateLimit-Reset: 1705330800
HeaderDescription
X-RateLimit-LimitMaximum requests per period
X-RateLimit-RemainingRequests remaining
X-RateLimit-ResetWhen limit resets (Unix timestamp)

What to Do on 429

When limit is exceeded, API returns:

{
  "statusCode": 429,
  "message": "Too Many Requests"
}

Wait until the time from X-RateLimit-Reset and retry:

Node.js
async function fetchWithRateLimit(url, options) {
  const response = await fetch(url, options);

  if (response.status === 429) {
    const resetTime = response.headers.get('X-RateLimit-Reset');
    const waitMs = (parseInt(resetTime) * 1000) - Date.now();
    await new Promise(r => setTimeout(r, Math.max(waitMs, 1000)));
    return fetch(url, options); // Retry
  }

  return response;
}

Retry Strategy

When to Retry Requests

SituationAction
5xx errorsRetry with exponential backoff
429 errorsWait until X-RateLimit-Reset
Network errorsRetry with backoff
4xx errorsDon't retry — fix the request

Exponential Backoff

For server errors, increase the pause between attempts:

async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);

      // Server error — retry
      if (response.status >= 500) {
        throw new Error(`Server error: ${response.status}`);
      }

      return response;
    } catch (error) {
      if (attempt === maxRetries - 1) throw error;

      // Exponential backoff: 1s, 2s, 4s
      const delay = 1000 * Math.pow(2, attempt);
      await new Promise(r => setTimeout(r, delay));
    }
  }
}

// Usage
const response = await fetchWithRetry(
  'https://crm.rentix.md/api/v1/listings',
  {
    method: 'PUT',
    headers: { 'Authorization': 'ApiKey YOUR_API_KEY' },
    body: JSON.stringify(data)
  }
);

Common Errors

Authentication (400, 401, 403)

ErrorCauseSolution
Multiple authentication methods providedBoth Authorization and X-API-Key headers sentUse only one authentication header
API key is requiredNo API key providedAdd Authorization: ApiKey YOUR_KEY header
Invalid API keyAPI key is incorrect or revokedCheck the key value
Agency is suspendedAgency account is suspendedContact support
CRM is not enabled for this agencyCRM access not enabledContact support to enable CRM

Listings (400)

ErrorCauseSolution
Cannot provide both id and externalIdBoth identifiers were passedUse only one
Must provide id or externalIdNo identifier provided for updateAdd id or externalId
External ID already linkedExternal ID is used by another listingUse a unique ID
Minimum 3 photos requiredPhotos needed for publishingUpload at least 3 photos
Description too shortDescription is less than 40 charactersAdd more text

Media (400)

ErrorCauseSolution
Duplicate external IDExternal ID is already in useUse a unique ID
File not foundFile doesn't existCheck fileId or externalFileId
Invalid file typeUnsupported formatUse JPEG, PNG, WebP, or HEIC
Upload URL expiredSigned URL expired (30 minutes)Request a new URL

Field Validation

CodeDescription
STRING_TOO_SHORTString is shorter than minimum
STRING_TOO_LONGString is longer than maximum
NUMBER_TOO_SMALLNumber is less than minimum
NUMBER_TOO_LARGENumber is greater than maximum
INVALID_ENUM_VALUEValue is not in allowed list
REQUIRED_FIELDRequired field is empty

Example: Handle All Cases

Node.js
async function apiRequest(endpoint, data) {
  const url = `https://crm.rentix.md/api/v1${endpoint}`;
  const options = {
    method: 'PUT',
    headers: {
      'Authorization': 'ApiKey YOUR_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(data)
  };

  for (let attempt = 0; attempt < 3; attempt++) {
    const response = await fetch(url, options);

    // Success
    if (response.ok) {
      return response.json();
    }

    // Rate limit — wait and retry
    if (response.status === 429) {
      const resetTime = response.headers.get('X-RateLimit-Reset');
      const waitMs = (parseInt(resetTime) * 1000) - Date.now();
      await new Promise(r => setTimeout(r, Math.max(waitMs, 1000)));
      continue;
    }

    // Server error — retry with backoff
    if (response.status >= 500) {
      await new Promise(r => setTimeout(r, 1000 * Math.pow(2, attempt)));
      continue;
    }

    // Client error — don't retry
    const error = await response.json();
    throw new Error(`API Error: ${JSON.stringify(error.message)}`);
  }

  throw new Error('Max retries exceeded');
}

Recommendations

  1. Log errors — save statusCode, message, and timestamp for diagnostics
  2. Don't ignore 4xx — these are errors in your data, fix them
  3. Respect rate limits — on 429, always wait the specified time
  4. Use exponential backoff — on 5xx, don't hammer the server immediately
Copyright © 2026