Partner API Get access

API reference

Two interfaces onto the same listings. The JSON API is for new integrations; the listingSync bridge answers the XML-RPC calls existing CRMs already make.

JSON APIhttps://api.lagoniko.ai/v1
listingSynchttps://api.lagoniko.ai/listingSync/v1_0

Every request on this page can be run with your API key. Use test credentials: they never publish anything.

The listing object

What you send to create or replace a listing, and what every response returns. Responses add the fields below the line.

Attributes

  • transactionstringRequired
    One of sale, rent.
  • propertyTypestringRequired
    One of apartment, maisonette, house, villa, studio, loft, building, commercial_building, office, shop, business_premises, showroom, warehouse, industrial_space, craft_space, hotel, parking, land, agricultural_land, island, other_land.
  • pricenumberRequired
    In euros. Monthly rent for a rental. Optional when priceOnRequest is true.
  • locationobjectRequired
    Where the property is. The area is read from the coordinates.
    Show 5 child attributes
    • latnumberRequired
      Latitude, WGS84.
    • lngnumberRequired
      Longitude, WGS84.
    • precisionstring
      exact shows the point and the street address. approximate (default) shows only the area.
    • addressstring or object
      Street address, or {"el", "en"}. Shown only with exact.
    • postalCodestring
  • sizenumberRequired
    Floor area in m². For land, 0 with plotSize.
  • plotSizenumber
    Plot area in m².
  • roomsobject
    Show 4 child attributes
    • bedroomsinteger
    • bathroomsinteger
    • wcinteger
      Separate WCs.
    • livingRoomsinteger
  • floorobject
    Show 4 child attributes
    • numberinteger
      Ground floor is 0, basement -1.
    • tointeger
      Top floor of a duplex.
    • categorystring
      basement, semi_basement, ground, elevated_ground, 1 to 4, 5_plus, penthouse. Derived from number when left out.
    • totalFloorsinteger
      Floors in the building.
  • yearBuiltinteger
    Needed to go live, except for land and parking.
  • yearRenovatedinteger
  • energyClassstring
    A+, A, B+, B, C, D, E, F, G, H, exempt, pending. Needed to go live, except for land and parking.
  • conditionstring
    newly_built, under_construction, unfinished, excellent, good, needs_renovation, renovated.
  • heatingobject
    Show 2 child attributes
    • systemstring
      none, central, autonomous, underfloor, air_conditioning, heat_pump, fireplace.
    • mediumstring
      natural_gas, oil, electric, wood, pellet, solar, district, lpg.
  • coolingstring
    none, air_conditioning, central_ac, heat_pump_reversible, ceiling_fan.
  • furnishingstring
    furnished, semi_furnished, unfurnished.
  • kitchenstring
    separate, open, american, none.
  • parkingSpacesinteger
  • commonExpensesnumber
    Monthly building charges in euros.
  • availableFromdate
    YYYY-MM-DD.
  • featuresarray of strings
    elevator, storage, parking, air_conditioning, balcony, sea_view, garden, pool, fireplace, security_door, double_glazing, solar_water_heater, alarm, pets_allowed, bbq, attic, playroom, underground_parking, ev_charger. Unknown codes are ignored with a warning.
  • titleobject
    {"el", "en"}, up to 160 characters each. Written for you from the type, size and area when left out.
  • descriptionobject
    {"el", "en"}. Needed to go live. One language is shown in both until you send the other.
  • mediaobject
    Show 2 child attributes
    • videoUrlstring
    • virtualTourUrlstring
  • agentRefstring
    Your id for the agent handling the listing.
  • priceOnRequestboolean
    Hide the price on the portal.
  • priceNegotiableboolean
  • statusstring
    published (default) or hidden.
  • photosarray of strings
    Image URLs in display order, up to 99. Replaces the listing’s photos when present.

Returned by Lagoniko

  • idinteger
    Lagoniko’s listing id. The listingSync methods use the same number.
  • externalIdstring
    Your id.
  • statestring
    live on the portal, pending until what blockedBy names is sent, hidden, or archived after a delete.
  • blockedByarray of strings
    What the listing needs before it can go live, for example energyClass.
  • urlstring or null
    The public page while the listing is live. Always null with test credentials.
  • testboolean
    True for a listing made with test credentials.
  • referenceCodestring
    The agency’s code for the listing in the Lagoniko workspace.
  • location.areastring
    The Lagoniko area the coordinates were placed in.
  • photosinteger
    Photos ready on the listing.
  • warningsarray
    Fields that were ignored, such as an unknown feature code.
