Create and update listings

Upload photos, then create, read, update and delete your agency's listings through the property API.

These endpoints manage your agency's own listings. Writes need the properties:write scope, reads properties:read, and photo uploads media:write. Every write is scoped to the key's organization. Send the key as Authorization: Bearer <key>, as in every example here. X-API-Key: <key> is still accepted on these routes, and so is Authorization: ApiKey <key>.

Upload photos

POST /properties/media/upload

Uploads one image (multipart field file, at most 20 MB). Every photo, thumbnail and floor plan on a listing must be an image your organization owns, so upload first and use the returned URLs.

bash
curl -X POST https://api.fondaro.com/properties/media/upload \  -H "Authorization: Bearer fondaro_pk_abc123" \  -F "file=@living-room.jpg"
json
{  "success": true,  "images": {    "fullSize": "https://…/properties/images/3f2a.jpg",    "thumbnail": "https://…/properties/thumbnails/3f2a.webp"  }}

Put fullSize in images[].url and thumbnail in thumbnails[].url. Photos uploaded in the dashboard, a URL the listing already has in the same field, and a thumbnail that repeats an images URL in the same request are accepted too; any other URL is a 400 naming the field.

Fondaro records each upload's pixel size and returns it as images[].width and height; you never need to send them. An upload that no listing uses within 7 days may be removed, so upload right before you create or update.

Create a listing

POST /properties

Creates a listing as pending with a generated reference (FDR- and eight letters and digits). See Own-listing lifecycle for statuses.

bash
curl -X POST https://api.fondaro.com/properties \  -H "Authorization: Bearer fondaro_pk_abc123" \  -H "Content-Type: application/json" \  -d '{    "listingType": "sale",    "propertyCategory": "residential",    "propertyType": "house_detached",    "city": "Marbella",    "countryCode": "ES",    "currency": "EUR",    "price": 1250000,    "bedrooms": 4,    "bathrooms": 3,    "livingArea": 320,    "plotArea": 800,    "areaUnit": "sqm",    "features": ["pool", "sea_view"],    "images": [{ "url": "https://…/properties/images/3f2a.jpg", "order": 0, "isFeatured": true }]  }'
json
{  "id": "29a1e184-237a-40c8-a1fe-624b0bcbb2f4",  "referenceNumber": "FDR-7KQ2MX9A",  "status": "pending",  "listingType": "sale",  "propertyType": "house_detached",  "city": "Marbella",  "price": 1250000,  "currency": "EUR",  "features": ["pool", "sea_view"],  "hasPool": true,  "hasSeaView": true,  "createdAt": "2026-10-02T10:00:00.000Z"}

Listing fields

Required on create:

FieldValues
listingTypesale, rent, sale_or_rent, fraction
propertyCategoryresidential, commercial, industrial, land
propertyTypeA type that belongs to the category (below)
cityUp to 100 characters
countryCodeISO 3166-1 alpha-2, for example ES
currencyISO 4217, for example EUR

Optional:

FieldTypeNotes
title, translatedTitlesstring, objectHeadline up to 140 characters; translations as { "es": "..." }
description, translatedDescriptionsstring, object
addressLine1, addressLine2, postalCodestring
community, region, provinceStatestring
latitude, longitudenumberMust lie inside countryCode. Without a point, Fondaro looks up addressLine1 and fills it in on an exact match
pricenumber
rentalPrice, rentalPriceLowSeason, rentalPriceHighSeason, rentalPeriodnumber, stringRent for rent and sale_or_rent; period day, week, month, year
availableFrom, completionDatedateYYYY-MM-DD
bedrooms, parkingSpacesinteger
bathroomsnumberHalves allowed, up to 99.9
livingArea, plotArea, areaUnitnumber, stringUnit sqm or sqft
yearBuiltinteger1801 to five years ahead
isNewConstruction, isExteriorboolean
conditionstringnew, excellent, good, needs_renovation, under_construction
floor, totalFloorsintegerBasements are negative
orientationstringN, NE, E, SE, S, SW, W, NW
parkingTypestringgarage, underground, covered, open, street, communal
energyRatingstringA+, A to G, exempt, in_progress
energyConsumptionKwh, co2Emissions, energyRatingDetailsnumber, string
communityFeesPerYear, ibiPerYear, basuraPerYearnumberYearly costs in currency
features, furnishedstring[], stringSee Amenities and furnishing
imagesarray[{ url, alt?, order, isFeatured? }]
thumbnailsarray[{ url, alt?, order, originalImageIndex }]
floorPlansarray[{ url, alt?, order }]
videoUrls, virtualTourUrlsstring[]Up to 20 http(s) links each
sharedCommission, sharedCommissionNotesnumber, stringWhat you offer a collaborating agency (0 to 100 %) and its terms; every agency on the network sees them
commissionnumberYour own commission %, private to your agency
viewingInstructionsstringKeys and access notes, private to your agency
agentIdstringThe assigned agent from your roster
additionalFeaturesobjectYour own key-value facts
autoRenewEnabledbooleanRenew automatically at expiresAt (default false)

