Homezone API for CRMs

Your CRM can publish an agent's listings on Homezone.al and keep them up to date: create, update, take down and delete them. This page is for the CRM's developers.

Get a token

  1. The agent opens Profile → Connect your CRM, presses Create token and chooses what the token can do and how long it works.
  2. The agent copies the token into your CRM's Homezone settings.
  3. Your CRM sends it with every request. The listings it creates belong to that agent's account.

There is one token per Homezone account. When the agent creates a new one or removes it, the old one stops working at once and your requests get 401. They get 401 too once the token expires, if the agent chose an end date. Keep it on your server like a password, never in a web page, an app or a link.

Send a request

All requests go to https://apiv2.homezone.al over HTTPS. Bodies and answers are JSON.

HeaderValue
AuthorizationBearer followed by the token
X-FingerYour CRM's name, for example bsp-crm. Never empty.
Content-Typeapplication/json, except for uploads (multipart/form-data)
EndpointDoesPermission
POST /media/uploadUploads a photo, when your photo links aren't public.Publish and update your listings
POST /property/saveCreates or updates a listing, its status included.Publish and update your listings
GET /property/loadReads the agent's listings.Read your listings
POST /property/deleteDeletes listings.Delete your listings

Each endpoint needs the permission next to it, the one the agent ticks under Profile → Connect your CRM. Every other endpoint answers 403. None of them moves a listing back to the top of the search: only a listing's first publication sets its date.

Create or update a listing

POST /property/save. Send the whole listing every time, with your own id in external_id. The first save creates the listing; every later save with the same external_id updates it.

curl -X POST https://apiv2.homezone.al/property/save \
  -H "Authorization: Bearer $HOMEZONE_TOKEN" \
  -H "X-Finger: bsp-crm" \
  -H "Content-Type: application/json" \
  -d '{
    "external_id": "BSP-58412",
    "status": "published",
    "contract_type": "rent",
    "category": "apartment",
    "title": "Apartament 1+1 me qira, Komuna e Parisit",
    "description": "70 m², i mobiluar, me ashensor.",
    "price": 700,
    "currency": "EUR",
    "pay_period": "monthly",
    "bedrooms": 1,
    "bathrooms": 1,
    "size": 70,
    "county": "Tiranë",
    "city": "Tiranë",
    "area": "Komuna e Parisit",
    "contact_name": "Jane Doe",
    "contact_email": "jane@example.com",
    "contact_phone": "+355691234567",
    "assets_url": ["https://cdn.example.com/58412/1.jpg", "https://cdn.example.com/58412/2.jpg"]
  }'

The answer:

{ "error": "", "errorCode": null, "id": 185276, "url": "https://homezone.al/…", "duplicates": [] }
  • id is the Homezone id. Keep it: deleting a listing uses it.
  • duplicates lists published listings that look the same (title, price, place and main photo). Your listing is saved anyway.
  • With "status": "published", a listing is published only if it has a category, county and city, a description, at least one photo, an address or area, and the contact name, email and phone. Otherwise it is saved as a draft, without an error.
  • Saving never moves a listing back to the top of the search. Only its first publication sets its date.

Photos

Send the photos in one of two ways. Either way, the list order is the display order and the first photo is the cover.

  • Links, when your photos are public: put them in assets_url. Each link must open without a login. Homezone downloads the photos on every save, so a save can take several seconds: wait 60 seconds before you time out.
  • Uploads, when they aren't public: upload each photo once (next section) and send the ids in assets: "assets": [{"id": 912345}, {"id": 912346}]. This is what the Homezone app does. Keep the ids and send the same ones on later saves: nothing is downloaded again, so saves stay fast.

Send all the photos on every save. A photo left out of the list is removed from the listing, and its id can't be used again: upload it again if you need it. A save without any photos keeps the current ones but saves the listing as a draft.

Upload a photo

POST /media/upload as multipart/form-data, with the same Authorization and X-Finger headers.

FieldValue
fileThe image, with a file name that ends in its extension.
fileSizeThe whole file's size in bytes.
tempFileNameEmpty. Only pieces of a large file use it (below).
curl -X POST https://apiv2.homezone.al/media/upload \
  -H "Authorization: Bearer $HOMEZONE_TOKEN" \
  -H "X-Finger: bsp-crm" \
  -F "file=@58412-1.jpg" \
  -F "fileSize=834512" \
  -F "tempFileName="

