Scrappa's GET /api/kyero/search returns Kyero property listings for sale or rent in Spain, Portugal, Italy and France as structured JSON. Get location_id and location_slug from the autocomplete endpoint.
What you get
One request returns one page of up to 20 listings. Each listing has id, name, price, price_formatted, reference_no, bedrooms, bathrooms, built_m2, plot_m2, property_type, short_description, images, feature_keys, badges, video and virtual tour links, the listing agent, and the path that the property endpoint takes. The response also has location with its parent places, pagination, available_filters and alternate_searches (nearby and parent places with their ids).
Filters are honoured
Kyero silently ignores filter values that are not in its own lists. This API rejects such values with a 422 (unsupported_filter_value) before any lookup, and the rejection is not billed. Allowed values: prices from available_filters.price (sale and rent have different lists), rooms 1-10, built area 50, 100, 150 or 200 m2. Every returned listing is also checked against the filters you sent. A listing that breaks a filter is removed and never returned. applied_filters shows what was applied.
Pagination
page runs from 1 to 50 with 20 listings per page, so at most 1,000 listings per search are reachable. pagination.count is the full match count and pagination.reachable is the part you can page through. Narrow the search with filters or a smaller location to reach the rest. A page above 50 returns a non-billable 422. The response never returns one page's data under another page number.
Property types
property_type accepts any, apartments or villas. Town houses and country houses are not available yet.
Coordinates and fees
Kyero does not publish the exact position of a listing. The property endpoint returns the town centre and says so in coordinates_precision. Kyero publishes no fee fields and no price history.
Run this endpoint
Endpoint
Parameters
Start with the required fields, then add optional filters only when your use case needs them.
Runnable path
2 required parameters needed before sending a request.
15 optional filters available.
integer
Required
Location id from the autocomplete endpoint.
31673
string
Required
Location slug from the autocomplete endpoint.
marbella
string
Optional
sale (default) or rent.
sale
string
Optional
any (default), apartments or villas.
example
integer
Optional
A step from available_filters.price. Sale: 50000 to 20000000. Rent per month: 250 to 8000.
10
integer
Optional
A step from available_filters.price.
500000
integer
Optional
1 to 10.
3
integer
Optional
1 to 10.
10
integer
Optional
1 to 10.
10
integer
Optional
1 to 10.
10
integer
Optional
In m2: 50, 100, 150 or 200.
10
integer
Optional
In m2: 50, 100, 150 or 200.
10
string
Optional
Comma-separated, all required: pool, garage, terrace, garden, parking, disabled_access, lift, near_beach, near_shops, near_golf, near_transport.
example
boolean
Optional
true to return new builds only.
true
boolean
Optional
true to return resale properties only. Cannot be combined with new_build.
true
string
Optional
price_asc, price_desc or newest. Without it Kyero uses its default order.
price_asc
integer
Optional
Result page, 1 to 50.
1
Request Examples
<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://scrappa.co/api/kyero/search?location_id=31673&location_slug=marbella&operation=sale&min_beds=3&max_price=500000&sort=price_asc",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"x-api-key: YOUR_API_KEY_HERE"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
<?php
use Illuminate\Support\Facades\Http;
$response = Http::timeout(30)
->withHeaders(['x-api-key' => 'YOUR_API_KEY_HERE'])
->get('https://scrappa.co/api/kyero/search?location_id=31673&location_slug=marbella&operation=sale&min_beds=3&max_price=500000&sort=price_asc');
if ($response->successful()) {
echo $response->body();
} else {
echo "Error: " . $response->status();
}
const options = {
method: 'GET',
headers: {
'x-api-key': 'YOUR_API_KEY_HERE'
}
};
fetch('https://scrappa.co/api/kyero/search?location_id=31673&location_slug=marbella&operation=sale&min_beds=3&max_price=500000&sort=price_asc', options)
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.text();
})
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
const axios = require('axios');
const options = {
method: 'GET',
url: 'https://scrappa.co/api/kyero/search?location_id=31673&location_slug=marbella&operation=sale&min_beds=3&max_price=500000&sort=price_asc',
headers: {
x-api-key: 'YOUR_API_KEY_HERE',
}
};
try {
const response = await axios(options);
console.log(response.data);
} catch (error) {
console.error('Error:', error.message);
}
require 'net/http'
require 'uri'
uri = URI.parse("https://scrappa.co/api/kyero/search?location_id=31673&location_slug=marbella&operation=sale&min_beds=3&max_price=500000&sort=price_asc")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme == 'https'
request = Net::HTTP::Get.new(uri.request_uri)
request['x-api-key'] = 'YOUR_API_KEY_HERE'
begin
response = http.request(request)
puts response.body
rescue => e
puts "Error: #{e.message}"
end
import http.client
import json
conn = http.client.HTTPSConnection("scrappa.co")
headers = {
'x-api-key': 'YOUR_API_KEY_HERE',
}
try:
conn.request("GET", "/api/kyero/search?location_id=31673&location_slug=marbella&operation=sale&min_beds=3&max_price=500000&sort=price_asc", headers=headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
except Exception as e:
print(f"Error: {e}")
finally:
conn.close()
import requests
headers = {
'x-api-key': 'YOUR_API_KEY_HERE',
}
try:
response = requests.get('https://scrappa.co/api/kyero/search?location_id=31673&location_slug=marbella&operation=sale&min_beds=3&max_price=500000&sort=price_asc', headers=headers)
response.raise_for_status()
print(response.text)
except requests.exceptions.RequestException as e:
print(f"Error: {e}")
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;
public class ApiExample {
public static void main(String[] args) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://scrappa.co/api/kyero/search?location_id=31673&location_slug=marbella&operation=sale&min_beds=3&max_price=500000&sort=price_asc")
.addHeader("x-api-key", "YOUR_API_KEY_HERE")
.build();
try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful()) {
System.out.println(response.body().string());
} else {
System.out.println("Error: " + response.code());
}
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
}
}
}
package main
import (
"fmt"
"net/http"
"io/ioutil"
)
func main() {
client := &http.Client{}
req, err := http.NewRequest("GET", "https://scrappa.co/api/kyero/search?location_id=31673&location_slug=marbella&operation=sale&min_beds=3&max_price=500000&sort=price_asc", nil)
if err != nil {
fmt.Println("Error creating request:", err)
return
}
req.Header.Set("x-api-key", "YOUR_API_KEY_HERE")
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error making request:", err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error reading response:", err)
return
}
fmt.Println(string(body))
}
#!/bin/bash
curl -X GET \
-H "x-api-key: YOUR_API_KEY_HERE" \
"https://scrappa.co/api/kyero/search?location_id=31673&location_slug=marbella&operation=sale&min_beds=3&max_price=500000&sort=price_asc"
using System;
using System.Net.Http;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", "YOUR_API_KEY_HERE");
try
{
var response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, "https://scrappa.co/api/kyero/search?location_id=31673&location_slug=marbella&operation=sale&min_beds=3&max_price=500000&sort=price_asc"));
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine(content);
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
}
}
import axios from 'axios';
async function run(): Promise<void> {
try {
const response = await axios({
method: 'GET',
url: 'https://scrappa.co/api/kyero/search?location_id=31673&location_slug=marbella&operation=sale&min_beds=3&max_price=500000&sort=price_asc',
headers: {
'x-api-key': 'YOUR_API_KEY_HERE',
},
});
console.log(response.data);
} catch (error) {
console.error('Error:', error);
}
}
void run();
use reqwest::Client;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
let response = client
.get("https://scrappa.co/api/kyero/search?location_id=31673&location_slug=marbella&operation=sale&min_beds=3&max_price=500000&sort=price_asc")
.header("x-api-key", "YOUR_API_KEY_HERE")
.send()
.await?;
println!("{}", response.text().await?);
Ok(())
}
Response Schema
Example response fields are illustrative; inspect the JSON before integrating.
Example response fields
Scan these fields before integrating.
success
location
operation
applied_filters
listings
pagination
available_filters
alternate_searches
+2 more
Common listings fields
id
name
price
price_formatted
{
"success": true,
"location": {
"id": 31673,
"name": "Marbella",
"slug": "marbella",
"type": "City",
"name_with_country": "Marbella, Spain",
"nation_id": 55529,
"country": "es",
"latitude": 36.50978,
"longitude": -4.88525,
"hierarchy": [
{
"id": 29,
"name": "Malaga",
"slug": "malaga",
"type": "Province"
}
]
},
"operation": "sale",
"applied_filters": {
"operation": "sale",
"property_type": "any",
"sort": "price_asc",
"min_beds": 3,
"max_price": 500000
},
"listings": [
{
"id": 21361013,
"name": "Apartment in Marbella, Malaga",
"price": 350000,
"price_formatted": "\u20ac 350,000",
"payment_scheme": "for_sale",
"reference_no": "EI-AC2137",
"location_id": 31673,
"property_type": {
"id": 1,
"key": "apartment",
"group_id": 1
},
"bedrooms": 3,
"bathrooms": 2,
"built_m2": 100,
"plot_m2": 0,
"short_description": "Discover a collection of 34 extraordinary apartments and penthouses...",
"images": [
"https://img.kyero.com/crop/960x720/properties/21361/21361013/428410368.jpg"
],
"images_count": 31,
"feature_keys": [
"garage",
"lift",
"terrace",
"pool",
"new_build"
],
"badges": [
"video_tour",
"remote_viewing"
],
"primary_badge": "new_build",
"featured": false,
"virtual_tour_url": null,
"video_url": "https://vimeo.com/1025703918",
"remote_viewing_enabled": true,
"agent": {
"id": 14222,
"name": "Example Agency",
"logo_url": "https://img.kyero.com/fit/125x125/agents/logos/14/14222.jpg",
"type": "2",
"prime": true,
"path": "/en/spain/estate-agents/profile/example-agency-a14222",
"url": "https://www.kyero.com/en/spain/estate-agents/profile/example-agency-a14222"
},
"path": "/en/property/21361013-apartment-for-sale-marbella",
"url": "https://www.kyero.com/en/property/21361013-apartment-for-sale-marbella"
}
],
"pagination": {
"page": 1,
"pages": 8,
"per_page": 20,
"count": 143,
"reachable": 143,
"max_pages": 50,
"has_next": true
},
"available_filters": {
"price": [
50000,
75000,
100000
],
"beds": [
1,
2,
3
],
"baths": [
1,
2,
3
],
"build_size": [
50,
100,
150,
200
],
"features": [
"pool",
"garage"
],
"location_features": [
"near_beach"
],
"multimedia": [
"remote_viewing",
"video",
"virtual_tour"
]
},
"alternate_searches": {
"locations_nearby": [
{
"label": "Estepona",
"location_id": 31466,
"location_slug": "estepona",
"path": "/en/estepona-property-for-sale-0l31466"
}
]
},
"title": "Properties for sale in Marbella",
"meta": {
"billable": true,
"attempts": 1,
"last_status": 200,
"endpoint_family": "search",
"dropped_by_guard": 0
}
}
Errors
Handle these documented responses before retrying or showing customer-facing failures.
Unsupported Filter Value or Page
A price, room or size value that Kyero does not offer, an unusable parameter, or a page above 50 (`unsupported_filter_value`, `invalid_parameter`, `page_out_of_range`). Kyero ignores unknown values, so they are rejected before any lookup. Non-billable.
{
"meta": {
"billable": false,
"retryable": false,
"endpoint_family": "search"
},
"error": {
"code": "unsupported_filter_value",
"message": "max_build_size must be one of: 50, 100, 150, 200. Kyero ignores other values, so they are rejected."
},
"success": false
}Validation Error
A query parameter failed validation, or a path, id or slug is unusable (`invalid_parameter`). Non-billable.
{
"errors": {
"country": [
"The selected country is invalid."
]
},
"message": "The selected country is invalid."
}Upstream Unavailable
Kyero could not be reached after retries, answered a different page than requested, did not apply the filters, or answered with a body this API cannot read (`upstream_unavailable`, `upstream_blocked`, `pagination_mismatch`, `filter_not_honoured`, `parser_drift`). Retryable and never billed. Clients are never rate limited.
{
"meta": {
"attempts": 3,
"billable": false,
"retryable": true,
"last_status": 302,
"endpoint_family": "search"
},
"error": {
"code": "upstream_blocked",
"message": "Kyero rejected the request from our egress pool. Please retry."
},
"success": false
}Generate Code with AI
Copy a ready-made prompt with all the endpoint details, parameters, and example responses. Paste it into ChatGPT, Claude, or any AI assistant to instantly generate working code.
Try It Live
Test this endpoint in our interactive playground with real data.