The listing object
{
  "id": 1000214,
  "externalId": "DOCS-1",
  "state": "live",
  "blockedBy": [],
  "test": false,
  "url": "https://lagoniko.ai/en/property/apartment-85-m-glyfada-1000214",
  "referenceCode": "KAL-0042",
  "status": "published",
  "transaction": "sale",
  "propertyType": "apartment",
  "price": 245000,
  "location": {
    "lat": 37.865,
    "lng": 23.755,
    "precision": "approximate",
    "area": "glyfada",
    "address": {
      "el": "Γλυφάδα",
      "en": "Glyfada"
    }
  },
  "size": 85,
  "rooms": {
    "bedrooms": 2,
    "bathrooms": 1,
    "wc": null,
    "livingRooms": null
  },
  "floor": {
    "number": 3,
    "to": null,
    "category": "3",
    "totalFloors": 5
  },
  "yearBuilt": 2004,
  "energyClass": "B",
  "features": [
    "balcony",
    "elevator",
    "parking"
  ],
  "title": {
    "el": "Διαμέρισμα 85 τ.μ., Γλυφάδα",
    "en": "Apartment, 85 m², Glyfada"
  },
  "photos": 0,
  "warnings": [],
  "createdAt": "2026-10-09T16:12:41.090Z",
  "updatedAt": "2026-10-09T16:12:41.090Z"
}
PUT/v1/listings/{externalId}

Create or replace a listing

Creates the listing the first time and replaces it after that. Sending the same body again changes nothing, so a request that timed out can simply be retried.

Fields left out are reset, as with any full replace. To change a few fields, use PATCH.

Path

  • externalIdstringRequired
    Your id for the listing. Letters, digits and . _ : / @ # -, up to 64 characters.

Body

The listing object. Required fields:

  • transactionstringRequired
    One of sale, rent.
  • propertyTypestringRequired
    One of apartment, maisonette, house, villa, studio, loft, building, commercial_building, office, shop, business_premises, showroom, warehouse, industrial_space, craft_space, hotel, parking, land, agricultural_land, island, other_land.
  • pricenumberRequired
    In euros. Monthly rent for a rental. Optional when priceOnRequest is true.
  • locationobjectRequired
    Where the property is. The area is read from the coordinates.
    Show 5 child attributes
    • latnumberRequired
      Latitude, WGS84.
    • lngnumberRequired
      Longitude, WGS84.
    • precisionstring
      exact shows the point and the street address. approximate (default) shows only the area.
    • addressstring or object
      Street address, or {"el", "en"}. Shown only with exact.
    • postalCodestring
  • sizenumberRequired
    Floor area in m². For land, 0 with plotSize.

Returns

The listing, with 201 when it was created and 200 otherwise.

PUT /v1/listings/{externalId}
curl -X PUT https://api.lagoniko.ai/v1/listings/DOCS-1 \
  -H "Authorization: Bearer $LAGONIKO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "transaction": "sale",
    "propertyType": "apartment",
    "price": 245000,
    "location": {
      "lat": 37.865,
      "lng": 23.755,
      "precision": "approximate"
    },
    "size": 85,
    "rooms": {
      "bedrooms": 2,
      "bathrooms": 1
    },
    "floor": {
      "number": 3,
      "totalFloors": 5
    },
    "yearBuilt": 2004,
    "energyClass": "B",
    "heating": {
      "system": "autonomous",
      "medium": "natural_gas"
    },
    "features": [
      "elevator",
      "balcony",
      "parking"
    ],
    "description": {
      "el": "Φωτεινό διαμέρισμα 85 τ.μ. στη Γλυφάδα, 300 μέτρα από τη θάλασσα.",
      "en": "Bright 85 m² apartment in Glyfada, 300 metres from the sea."
    }
  }'
Response201
{
  "id": 1000214,
  "externalId": "DOCS-1",
  "state": "live",
  "blockedBy": [],
  "test": false,
  "url": "https://lagoniko.ai/en/property/apartment-85-m-glyfada-1000214",
  "referenceCode": "KAL-0042",
  "status": "published",
  "transaction": "sale",
  "propertyType": "apartment",
  "price": 245000,
  "location": {
    "lat": 37.865,
    "lng": 23.755,
    "precision": "approximate",
    "area": "glyfada",
    "address": {
      "el": "Γλυφάδα",
      "en": "Glyfada"
    }
  },
  "size": 85,
  "rooms": {
    "bedrooms": 2,
    "bathrooms": 1,
    "wc": null,
    "livingRooms": null
  },
  "floor": {
    "number": 3,
    "to": null,
    "category": "3",
    "totalFloors": 5
  },
  "yearBuilt": 2004,
  "energyClass": "B",
  "features": [
    "balcony",
    "elevator",
    "parking"
  ],
  "title": {
    "el": "Διαμέρισμα 85 τ.μ., Γλυφάδα",
    "en": "Apartment, 85 m², Glyfada"
  },
  "photos": 0,
  "warnings": [],
  "createdAt": "2026-10-09T16:12:41.090Z",
  "updatedAt": "2026-10-09T16:12:41.090Z"
}
PATCH/v1/listings/{externalId}

Update a listing

Changes the fields in the body and keeps the rest. Objects are merged field by field: {"location": {"precision": "exact"}} keeps the coordinates. features and photos are replaced as a whole.

Path

  • externalIdstringRequired
    Your id for the listing.

Returns

The updated listing.

