Fișiere media

Încărcare fișiere

Cum să încarci fotografii — prin URL în anunț, import după URL sau signed URL

Trei modalități de încărcare a fotografiilor, de la simplu la complex:

  1. URL în anunț — transmite linkurile direct la crearea anunțului
  2. Import după URL — încarcă fotografiile separat, apoi leagă-le la anunț
  3. Signed URL — pentru încărcare fișiere de pe client

URL în anunț (recomandat)

Cea mai simplă metodă — transmite URL-urile fotografiilor direct la crearea sau actualizarea anunțului. Se recomandă adăugarea externalFileId pentru urmărire:

{
  "externalId": "apt-001",
  "announcementStatus": "active",
  "announcementType": "rent",
  "propertyType": "residential",
  "propertySecondaryType": "apartment",
  "announcementValue": 500,
  "files": [
    { "url": "https://placehold.co/1920x1080/jpg?text=Living", "externalFileId": "apt-001-photo-1" },
    { "url": "https://placehold.co/1920x1080/jpg?text=Dormitor", "externalFileId": "apt-001-photo-2" },
    { "url": "https://placehold.co/1920x1080/jpg?text=Bucătărie", "externalFileId": "apt-001-photo-3" }
  ]
}

Sistemul va încărca automat fotografiile, le va optimiza și le va lega la anunț. La retrimiterea aceluiași externalFileId, sistemul folosește fișierul deja încărcat, evitând duplicarea.


Import după URL

Folosește această metodă dacă vrei să încarci fotografiile în avans sau să le gestionezi separat de anunțuri.

Încarcă o fotografie

const response = await fetch('https://crm.rentix.md/api/v1/media/upload-from-url', {
  method: 'POST',
  headers: {
    'Authorization': 'ApiKey YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    url: 'https://placehold.co/1920x1080/jpg?text=Living',
    externalId: 'apt-001-photo-1'
  })
});

const result = await response.json();
console.log(`Media ID: ${result.mediaId}, Status: ${result.status}`);
Răspuns
{
  "mediaId": 123,
  "status": "pending",
  "externalId": "apt-001-photo-1",
  "jobId": 456
}

Statusul pending înseamnă că fișierul a fost pus în coadă pentru încărcare și optimizare. Câmpul jobId permite urmărirea statusului procesării.

Încărcare bulk

Pentru încărcarea mai multor fișiere, folosește endpoint-ul bulk cu operația upload-from-url:

const response = await fetch('https://crm.rentix.md/api/v1/media/bulk', {
  method: 'POST',
  headers: {
    'Authorization': 'ApiKey YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    operations: [
      { op: 'upload-from-url', url: 'https://placehold.co/1920x1080/jpg?text=Photo+1', externalId: 'apt-001-photo-1' },
      { op: 'upload-from-url', url: 'https://placehold.co/1920x1080/jpg?text=Photo+2', externalId: 'apt-001-photo-2' },
      { op: 'upload-from-url', url: 'https://placehold.co/1920x1080/jpg?text=Photo+3', externalId: 'apt-001-photo-3' }
    ]
  })
});

const result = await response.json();
console.log(`Încărcate: ${result.summary.succeeded} din ${result.summary.total}`);
Răspuns
{
  "results": [
    { "op": "upload-from-url", "externalId": "apt-001-photo-1", "mediaId": 123, "success": true },
    { "op": "upload-from-url", "externalId": "apt-001-photo-2", "mediaId": 124, "success": true }
  ],
  "summary": { "total": 2, "succeeded": 2, "failed": 0 }
}

Signed URL

Folosește această metodă pentru încărcarea fișierelor direct de pe client sau când fișierele nu sunt accesibile printr-un URL public.

Pasul 1. Solicită URL-ul pentru încărcare

const response = await fetch('https://crm.rentix.md/api/v1/media/request-upload-url', {
  method: 'POST',
  headers: {
    'Authorization': 'ApiKey YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    files: [
      { fileName: 'living-room.jpg', size: 245000, contentType: 'image/jpeg', externalId: 'apt-001-photo-1' }
    ]
  })
});