The answer:

{ "status": 1, "message": "File uploaded", "id": 912345, "thumbUrl": "https://media.homezone.al/…", "path": "2026/11/07/…" }
  • Send each file in one request, up to 50 MB. For a larger file, send it in pieces in order, as the Homezone app does with 1 MB pieces. The first piece has an empty tempFileName, and fileSize is always the whole file's size. Each answer before the last says "Chunk uploaded" and gives a tempFileName for the next piece. The last answer has the id.
  • JPEG, PNG, WebP or GIF. Any other type answers 400 UNSUPPORTED_MEDIA.
  • An uploaded photo can only be used in the same agent's listings.
  • Upload only the photos you're about to save: a photo never attached to a listing stays stored.

Fields

FieldValuesNotes
external_idtextYour id. A save with a known one updates instead of creating.
external_urllinkThe listing on your site. Optional.
statuspublished, draftDefault draft.
contract_typesale, rent
categoryapartment, house, vila, studio, penthouse, development, commercial, shop, store, bar, bar_restaurant, hotel, office, land, park, propertyNeeded to publish.
titletextAt most 128 characters.
descriptiontextNeeded to publish.
pricenumber
currencyEUR, USD, ALLDefault EUR. ALL is stored in EUR at 100 lek per euro.
pay_perioddaily, weekly, monthly, yearlyRent only. Default monthly.
bedrooms, bathrooms, floornumbers
size, land_sizenumbersIn m².
build_yearyearOptional.
facilitiescable_tv, cable_data, central_heating, dishwasher, dryer, washing_machine, garden, balcony, gas_heating, internet, alarm, parking, reception, wheelchair_access, microwave, serviced_propertyA list.
has_certificate, contact_whatsapp0, 1
energy_classA+, A … G, null
energy_indicator0 to 2000, or nullkWh per m² a year.
countryAL
county, citytextNeeded to publish.
area, addresstextOne of the two is needed to publish.
latitude, longitudenumbers
contract_statusavailable, rented, sold, withdrawn, sale_agreedDefault available.
contact_name, contact_email, contact_phonetextNeeded for a new listing, and to publish.
expiry_datedateDefault one year after the save.
assets_urllist of linksPublic photos. See Photos.
assetslist of {"id": …}Uploaded photos. See Photos.

A number field that gets something else is saved as 0. Fields that Homezone sets itself (user_id, agency_id, publish_date, views and the like) are ignored.

Take a listing down

  • Unpublish: save it with "status": "draft". Saving it again with "published" puts it back with its old date.
  • Sold or rented: save it with "contract_status": "sold" or "rented".
  • Delete: POST /property/delete with the Homezone ids, [185276, 185277]. The answer counts them: {"result": 2}. A later save with the same external_id brings the listing back.

Your CRM's version wins. The agent's edits on Homezone are replaced at the next save, and a listing deleted on Homezone comes back at the next save with its external_id. To keep a listing off Homezone, unpublish or delete it from the CRM.

Read the agent's listings

  • GET /property/load?externalId=BSP-58412 finds one listing by your id.
  • GET /property/load?status=published&page=1&limit=100 lists them, at most 200 a page. The answer is {"properties": [...], "total": 120}.

Errors

AnswerWhyWhat to do
401The token was removed, replaced or has expired, or the account was closed.Ask the agent for a new token. Don't retry.
403 domain is not authorizedNo token, or not a token Homezone made: check that it was copied whole.Send the token as <code>Authorization: Bearer</code>.
403 Missing fingerprintThe X-Finger header is missing.Add it.
403 This token is not allowed to do thisThe token doesn't have the permission this endpoint needs, or the endpoint isn't on this page.Ask the agent for a token with that permission.
400 UNSUPPORTED_MEDIAAn upload that isn't JPEG, PNG, WebP or GIF.Convert it, or leave it out.
400 INVALID_CONTACTA new listing without contact name, email and phone.Send all three.
400GET where POST is needed.Use POST.
500A problem on our side.Retry later.

Good practice

  • Save a listing only when something changed in the CRM.
  • Send one request at a time per agent, and wait for the answer.
  • Retry network errors and 500 after 1, 5 and 15 minutes. Don't retry 400, 401 or 403.
  • Use each external_id for one property only, and never reuse it.
  • Store the Homezone id next to your own.