PATCH /v1/listings/{externalId}
curl -X PATCH https://api.lagoniko.ai/v1/listings/DOCS-1 \
  -H "Authorization: Bearer $LAGONIKO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "price": 239000,
    "features": [
      "elevator",
      "balcony",
      "parking",
      "sea_view"
    ]
  }'
Response200
{
  "id": 1000214,
  "externalId": "DOCS-1",
  "state": "live",
  "blockedBy": [],
  "test": false,
  "url": "https://lagoniko.ai/en/property/apartment-85-m-glyfada-1000214",
  "referenceCode": "KAL-0042",
  "status": "published",
  "transaction": "sale",
  "propertyType": "apartment",
  "price": 239000,
  "location": {
    "lat": 37.865,
    "lng": 23.755,
    "precision": "approximate",
    "area": "glyfada",
    "address": {
      "el": "Γλυφάδα",
      "en": "Glyfada"
    }
  },
  "size": 85,
  "rooms": {
    "bedrooms": 2,
    "bathrooms": 1,
    "wc": null,
    "livingRooms": null
  },
  "floor": {
    "number": 3,
    "to": null,
    "category": "3",
    "totalFloors": 5
  },
  "yearBuilt": 2004,
  "energyClass": "B",
  "features": [
    "balcony",
    "elevator",
    "parking",
    "sea_view"
  ],
  "title": {
    "el": "Διαμέρισμα 85 τ.μ., Γλυφάδα",
    "en": "Apartment, 85 m², Glyfada"
  },
  "photos": 0,
  "warnings": [],
  "createdAt": "2026-10-09T16:12:41.090Z",
  "updatedAt": "2026-10-09T16:12:41.090Z"
}
GET/v1/listings/{externalId}

Retrieve a listing

Returns a listing by your id. Deleted listings answer 404.

Path

  • externalIdstringRequired
    Your id for the listing.
GET /v1/listings/{externalId}
curl https://api.lagoniko.ai/v1/listings/DOCS-1 \
  -H "Authorization: Bearer $LAGONIKO_API_KEY"
Response200
{
  "id": 1000214,
  "externalId": "DOCS-1",
  "state": "live",
  "blockedBy": [],
  "test": false,
  "url": "https://lagoniko.ai/en/property/apartment-85-m-glyfada-1000214",
  "referenceCode": "KAL-0042",
  "status": "published",
  "transaction": "sale",
  "propertyType": "apartment",
  "price": 245000,
  "location": {
    "lat": 37.865,
    "lng": 23.755,
    "precision": "approximate",
    "area": "glyfada",
    "address": {
      "el": "Γλυφάδα",
      "en": "Glyfada"
    }
  },
  "size": 85,
  "rooms": {
    "bedrooms": 2,
    "bathrooms": 1,
    "wc": null,
    "livingRooms": null
  },
  "floor": {
    "number": 3,
    "to": null,
    "category": "3",
    "totalFloors": 5
  },
  "yearBuilt": 2004,
  "energyClass": "B",
  "features": [
    "balcony",
    "elevator",
    "parking"
  ],
  "title": {
    "el": "Διαμέρισμα 85 τ.μ., Γλυφάδα",
    "en": "Apartment, 85 m², Glyfada"
  },
  "photos": 0,
  "warnings": [],
  "createdAt": "2026-10-09T16:12:41.090Z",
  "updatedAt": "2026-10-09T16:12:41.090Z"
}
GET/v1/listings

List listings

Your listings, most recently changed first.

Query

  • limitinteger
    1 to 500. Default 50.
  • cursorstring
    The nextCursor of the previous page.
  • statestring
    Comma-separated live, pending, hidden, archived. All but archived by default.
  • updatedSincedate-time
    Only listings changed since then.
  • externalIdstring
    Comma-separated ids.
GET /v1/listings
curl https://api.lagoniko.ai/v1/listings?limit=20&state=live%2Cpending \
  -H "Authorization: Bearer $LAGONIKO_API_KEY"
Response200
{
  "data": [
    {
      "id": 1000214,
      "externalId": "DOCS-1",
      "state": "live",
      "blockedBy": [],
      "test": false,
      "url": "https://lagoniko.ai/en/property/apartment-85-m-glyfada-1000214",
      "referenceCode": "KAL-0042",
      "status": "published",
      "transaction": "sale",
      "propertyType": "apartment",
      "price": 245000,
      "location": {
        "lat": 37.865,
        "lng": 23.755,
        "precision": "approximate",
        "area": "glyfada",
        "address": {
          "el": "Γλυφάδα",
          "en": "Glyfada"
        }
      },
      "size": 85,
      "rooms": {
        "bedrooms": 2,
        "bathrooms": 1,
        "wc": null,
        "livingRooms": null
      },
      "floor": {
        "number": 3,
        "to": null,
        "category": "3",
        "totalFloors": 5
      },
      "yearBuilt": 2004,
      "energyClass": "B",
      "features": [
        "balcony",
        "elevator",
        "parking"
      ],
      "title": {
        "el": "Διαμέρισμα 85 τ.μ., Γλυφάδα",
        "en": "Apartment, 85 m², Glyfada"
      },
      "photos": 0,
      "warnings": [],
      "createdAt": "2026-10-09T16:12:41.090Z",
      "updatedAt": "2026-10-09T16:12:41.090Z"
    }
  ],
  "nextCursor": "MTc2MDAyNjM2MTA5MC42OGU3Y2UzOWE1YjY0ZjAw"
}
DELETE/v1/listings/{externalId}

