📈 KSA Land Data

API documentation

REST, JSON, key-based auth. Base URL https://ksalanddata.com/v1. Background: where the data comes from, pulling comparables, coverage.

Quickstart

This call needs no key:

curl https://ksalanddata.com/v1/meta
{
 "dataset": "moj-sales",
 "records": 1474665,
 "quarters": ["2020Q1", "2020Q2", "2020Q3", "2020Q4", "2021Q1", "2021Q2", "2021Q3", "2021Q4", "2022Q1", "2022Q2", "2022Q3", "2022Q4", "2023Q1", "2023Q2", "2023Q3", "2023Q4", "2024Q1", "2024Q2", "2024Q3", "2024Q4", "2025Q1", "2025Q2", "2025Q3", "2025Q4", "2026Q1", "2026Q2"],
 "regions": 13,
 "cities": 175,
 "source": "Saudi Ministry of Justice via the Saudi Open Data Portal (open.data.gov.sa)",
 "license": "Saudi Open Data License (ODC Attribution License): https://open.data.gov.sa/odp-public/static/ar/assets/Open_Data_License_Ar.pdf",
 "attribution": "Contains information from Ministry of Justice real-estate transactions (https://open.data.gov.sa), published on the Saudi Open Data Portal and in the Ministry's real-estate transactions report (moj.gov.sa), which is made available under the Saudi Open Data License (ODC Attribution License) (https://open.data.gov.sa/odp-public/static/ar/assets/Open_Data_License_Ar.pdf).",
 "built": "2026-10-14"
}
Get a free API key

500 requests/month. Aggregates + latest-quarter transactions. No card.

Your key works the same whether you tick this or not. Either way we email you about your key and your account: a welcome note, a notice if the key is replaced, and a warning when you near your monthly allowance.

Your API key is ready

This is the only time they will be shown. They are not emailed and cannot be displayed again.

The key (not the recovery code) is also kept in this browser, so the account page and the map fill it in on this device (a paid key already saved here is left in place).

API key


 

Recovery code: gets you a new key on the account page if you lose this one


 

Copy both to continue.

curl -H "x-api-key: YOUR_KEY" "https://ksalanddata.com/v1/stats/regions?quarter=2026Q2"

Endpoints

OpenAPI spec: /openapi.json

GET /v1/meta

Coverage: quarters, record counts, region/city lists. No auth.

GET /v1/stats/regions

Quarterly aggregates for the 13 regions. Params: quarter (e.g. 2026Q2; default latest), classification (residential|commercial|agricultural|mixed|all, default all). Returns n, total_sar, median_price, median_psm, median_area per region.

GET /v1/stats/cities

Quarterly aggregates per city. Params: region (slug), city (slug), quarter, classification. One of region/city recommended.

GET /v1/stats/districts

District-level aggregates inside a city. Params: city (slug, required), quarter. Districts with fewer than 5 deals in a quarter are omitted.

GET /v1/usage

Your plan, monthly quota, and the requests you have made this month (UTC), counted exactly, with a per-day breakdown. A call shows up in the counts from the next one. used_estimate is the sampled counter the quota is enforced on; it can differ from used by a few requests.

{
 "tier": "starter", "month": "202609", "monthly_quota": 50000,
 "used": 1234, "remaining": 48766,
 "days": [{"day": "2026-09-14", "requests": 900}, {"day": "2026-09-15", "requests": 334}],
 "used_estimate": 1230, "remaining_estimate": 48770
}

GET /v1/logs

Your request log for the last 30 days, newest first: time (UTC), method, endpoint, query string, HTTP status, and how long we took in milliseconds. A request appears a few seconds after it is made. Params: limit (1–500, default 100), since (an ISO date or time, e.g. 2026-09-01), cursor (pass back next_cursor to get the next page; null means there is no more). The log never holds your key or your IP address. Requests refused because the quota ran out are listed with status 429. Calls to /v1/usage and /v1/logs count against the quota like any other call, so once it is used up they are refused too until the 1st; the account page still shows your count.

