REST, JSON, key-based auth. Base URL https://ksalanddata.com/v1. Background: where the data comes from, pulling comparables, coverage.
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"
}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.
curl -H "x-api-key: YOUR_KEY" "https://ksalanddata.com/v1/stats/regions?quarter=2026Q2"
Coverage: quarters, record counts, region/city lists. No auth.
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.
Quarterly aggregates per city. Params: region (slug), city (slug), quarter, classification. One of region/city recommended.
District-level aggregates inside a city. Params: city (slug, required), quarter. Districts with fewer than 5 deals in a quarter are omitted.
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
}
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}
]
}
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 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.
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"
}
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.
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.
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).
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).