Delete a listing

Takes the listing off the portal. A later PUT with the same id brings it back under the same id.

Path

  • externalIdstringRequired
    Your id for the listing.
DELETE /v1/listings/{externalId}
curl -X DELETE https://api.lagoniko.ai/v1/listings/DOCS-1 \
  -H "Authorization: Bearer $LAGONIKO_API_KEY"
Response204
204 No Content
POST/v1/listings/{externalId}/renew

Renew a listing

Confirms the listing is still available. Buyers see how recently a listing was confirmed.

Path

  • externalIdstringRequired
    Your id for the listing.
POST /v1/listings/{externalId}/renew
curl -X POST https://api.lagoniko.ai/v1/listings/DOCS-1/renew \
  -H "Authorization: Bearer $LAGONIKO_API_KEY"
Response204
204 No Content
PUT/v1/listings/{externalId}/photos

Set photos

Makes the listing’s photos exactly these URLs, in this order. Unchanged URLs keep their photo; new ones are downloaded in the background, usually within seconds.

JPEG, PNG, WebP, GIF or AVIF, up to 25 MB each, 99 per listing. The same image sent again is stored once.

Path

  • externalIdstringRequired
    Your id for the listing.

Body

  • photosarray of stringsRequired
    Image URLs in display order.

Returns

Each slot with its status: pending, processing, ready or failed with an error that says why.

PUT /v1/listings/{externalId}/photos
curl -X PUT https://api.lagoniko.ai/v1/listings/DOCS-1/photos \
  -H "Authorization: Bearer $LAGONIKO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "photos": [
      "https://images.your-crm.gr/listings/2041/1.jpg",
      "https://images.your-crm.gr/listings/2041/2.jpg"
    ]
  }'
Response200
{
  "data": [
    {
      "slot": 1,
      "status": "ready",
      "source": "https://images.your-crm.gr/listings/2041/1.jpg",
      "url": "https://lagoniko.ai/uploads/properties/apartment-85-m-glyfada-1000214/2026/10/26070ac7954b1cdd-detail.webp"
    },
    {
      "slot": 2,
      "status": "pending",
      "source": "https://images.your-crm.gr/listings/2041/2.jpg",
      "url": null
    }
  ]
}
GET/v1/listings/{externalId}/photos

List photos

The listing’s photo slots and their status.

Path

  • externalIdstringRequired
    Your id for the listing.
GET /v1/listings/{externalId}/photos
curl https://api.lagoniko.ai/v1/listings/DOCS-1/photos \
  -H "Authorization: Bearer $LAGONIKO_API_KEY"
Response200
{
  "data": [
    {
      "slot": 1,
      "status": "failed",
      "source": "https://images.your-crm.gr/listings/2041/1.jpg",
      "url": null,
      "error": "The image URL answered 404."
    }
  ]
}
POST/v1/listings/batch

Batch create or replace

Up to 100 listings in one request, each with its externalId. Each succeeds or fails on its own; the response has one result per listing, in order.

Body

  • listingsarray of objectsRequired
    Listings, each with externalId.
POST /v1/listings/batch
curl -X POST https://api.lagoniko.ai/v1/listings/batch \
  -H "Authorization: Bearer $LAGONIKO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "listings": [
      {
        "externalId": "DOCS-1",
        "transaction": "sale",
        "propertyType": "apartment",
        "price": 245000,
        "location": {
          "lat": 37.865,
          "lng": 23.755,
          "precision": "approximate"
        },
        "size": 85,
        "rooms": {
          "bedrooms": 2,
          "bathrooms": 1
        },
        "floor": {
          "number": 3,
          "totalFloors": 5
        },
        "yearBuilt": 2004,
        "energyClass": "B",
        "heating": {
          "system": "autonomous",
          "medium": "natural_gas"
        },
        "features": [
          "elevator",
          "balcony",
          "parking"
        ],
        "description": {
          "el": "Φωτεινό διαμέρισμα 85 τ.μ. στη Γλυφάδα, 300 μέτρα από τη θάλασσα.",
          "en": "Bright 85 m² apartment in Glyfada, 300 metres from the sea."
        }
      },
      {
        "externalId": "DOCS-2",
        "transaction": "rent",
        "propertyType": "studio",
        "price": 650,
        "location": {
          "lat": 37.8186,
          "lng": 23.7745
        },
        "size": 32,
        "yearBuilt": 1998,
        "energyClass": "D",
        "description": {
          "el": "Γκαρσονιέρα στη Βούλα."
        }
      }
    ]
  }'