curl -H "x-api-key: YOUR_KEY" "https://ksalanddata.com/v1/logs?limit=2"
{
 "count": 2, "retention_days": 30, "next_cursor": 812,
 "logs": [
  {"time": "2026-09-15T08:12:03.417Z", "method": "GET", "endpoint": "/v1/transactions",
   "query": "city=riyadh&quarter=2026Q2&limit=100", "status": 200, "ms": 41},
  {"time": "2026-09-15T08:11:58.090Z", "method": "GET", "endpoint": "/v1/stats/regions",
   "query": "quarter=2026Q2", "status": 200, "ms": 6}
 ]
}

GET /v1/export

Pro plan only: the full dataset as one gzip-compressed CSV, the same file as the one-time dataset purchase. Columns are described in the data dictionary. Other tiers get 403.

Team plan: files and member keys

Team plan only; other tiers get 403. All keys of a Team account share one monthly quota of 1,000,000 calls, and each file download counts as one call.

GET /v1/files lists this quarter's release: every file with its size, sha256 and row count. Bulk CSV and Parquet for each quarter and the full window, the district time series, and one Excel workbook per city (plus all of them in one zip). Download one with the same header; an interrupted download resumes with a Range header:

curl -H "x-api-key: sk_..." -o 2026Q2.parquet https://ksalanddata.com/v1/files/bulk/parquet/2026Q2.parquet

Member keys belong to the key that bought Team (the owner key). The owner manages them: GET /v1/account/keys lists them, POST /v1/account/keys with {"label": "..."} adds one (up to 4, 5 keys in all; the new key is shown once), POST /v1/account/keys/<id>/rotate replaces one and DELETE /v1/account/keys/<id> removes one. A member key has no recovery code: if one is lost, the owner replaces it. When the plan ends, every key of the account loses access to the files at once.

GET /v1/transactions

Transaction-level records. Params: city (slug, required), quarter (required), classification, district (Arabic name as returned by /v1/stats/districts; a leading "حي" and alef/ya/ta-marbuta spelling variants are ignored), min_price, max_price, limit (≤1000), offset. Free tier: latest quarter only, limit ≤100. Paid: full history since 2020.

{
 "date": "2025-11-12",
 "region": "riyadh",
 "city": "riyadh",
 "district_ar": "الياسمين",
 "classification": "residential",
 "property_type": null,
 "properties_count": 1,
 "price_sar": 1250000.0,
 "area_sqm": 375.0,
 "price_per_sqm": 3333.33,
 "ref_no": "31982411"
}

Field notes

property_type (land, apartment, villa …) exists only where the source published it (2023 Q1–Q3). district_ar is the registry's Arabic district name; district-level English is on the roadmap. Prices are as registered; no adjustment. Quarters follow the deed's Gregorian date.

Lost or leaked keys

Keys are shown once at creation, together with a recovery code, and never emailed. Lost a key? Use the recovery code on the account page: you get a new key and a new code, and a paid plan moves with them. Leaked a key? Replace it on the same page; the old key stops working at once and your recovery code keeps working. A plan attaches to the key you paste at checkout. Lost both the key and the code? Write via the contact form; we reply only to the email the key was issued to.

Auth, limits, errors

Send x-api-key on every request. Monthly quotas: free 500, Starter 50,000, Pro 250,000. Responses: 401 missing/bad key, 403 endpoint above tier, 429 quota exceeded, 400 bad params. Quota resets on the 1st (UTC).

Coverage & caveats

1,474,665 sales deeds, 2020Q1–2026Q2. 2025Q2 comes from the portal's original release of that quarter (the file it serves now repeats 2024Q2); 2026 quarters come from the Ministry’s public real-estate transactions report, which carries the same deals. Transaction rows with an unparseable price or date, or an unknown region, are dropped. Sales registered on the Real Estate Registry (السجل العقاري) may not appear in the Ministry's published files and are not in this dataset; Riyadh from 2025 onward is materially affected. Contains information from Ministry of Justice real-estate transactions, published on the Saudi Open Data Portal and in the Ministry’s real-estate transactions report (moj.gov.sa), which is made available under the Saudi Open Data License (ODC Attribution License).