const result = await response.json();
console.log(`URL încărcare: ${result.upload[0].url}`);
Răspuns
{
  "uuid": "abc123",
  "upload": [
    {
      "url": "https://storage.googleapis.com/bucket/abc123_living-room.jpg?signature=...",
      "generatedFileName": "abc123_living-room.jpg",
      "externalId": "apt-001-photo-1"
    }
  ]
}
URL-ul este valabil 30 minute. Încarcă fișierul înainte de expirare.

Pasul 2. Încarcă fișierul

Trimite fișierul cu o cerere PUT la URL-ul primit:

curl -X PUT "https://storage.googleapis.com/bucket/abc123_living-room.jpg?signature=..." \
  -H "Content-Type: image/jpeg" \
  --data-binary @living-room.jpg

Pasul 3. Confirmă încărcarea

Folosește endpoint-ul bulk cu operația confirm-upload:

const response = await fetch('https://crm.rentix.md/api/v1/media/bulk', {
  method: 'POST',
  headers: {
    'Authorization': 'ApiKey YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    operations: [
      {
        op: 'confirm-upload',
        uuid: 'abc123',
        generatedFileName: 'abc123_living-room.jpg',
        externalId: 'apt-001-photo-1'
      }
    ]
  })
});

const result = await response.json();
console.log(`Confirmate: ${result.summary.succeeded} din ${result.summary.total}`);

Leagă fotografiile la anunț

După încărcare, leagă fotografiile la anunț. Sunt trei modalități de a indica fișierul:

După internal ID

{
  "files": [
    { "id": 123 },
    { "id": 124 }
  ]
}

După external ID

{
  "files": [
    { "externalFileId": "apt-001-photo-1" },
    { "externalFileId": "apt-001-photo-2" }
  ]
}

După URL (auto-import)

{
  "files": [
    { "url": "https://placehold.co/1920x1080/jpg?text=Photo+1", "externalFileId": "apt-001-photo-1" },
    { "url": "https://placehold.co/1920x1080/jpg?text=Photo+2", "externalFileId": "apt-001-photo-2" }
  ]
}

Operații bulk cu media

Toate operațiile cu fișiere media pot fi efectuate prin endpoint-ul unic POST /media/bulk:

OperațieDescriere
upload-from-urlÎncarcă fișier după URL
confirm-uploadConfirmă încărcare prin signed URL
linkLeagă external ID la fișier
unlinkDezleagă external ID
deleteȘterge fișier

Exemplu combinație operații

{
  "operations": [
    { "op": "upload-from-url", "url": "https://example.com/new.jpg", "externalId": "new-photo" },
    { "op": "link", "mediaId": 123, "externalId": "old-photo-linked" },
    { "op": "delete", "externalId": "old-photo-to-remove" }
  ]
}

Gestionarea erorilor

O eroare într-o operație nu oprește celelalte. Verifică success pentru fiecare rezultat:

Răspuns cu eroare
{
  "results": [
    { "op": "upload-from-url", "externalId": "photo-1", "mediaId": 123, "success": true },
    {
      "op": "upload-from-url",
      "externalId": "photo-2",
      "mediaId": null,
      "success": false,
      "error": {
        "statusCode": 400,
        "body": {
          "error": "Duplicate external ID",
          "error_code": "DUPLICATE_EXTERNAL_ID"
        }
      }
    }
  ],
  "summary": { "total": 2, "succeeded": 1, "failed": 1 }
}

Erori frecvente

EroareCauzăSoluție
Duplicate external IDExternal ID este deja folositFolosește un ID unic pentru fiecare fișier
Upload URL expiredSigned URL a expiratSolicită un URL nou
Invalid content typeFormat fișier invalidFolosește JPEG, PNG, WebP sau HEIC
File too largeFișier prea mareMicșorează dimensiunea sau comprimă
Copyright © 2026