Response200
{
  "results": [
    {
      "index": 0,
      "externalId": "DOCS-1",
      "ok": true,
      "created": false,
      "id": 1000214,
      "state": "live",
      "blockedBy": [],
      "warnings": []
    },
    {
      "index": 1,
      "externalId": "DOCS-2",
      "ok": true,
      "created": true,
      "id": 1000215,
      "state": "live",
      "blockedBy": [],
      "warnings": []
    }
  ],
  "summary": {
    "received": 2,
    "succeeded": 2,
    "failed": 0
  }
}
GET/v1/me

Check your credentials

The credential you are calling with and its limits. A quick way to test a key.

GET /v1/me
curl https://api.lagoniko.ai/v1/me \
  -H "Authorization: Bearer $LAGONIKO_API_KEY"
Response200
{
  "credential": {
    "name": "Kalimera Homes",
    "keyId": "iF8voc2q00jAfxKT",
    "username": "kalimera-homes",
    "mode": "test"
  },
  "limits": {
    "requestsPerMinute": 1200,
    "batchSize": 100,
    "photosPerListing": 99
  },
  "announceNewListings": false
}
GET/v1/locate

Locate a point

The Lagoniko area a point would be placed in, without creating anything.

GET /v1/locate
curl https://api.lagoniko.ai/v1/locate?lat=37.865&lng=23.755 \
  -H "Authorization: Bearer $LAGONIKO_API_KEY"
Response200
{
  "area": {
    "slug": "glyfada",
    "name": {
      "el": "Γλυφάδα",
      "en": "Glyfada"
    }
  }
}
GET/v1/reference

Accepted values

Every accepted value of every coded field. Use it to check your mappings.

GET /v1/reference
curl https://api.lagoniko.ai/v1/reference \
  -H "Authorization: Bearer $LAGONIKO_API_KEY"
Response200
{
  "transaction": [
    "sale",
    "rent"
  ],
  "energyClass": [
    "A+",
    "A",
    "B+",
    "B",
    "C",
    "D",
    "E",
    "F",
    "G",
    "H",
    "exempt",
    "pending"
  ],
  "...": "..."
}

Errors

Every error has the same shape. code is stable and safe to branch on, details names each refused field, and requestId is what support asks for.

StatusCodeMeaning
400invalid_requestThe request is malformed: not JSON, a bad query parameter or id.
401unauthorizedNo API key, a wrong one, or a revoked one.
403forbiddenThe key is not allowed from this address.
404not_foundNo such listing or endpoint.
413payload_too_largeOver 10 MB. Send fewer listings per batch.
422validation_failedInvalid fields; details names each one.
429rate_limitedOver the limit. Wait Retry-After seconds.
500internal_errorNothing changed. Retry.

Responses carry X-RateLimit-Limit and X-RateLimit-Remaining; a 429 carries Retry-After.

Error
{
  "error": {
    "code": "validation_failed",
    "message": "The listing has 2 problems.",
    "details": [
      {
        "field": "propertyType",
        "code": "invalid_value",
        "message": "propertyType must be one of: apartment, maisonette, …"
      },
      {
        "field": "location.lat",
        "code": "out_of_range",
        "message": "location.lat must be at most 42.5."
      }
    ],
    "requestId": "req_1B-PuDAe5Aak"
  }
}

listingSync bridge

The listingSync v1.0 interface, answered by Lagoniko: XML-RPC over HTTPS at https://api.lagoniko.ai/listingSync/v1_0. A bridge written for it works unchanged.

Protocol

  • Every call carries the application key, the username and the secret. The application key is accepted as it is.
  • Method names are case-insensitive. UTF-8, ISO-8859-7 and Windows-1253 bodies are read by their XML declaration.
  • Every answer is HTTP 200; an error is a fault with a code.
  • Listing ids are Lagoniko’s integers. brokerListingID is yours and makes a repeated sync.newListing an update.
  • Bodies up to 40 MB, enough for a photo sent as base64.
system.listMethods
<?xml version="1.0"?>
<methodCall>
  <methodName>system.listMethods</methodName>
  <params/>
</methodCall>
Response
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
  <params>
    <param><value><array><data>
      <value><string>sync.newListing</string></value>
      <value><string>sync.editListing</string></value>
      <value><string>sync.deleteListing</string></value>
      <value><string>…</string></value>
      <value><string>system.multicall</string></value>
    </data></array></value></param>
  </params>
</methodResponse>
RPCsync.newListing

sync.newListing

sync.newListing(appKey, brokerId, username, password, listing)

Creates a listing and returns its id. When listingDetails.brokerListingID matches a listing you already sent, that listing is updated instead and its id is returned, so a bridge that lost a response can send the listing again.

Parameters

  • appKeystringRequired
    Any value. Kept for compatibility.
  • brokerIdintRequired
    Your id for the agent. 0 when you have none.
  • usernamestringRequired
  • passwordstringRequired
    The secret.
  • listingstructRequired

Returns int listing id