propertyType must belong to propertyCategory; other fits every category.

CategoryTypes
residentialapartment, condominium, house_detached, house_semi_detached, house_terraced, townhouse, multi_family_home, penthouse, studio
commercialoffice, retail, commercial_other, hospitality
industrialindustrial_warehouse, industrial_other
landland_residential, land_commercial, land_agricultural, land_other

Amenities and furnishing

features lists amenities as slugs: pool, sea_view, garage, terrace, garden, air_conditioning, lift, beachfront, frontline_golf, panoramic_views, gated_complex, storage_room, built_in_wardrobes, luxury. Furnishing is its own field, furnished (no, partly, fully).

The older booleans (hasPool, hasSeaView, hasGarage, hasTerrace, hasGarden, hasAirConditioning, hasLift, isFurnished) still work:

  • With features, the list is stored and the booleans follow it; booleans sent beside it are ignored.
  • With booleans only, each adds or removes its own amenity and leaves every other slug as it was.
  • furnished wins over isFurnished. Sent alone, isFurnished: true stores fully and false clears furnished.

Responses always carry both features and the booleans.

Read a listing

GET /properties/:id

Returns your own listing in any status, or another agency's active listing. Anything else is a 404.

Query parameterMeaning
includeBrandingAdd the agency's branding and the agent card
includeAdCount, includeAdCreativesAdd the ad creative count or the creatives
bash
curl "https://api.fondaro.com/properties/29a1e184-237a-40c8-a1fe-624b0bcbb2f4?includeBranding=true" \  -H "Authorization: Bearer fondaro_pk_abc123"
json
{  "id": "29a1e184-237a-40c8-a1fe-624b0bcbb2f4",  "referenceNumber": "FDR-7KQ2MX9A",  "status": "active",  "city": "Marbella",  "price": 1250000,  "currency": "EUR",  "sharedCommission": 2.5,  "sharedCommissionNotes": "Paid on completion.",  "agent": { "firstName": "Ana", "lastName": "Ruiz", "title": "Sales agent" },  "organizationBranding": { "name": "Costa Homes" }}

Another agency's listing omits only what is private to it: commission, viewingInstructions and import-only additionalFeatures keys. It keeps the street address, postcode, exact coordinates and the shared-commission offer. The agent's email and phone numbers appear only when that agent shares their contact with the network (the default).

Update a listing

PUT /properties/:id

Send only the fields to change; any field you leave out keeps its value. Every create field is accepted, plus status (sold, rented or deleted; see Own-listing lifecycle).

bash
curl -X PUT https://api.fondaro.com/properties/29a1e184-237a-40c8-a1fe-624b0bcbb2f4 \  -H "Authorization: Bearer fondaro_pk_abc123" \  -H "Content-Type: application/json" \  -d '{"price": 1150000, "commission": 4.5}'

Returns the updated listing. The required create fields and the lists features, floorPlans, videoUrls and virtualTourUrls cannot be cleared with null; send [] to empty a list. A changed type is checked against the category and a changed point against the country. referenceNumber never changes.

Delete a listing

DELETE /properties/:id

Sets the listing's status to deleted. It leaves search and portal feeds but its history is kept.

bash
curl -X DELETE https://api.fondaro.com/properties/29a1e184-237a-40c8-a1fe-624b0bcbb2f4 \  -H "Authorization: Bearer fondaro_pk_abc123"
json
{ "success": true }

Errors

StatusWhen
400A field fails validation. message is an array of strings, each led by the field path, for example "areaUnit must be one of the following values: sqm, sqft" or "images.2.url is not an image this organization owns"
403The key lacks the scope (API_KEY_SCOPE_MISSING)
404The listing does not exist, is not yours (writes), or is another agency's non-active listing (reads)

Nothing is saved when a request is refused.