sync.newListing
<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
  <methodName>sync.newListing</methodName>
  <params>
    <param><value><string>APP-KEY</string></value></param>
    <param><value><int>0</int></value></param>
    <param><value><string>your-username</string></value></param>
    <param><value><string>your-secret</string></value></param>
    <param><value><struct>
      <member><name>location</name><value><struct>
        <member><name>latitude</name><value><string>37.8650</string></value></member>
        <member><name>longitude</name><value><string>23.7550</string></value></member>
        <member><name>geocodeType</name><value><string>offset</string></value></member>
      </struct></value></member>
      <member><name>propertyDetails</name><value><struct>
        <member><name>category</name><value><string>residential</string></value></member>
        <member><name>propertyType</name><value><string>apartment</string></value></member>
        <member><name>livingArea</name><value><int>85</int></value></member>
        <member><name>rooms</name><value><int>2</int></value></member>
        <member><name>fullBathrooms</name><value><int>1</int></value></member>
        <member><name>yearBuilt</name><value><int>2004</int></value></member>
      </struct></value></member>
      <member><name>detailedCharacteristics</name><value><struct>
        <member><name>floorNumber</name><value><int>3</int></value></member>
        <member><name>energyClass</name><value><string>b</string></value></member>
        <member><name>heatingController</name><value><string>autonomous</string></value></member>
        <member><name>elevator</name><value><string>yes</string></value></member>
        <member><name>balcony</name><value><string>yes</string></value></member>
      </struct></value></member>
      <member><name>listingDetails</name><value><struct>
        <member><name>listingType</name><value><string>for sale</string></value></member>
        <member><name>price</name><value><int>245000</int></value></member>
        <member><name>currency</name><value><string>eur</string></value></member>
        <member><name>published</name><value><string>yes</string></value></member>
        <member><name>brokerListingID</name><value><string>DOCS-1</string></value></member>
        <member><name>description</name><value><struct>
          <member><name>gr</name><value><string>Φωτεινό διαμέρισμα 85 τ.μ. στη Γλυφάδα.</string></value></member>
          <member><name>en</name><value><string>Bright 85 m² apartment in Glyfada.</string></value></member>
        </struct></value></member>
      </struct></value></member>
    </struct></value></param>
  </params>
</methodCall>
Response
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
  <params>
    <param><value><int>1000214</int></value></param>
  </params>
</methodResponse>
RPCsync.editListing

sync.editListing

sync.editListing(appKey, username, password, listingId, listing)

Changes the groups and fields present in the struct and keeps everything else.

Returns boolean true

sync.editListing
<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
  <methodName>sync.editListing</methodName>
  <params>
    <param><value><string>APP-KEY</string></value></param>
    <param><value><string>your-username</string></value></param>
    <param><value><string>your-secret</string></value></param>
    <param><value><int>1000214</int></value></param>
    <param><value><struct>
      <member><name>listingDetails</name><value><struct>
        <member><name>price</name><value><int>239000</int></value></member>
      </struct></value></member>
    </struct></value></param>
  </params>
</methodCall>
Response
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
  <params>
    <param><value><boolean>1</boolean></value></param>
  </params>
</methodResponse>
RPCsync.getListing

sync.getListing

sync.getListing(appKey, username, password, listingId)

The listing in the same groups you send, plus listingDetails.listingID, url and lastModified.

Returns struct listing

sync.getListing
<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
  <methodName>sync.getListing</methodName>
  <params>
    <param><value><string>APP-KEY</string></value></param>
    <param><value><string>your-username</string></value></param>
    <param><value><string>your-secret</string></value></param>
    <param><value><int>1000214</int></value></param>
  </params>
</methodCall>
Response
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
  <params>
    <param><value><struct>
      <member><name>listingDetails</name><value><struct>
        <member><name>listingID</name><value><int>1000214</int></value></member>
        <member><name>brokerListingID</name><value><string>DOCS-1</string></value></member>
        <member><name>listingType</name><value><string>for sale</string></value></member>
        <member><name>price</name><value><int>245000</int></value></member>
        <member><name>currency</name><value><string>eur</string></value></member>
        <member><name>published</name><value><string>yes</string></value></member>
      </struct></value></member>
    </struct></value></param>
  </params>
</methodResponse>
RPCsync.deleteListing

sync.deleteListing

sync.deleteListing(appKey, username, password, listingId)

Takes the listing off the portal. Sending it again with the same brokerListingID restores it under the same id.

Returns boolean true

sync.deleteListing
<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
  <methodName>sync.deleteListing</methodName>
  <params>
    <param><value><string>APP-KEY</string></value></param>
    <param><value><string>your-username</string></value></param>
    <param><value><string>your-secret</string></value></param>
    <param><value><int>1000214</int></value></param>
  </params>
</methodCall>
Response
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
  <params>
    <param><value><boolean>1</boolean></value></param>
  </params>
</methodResponse>
RPCsync.renewListing

sync.renewListing

sync.renewListing(appKey, username, password, listingId)

Confirms the listing is still available.

Returns boolean true

sync.renewListing
<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
  <methodName>sync.renewListing</methodName>
  <params>
    <param><value><string>APP-KEY</string></value></param>
    <param><value><string>your-username</string></value></param>
    <param><value><string>your-secret</string></value></param>
    <param><value><int>1000214</int></value></param>
  </params>
</methodCall>
Response
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
  <params>
    <param><value><boolean>1</boolean></value></param>
  </params>
</methodResponse>
RPCsync.searchListings

sync.searchListings

sync.searchListings(appKey, username, password, criteria?)

Your listings, most recently changed first. Optional criteria: brokerListingID, page from 1, perPage 1 to 500.

Returns array of struct

sync.searchListings
<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
  <methodName>sync.searchListings</methodName>
  <params>
    <param><value><string>APP-KEY</string></value></param>
    <param><value><string>your-username</string></value></param>
    <param><value><string>your-secret</string></value></param>
    <param><value><struct>
      <member><name>page</name><value><int>1</int></value></member>
      <member><name>perPage</name><value><int>100</int></value></member>
    </struct></value></param>
  </params>
</methodCall>
Response
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
  <params>
    <param><value><array><data>
      <value><struct>
        <member><name>listingID</name><value><int>1000214</int></value></member>
        <member><name>brokerListingID</name><value><string>DOCS-1</string></value></member>
        <member><name>published</name><value><string>yes</string></value></member>
        <member><name>status</name><value><string>published</string></value></member>
      </struct></value>
    </data></array></value></param>
  </params>
</methodResponse>
RPCsync.addImage

sync.addImage

sync.addImage(appKey, username, password, listingId, slot, image)

Puts a photo in a slot from 1 to 99; slot 1 is shown first. Send a URL, and the call returns at once while the photo is processed in the background, or the image itself as base64, processed during the call. A slot that already has the same URL is left as it is.

Returns int slot

sync.addImage
<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
  <methodName>sync.addImage</methodName>
  <params>
    <param><value><string>APP-KEY</string></value></param>
    <param><value><string>your-username</string></value></param>
    <param><value><string>your-secret</string></value></param>
    <param><value><int>1000214</int></value></param>
    <param><value><int>1</int></value></param>
    <param><value><string>https://images.your-crm.gr/listings/2041/1.jpg</string></value></param>
  </params>
</methodCall>
Response
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
  <params>
    <param><value><int>1</int></value></param>
  </params>
</methodResponse>
RPCsync.deleteImage

sync.deleteImage

sync.deleteImage(appKey, username, password, listingId, slot)

Removes the photo in a slot.

Returns boolean true

sync.deleteImage
<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
  <methodName>sync.deleteImage</methodName>
  <params>
    <param><value><string>APP-KEY</string></value></param>
    <param><value><string>your-username</string></value></param>
    <param><value><string>your-secret</string></value></param>
    <param><value><int>1000214</int></value></param>
    <param><value><int>1</int></value></param>
  </params>
</methodCall>
Response
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
  <params>
    <param><value><boolean>1</boolean></value></param>
  </params>
</methodResponse>
RPCsync.getImageList

sync.getImageList

sync.getImageList(appKey, username, password, listingId)

Each slot with the URL its photo is served from, or the URL you sent while it is still processing.

Returns struct slot to URL

sync.getImageList
<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
  <methodName>sync.getImageList</methodName>
  <params>
    <param><value><string>APP-KEY</string></value></param>
    <param><value><string>your-username</string></value></param>
    <param><value><string>your-secret</string></value></param>
    <param><value><int>1000214</int></value></param>
  </params>
</methodCall>
Response
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
  <params>
    <param><value><struct>
      <member><name>1</name><value><string>https://lagoniko.ai/uploads/properties/apartment-85-m-glyfada-1000214/2026/10/26070ac7954b1cdd-detail.webp</string></value></member>
    </struct></value></param>
  </params>
</methodResponse>
RPCsync.getImage

sync.getImage

sync.getImage(appKey, username, password, listingId, slot)

One slot’s status, pending, ready or failed, with the reason when it failed.

Returns struct

sync.getImage
<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
  <methodName>sync.getImage</methodName>
  <params>
    <param><value><string>APP-KEY</string></value></param>
    <param><value><string>your-username</string></value></param>
    <param><value><string>your-secret</string></value></param>
    <param><value><int>1000214</int></value></param>
    <param><value><int>1</int></value></param>
  </params>
</methodCall>
Response
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
  <params>
    <param><value><struct>
      <member><name>slot</name><value><int>1</int></value></member>
      <member><name>status</name><value><string>ready</string></value></member>
      <member><name>url</name><value><string>https://lagoniko.ai/uploads/…-detail.webp</string></value></member>
      <member><name>source</name><value><string>https://images.your-crm.gr/listings/2041/1.jpg</string></value></member>
    </struct></value></param>
  </params>
</methodResponse>
RPCsystem.multicall

system.multicall

Up to 200 calls in one request, run in order, so a listing and its photos can travel together. The answer has one entry per call: a one-element array for a result, a fault struct for a failure. Each call counts towards the rate limit.

system.multicall
batch = xmlrpc.client.MultiCall(api)
for listing in changed_listings:
    batch.sync.newListing("APP-KEY", 0, "your-username", secret, listing)
for result in batch():  # raises Fault at the first failed call
    print(result)

Listing structure

A listing is a struct of groups. Send the whole listing to sync.newListing, only what changed to sync.editListing. Flags are the strings "yes" and "no". Fields the interface defines and Lagoniko does not use are accepted and ignored.

location

  • latitude, longitudestring or doubleRequired
    The area is read from them.
  • geocodeTypestring
    exact shows the point and the street address. offset (default) and hidden show only the area.
  • streetAddressstruct
    {gr, en}, or streetAddressGR / streetAddressEN.
  • displayAddressyes / no
    no: the street address is not stored.
  • zipstring
  • geographyIdint
    Read only when there are no coordinates. Also areaID.

propertyDetails

  • categorystringRequired
    residential, commercial, land.
  • propertyTypestringRequired
    Residential: apartment, studio, maisonette, detached, villa, loft, bungalow, building. Commercial: office, store, warehouse, industrial, craft space, hotel, showroom, building, parking. Land: plot, parcel, island. Anything else is stored as the general type of its category.
  • livingAreaintRequired
    m². 0 for land, with lotSize.
  • lotSizeint
    Plot, m².
  • roomsint
    Bedrooms.
  • fullBathrooms, halfBathroomsint
    Bathrooms and WCs.
  • yearBuiltint
    Needed to go live, except for land and parking.

listingDetails

  • listingTypestringRequired
    for sale, for rent.
  • priceintRequired
    Euros. Monthly rent for a rental.
  • currencystring
    eur. Other currencies are refused.
  • brokerListingIDstring
    Your id, up to 64 characters. Send it: it turns a repeated sync.newListing into an update.
  • publishedyes / no
    no keeps the listing off the portal.
  • descriptionstruct
    {gr, en}, or descriptionGR / descriptionEN. Needed to go live.
  • titlestruct
    {gr, en}. Written for you when left out.
  • dateAvailablestring
    dd/mm/yyyy.
  • newDevelopmentyes / no
    Newly built.

detailedCharacteristics

  • floorNumberint or string
    A number, or basement, semi-basement, ground floor, elevated ground floor.
  • energyClassstring
    ap, a, bp, b, c to g, excemption, under_issuance. Needed to go live, except for land and parking.
  • heatingControllerstring
    autonomous, central, none. Also heatingSystem.
  • heatingMediumstring
    petrol, natural gas, gas, current, pellet, wood, stove, infrared, fan coil, teleheating, geothermal energy.
  • renovationYear, livingRooms, commonExpensesint
  • furnished, renovated, requiresRenovation, unfinished, penthouseyes / no
  • elevator, garage, storageSpace, balcony, garden, swimmingPool, fireplace, airConditioning, secureDoor, solarWaterHeating, alarm, doubleGlass, petsAllowed, attic, playroomyes / no
    Amenities. storageSpace may be a size in m².

links

  • virtualTourURL, videoURLstring
Listing struct
listing = {
    "location": {
        "latitude": "37.8650",
        "longitude": "23.7550",
        "geocodeType": "offset",
    },
    "propertyDetails": {
        "category": "residential",
        "propertyType": "apartment",
        "livingArea": 85,
        "rooms": 2,
        "fullBathrooms": 1,
        "yearBuilt": 2004,
    },
    "detailedCharacteristics": {
        "floorNumber": 3,
        "energyClass": "b",
        "heatingController": "autonomous",
        "elevator": "yes",
        "balcony": "yes",
    },
    "listingDetails": {
        "listingType": "for sale",
        "price": 245000,
        "currency": "eur",
        "published": "yes",
        "brokerListingID": "DOCS-1",
        "description": {
            "gr": "Φωτεινό διαμέρισμα 85 τ.μ. στη Γλυφάδα.",
            "en": "Bright 85 m² apartment in Glyfada.",
        },
    },
}

Faults

CodeMeaningWhat to do
100Authentication failedCheck the username and password.
101Credentials revokedAsk Lagoniko for new credentials.
102Address not allowedCall from an address registered for the credential.
103Too many failed loginsWait 15 minutes.
110Listing not foundThe id is not one of your listings, or it was deleted.
120Invalid listing dataThe message names the fields.
121Invalid photoSend an http(s) URL or base64 image data.
122Invalid parameterA listing id or slot is out of range.
140Too many requestsRetry after the seconds in the message.
500Internal errorNothing changed. Retry.
620Unknown methodCheck the method name.
623Wrong parametersThe number or types of the parameters do not match.
634Not a method callThe body is not an XML-RPC method call.
Fault
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
  <fault><value><struct>
    <member><name>faultCode</name><value><int>110</int></value></member>
    <member><name>faultString</name><value><string>Listing 1000214 was not found.</string></value></member>
  </struct></value></fault>
</methodResponse>