Endpoints
8 read-only endpoints under https://jokerprice.com/api/v1. All need Authorization: Bearer ss_…; all return JSON.
Summary
| Endpoint | Purpose | Required input |
|---|---|---|
| GET/api/v1/markets | List markets | none |
| GET/api/v1/markets/{slug} | Get a market report | slug |
| GET/api/v1/metrics | Get performance metrics | city, or north, south, east and west |
| GET/api/v1/trends | Get daily trends | city |
| GET/api/v1/pace | Get market pace | city |
| GET/api/v1/events | List events and holidays | none |
| GET/api/v1/listings | List listings | city |
| POST/api/v1/estimate | Estimate revenue | latitude, longitude |
List markets
GET/api/v1/markets
Every destination with at least 20 collected listings, sorted by listing count. tracker is null until a destination has tracked calendars; its occupancy, ADR and revenue are meaningful once maturity is "estimating".
No parameters.
Example request
curl -H "Authorization: Bearer $JOKERPRICE_API_KEY" \
"https://jokerprice.com/api/v1/markets"Example response
{
"markets": [
{
"slug": "riyadh",
"name": "Riyadh",
"latitude": 24.7136,
"longitude": 46.6753,
"listings": 9412,
"sources": {
"gathern": 7650,
"airbnb": 1762
},
"nightly": {
"median": 420,
"p25": 300,
"p75": 650
},
"tracker": {
"maturity": "estimating",
"trackingDays": 41,
"tracked": 812,
"occupancy": 0.47,
"adr": 512.4,
"revpar": 240.8,
"monthlyRevenuePerListing": 7225,
"onTheBooks": 0.18
}
},
{
"slug": "jeddah",
"name": "Jeddah",
"latitude": 21.4858,
"longitude": 39.1925,
"listings": 6120,
"sources": {
"gathern": 5011,
"airbnb": 1109
},
"nightly": {
"median": 450,
"p25": 320,
"p75": 700
},
"tracker": null
}
]
}Key fields
| Field | Meaning |
|---|---|
slug | Identifier used by every other endpoint. |
listings | Collected listings for the destination, all sources. |
sources | Listing counts from Gathern and Airbnb. |
nightly | Median, 25th and 75th percentile asking rate in SAR. |
tracker | Calendar-tracking summary over the last 90 nights, or null. |
Get a market report
GET/api/v1/markets/{slug}
The full report behind a public /market-data page: supply by source, asking-rate quartiles, median asking rate by bedroom count (groups of 5 or more), property mix, average rating (0–10) and, when tracked, 90-day occupancy, ADR, RevPAR, revenue per listing and weekday, monthly and lead-time breakdowns.
Parameters
| Parameter | In | Required | Description |
|---|---|---|---|
slug | path | Yes | Lowercase market slug from List markets, e.g. riyadh, dubai, cairo. |
Example request
curl -H "Authorization: Bearer $JOKERPRICE_API_KEY" \
"https://jokerprice.com/api/v1/markets/riyadh"Example response
{
"market": {
"slug": "riyadh",
"name": "Riyadh",
"latitude": 24.7136,
"longitude": 46.6753,
"listings": 9412,
"sources": {
"gathern": 7650,
"airbnb": 1762
},
"nightly": {
"median": 420,
"p25": 300,
"p75": 650
},
"bedrooms": [
{
"bedrooms": 1,
"listings": 2210,
"median": 300
},
{
"bedrooms": 2,
"listings": 3105,
"median": 420
},
{
"bedrooms": 3,
"listings": 1980,
"median": 600
}
],
"types": [
{
"type": "Apartment",
"count": 5120
},
{
"type": "Chalet",
"count": 1870
},
{
"type": "Villa",
"count": 990
}
],
"rating": 8.9,
"tracker": {
"maturity": "estimating",
"trackingDays": 41,
"tracked": 812,
"occupancy": 0.47,
"adr": 512.4,
"revpar": 240.8,
"monthlyRevenuePerListing": 7225,
"onTheBooks": 0.18,
"observedNights": 30122,
"byMonth": [
{
"month": "2026-09",
"period": "observed",
"bookedNights": 11920,
"nights": 24800,
"occupancy": 0.48,
"adr": 505
}
],
"byWeekday": [
{
"weekday": 4,
"bookedNights": 2410,
"nights": 3900,
"occupancy": 0.62,
"adr": 560
}
],
"leadTimes": [
{
"label": "0–1 days",
"nights": 3120
},
{
"label": "2–7 days",
"nights": 4800
}
]
}
}
}Key fields
| Field | Meaning |
|---|---|
bedrooms | Median asking rate per bedroom count, for groups of at least 5 listings. |
types | Up to 8 property types by listing count. |
rating | Average rating out of 10. |
tracker.byWeekday | weekday 0 is Sunday. Booked nights, observed nights, occupancy and ADR. |
tracker.byMonth | period is observed, mixed or ahead (future nights already booked). |
tracker.leadTimes | Booked nights by how far ahead they were booked. |
Get performance metrics
GET/api/v1/metrics
Occupancy, ADR and revenue from daily calendar tracking for a city or a map rectangle. past covers the nights before today; forward is the share of upcoming nights already booked. series has one row per night. maturity stays "collecting" until there are 7 days of history and 100 observed listing-nights.
Parameters
| Parameter | In | Required | Description |
|---|---|---|---|
city | query | No | Market slug or name. Pass city, or all four of north, south, east and west. |
north, south, east, west | query | No | Rectangle in decimal degrees, up to 5 degrees across. |
past_days | query | No | Nights to look back, 1–365. Default 30. |
forward_days | query | No | Nights to look ahead, 1–365. Default 60. |
Example request
curl -H "Authorization: Bearer $JOKERPRICE_API_KEY" \
"https://jokerprice.com/api/v1/metrics?city=riyadh&past_days=30&forward_days=60"
# Or a map rectangle
curl -H "Authorization: Bearer $JOKERPRICE_API_KEY" \
"https://jokerprice.com/api/v1/metrics?north=24.85&south=24.70&east=46.80&west=46.60"Example response
{
"metrics": {
"source": "all",
"today": "2026-10-28",
"from": "2026-09-28",
"to": "2026-12-27",
"trackingDays": 41,
"maturity": "estimating",
"listings": {
"tracked": 812,
"checked": 806,
"medianAskingNightly": 430,
"bedrooms": [
{
"value": "2",
"count": 301
},
{
"value": "1",
"count": 244
}
],
"types": [
{
"value": "6",
"count": 520
},
{
"value": "2",
"count": 160
}
]
},
"past": {
"nights": 24180,
"bookedNights": 11365,
"occupancy": 0.47,
"adr": 512.4,
"revpar": 240.8,
"monthlyRevenuePerListing": 7225
},
"forward": {
"nights": 48360,
"bookedNights": 8705,
"onTheBooks": 0.18
},
"byWeekday": [
{
"weekday": 0,
"bookedNights": 1450,
"nights": 3460,
"occupancy": 0.42,
"adr": 480
},
{
"weekday": 4,
"bookedNights": 2410,
"nights": 3460,
"occupancy": 0.7,
"adr": 560
}
],
"byMonth": [
{
"month": "2026-10",
"period": "mixed",
"bookedNights": 10220,
"nights": 21900,
"occupancy": 0.47,
"adr": 510
}
],
"leadTimes": [
{
"label": "0–1 days",
"nights": 3120
},
{
"label": "2–7 days",
"nights": 4800
},
{
"label": "8–14 days",
"nights": 1900
}
],
"series": [
{
"night": "2026-10-27",
"past": true,
"booked": 401,
"eligible": 806,
"occupancy": 0.4975,
"adr": 498.2
}
]
}
}Key fields
| Field | Meaning |
|---|---|
maturity | "collecting" or "estimating". Treat occupancy and ADR as indicative only while collecting. |
past | Observed nights, booked nights, occupancy, ADR, RevPAR and ADR × occupancy × 30. |
forward.onTheBooks | Share of upcoming observed nights that are already booked. |
listings | Tracked listings in scope, their median asking rate and bedroom and type mix (type ids). |
series | One row per night: booked and eligible listings, occupancy and ADR. |
Get daily trends
GET/api/v1/trends
One stored daily snapshot per destination, as a time series for one metric. Occupancy, ADR and RevPAR in each snapshot cover the 30 nights before that day; on_the_books covers the 30 nights after it. changes compares the latest value with 7, 30 and 90 days earlier once that much history exists; yearOverYear stays null until a full year is stored.
Parameters
| Parameter | In | Required | Description |
|---|---|---|---|
city | query | Yes | Market slug or name. |
metric | query | No | occupancy (default), adr, revpar, asking, listings, tracked or on_the_books. |
source | query | No | all (default), gathern or airbnb. |
days | query | No | Days of history to return, 7–1100. Default 365. |
Example request
curl -H "Authorization: Bearer $JOKERPRICE_API_KEY" \
"https://jokerprice.com/api/v1/trends?city=riyadh&metric=occupancy&days=90"Example response
{
"trends": {
"metric": "occupancy",
"label": "Occupancy",
"unit": "share",
"source": "all",
"days": 365,
"windowNights": 30,
"today": "2026-10-28",
"destination": {
"slug": "riyadh",
"name": "Riyadh"
},
"sources": [
"all",
"gathern",
"airbnb"
],
"points": [
{
"day": "2026-10-27",
"value": 0.46,
"origin": "daily",
"observedNights": 23950
},
{
"day": "2026-10-28",
"value": 0.47,
"origin": "daily",
"observedNights": 24180
}
],
"changes": [],
"yearOverYear": null,
"supply": {
"latest": {
"day": "2026-10-28",
"value": 9412,
"tracked": 812
},
"first": {
"day": "2026-10-27",
"value": 9390,
"tracked": 806
},
"changes": [],
"points": [
{
"day": "2026-10-28",
"value": 9412,
"tracked": 812
}
]
},
"history": {
"days": 2,
"firstDay": "2026-10-27",
"dailySince": "2026-10-27",
"backfilledDays": 0
},
"notice": "Only 2 days of history so far (since 2026-10-27). JokerPrice stores one snapshot a day, so trends firm up over the coming weeks; year-over-year appears after a full year."
}
}Key fields
| Field | Meaning |
|---|---|
points | day, value and the number of observed nights behind it. origin is daily or backfill. metric=asking adds p25 and p75. |
changes | Change versus 7, 30 and 90 days earlier, where history allows. |
supply | Stored and tracked listing counts over time. |
history | Days of history, the first day and how many days were backfilled. |
notice | A plain-language note when history is short, otherwise null. |
Get market pace
GET/api/v1/pace
Booking pace from daily snapshots. For each stay date in the next 30 days: onTheBooks is the booked share of tracked nights at the latest snapshot, and pickup7 and pickup14 are how much that share rose over the previous 7 and 14 days. curve averages the booked share by days before arrival. status stays "collecting" until 7 days of snapshots exist.
Parameters
| Parameter | In | Required | Description |
|---|---|---|---|
city | query | Yes | Market slug or name. |
Example request
curl -H "Authorization: Bearer $JOKERPRICE_API_KEY" \
"https://jokerprice.com/api/v1/pace?city=dubai"Example response
{
"pace": {
"destination": "dubai",
"today": "2026-11-20",
"snapshotDays": 21,
"minSnapshotDays": 7,
"basis": "tracked public calendars (estimate)",
"status": "ready",
"latestSnapshot": "2026-11-20",
"stayDates": [
{
"stayDate": "2026-11-27",
"onTheBooks": 0.41,
"eligible": 1180,
"pickup7": 0.09,
"pickup14": 0.15
}
],
"curve": [
{
"lead": 0,
"onTheBooks": 0.52,
"stayDates": 14
},
{
"lead": 7,
"onTheBooks": 0.4,
"stayDates": 14
}
]
}
}Key fields
| Field | Meaning |
|---|---|
status | "collecting" or "ready". |
stayDates | stayDate, onTheBooks, eligible tracked nights, pickup7 and pickup14 (null without that much history). |
curve | lead (days before arrival 0–30), mean onTheBooks and how many stay dates it averages; null below three. |
basis | Shares come from public calendars, so they are estimates. |
List events and holidays
GET/api/v1/events
The sourced calendar of local holidays and events used by event pricing rules. Each event has English and Arabic names, a kind, the cities it covers (all-sa for all of Saudi Arabia), inclusive start and end dates, a certainty and its source. "expected" dates (for example Hijri dates before the moon-sighting announcement) can move.
Parameters
| Parameter | In | Required | Description |
|---|---|---|---|
city | query | No | Market slug or name; omit for every event. |
from, to | query | No | Date range, YYYY-MM-DD. Events overlapping the range are returned. |
kind | query | No | Comma-separated kinds: religious, national, school, season, sports, culture, business. |
Example request
curl -H "Authorization: Bearer $JOKERPRICE_API_KEY" \
"https://jokerprice.com/api/v1/events?city=riyadh&from=2026-11-01&to=2027-03-31"Example response
{
"version": "2026-10-28.2",
"lastReviewed": "2026-10-28",
"coverage": {
"start": "2026-01-01",
"end": "2027-12-31"
},
"certainty": {
"official": "Published by the authority or organiser itself on its own site.",
"expected": "Computed (for example from the Umm al-Qura calendar), not fully announced, or reported only in the news; may move."
},
"count": 1,
"events": [
{
"id": "saudi-national-day-2026",
"name": {
"en": "Saudi National Day",
"ar": "اليوم الوطني السعودي"
},
"kind": "national",
"cities": [
"all-sa"
],
"start": "2026-09-23",
"end": "2026-09-23",
"certainty": "official",
"sourceUrl": "https://www.my.gov.sa/",
"verifiedAt": "2026-10-28"
}
]
}Key fields
| Field | Meaning |
|---|---|
events | id, name (en, ar), kind, cities, start, end, certainty, sourceUrl, verifiedAt and an optional note. |
certainty | What official and expected mean. |
version, lastReviewed | Calendar version and the date it was last reviewed. |
List listings
GET/api/v1/listings
Collected listings for a destination, ordered by listingKey. source is gathern, airbnb or agoda. nightly is the last asking rate seen in SAR before fees; rating is out of 10 (Airbnb ratings are doubled). Keep requesting with cursor=nextCursor until nextCursor is null.
Parameters
| Parameter | In | Required | Description |
|---|---|---|---|
city | query | Yes | Market slug or name. |
limit | query | No | Listings per page, 1–500. Default 100. |
cursor | query | No | nextCursor from the previous page. |
Example request
curl -H "Authorization: Bearer $JOKERPRICE_API_KEY" \
"https://jokerprice.com/api/v1/listings?city=riyadh&limit=100"Example response
{
"listings": [
{
"id": "48213",
"source": "gathern",
"sourceListingId": "48213",
"listingKey": "gathern:48213",
"title": "Modern 2BR in Al Malqa",
"city": "Riyadh",
"district": "Al Malqa",
"typeId": "6",
"latitude": 24.8094,
"longitude": 46.6112,
"bedrooms": 2,
"area": 120,
"nightly": 420,
"rating": 9.4,
"reviews": 87,
"url": "https://gathern.co/view/1234/unit/48213",
"updatedAt": "2026-10-27T21:14:03.000Z"
}
],
"nextCursor": "gathern:48213"
}Key fields
| Field | Meaning |
|---|---|
listingKey | source:id. Stable across collections and used as the cursor. |
typeId | Property type id (table below). |
nightly | Last asking nightly rate in SAR, before fees. |
rating, reviews | Rating out of 10 and review count, where the platform shows them. |
updatedAt | When the listing was last collected. |
Estimate revenue
POST/api/v1/estimate
The revenue calculator. Comparables are stored listings within the radius that match bedrooms and type. ADR uses booked-night prices from tracked calendars nearby (or within 20 km) once mature, otherwise the comparables' median asking rate. Without measured occupancy, projection is null and scenarios holds 40%, 55% and 70% occupancy cases. Add an investment object to get cash flow, cap rate and payback for the same projection.
Parameters
| Parameter | In | Required | Description |
|---|---|---|---|
latitude, longitude | body | Yes | Property location in decimal degrees. |
radiusKm | body | No | Comparable radius, 0.5–20 km. Default 3. |
bedrooms | body | No | Exact bedroom count 1–6, or 0 for any. Default 0. |
typeId | body | No | Property type id (see below) or "all". Default "all". |
investment | body | No | Optional. purchasePrice, downPaymentPct (default 25), loanRatePct (6), loanTermYears (25), setupCost, monthlyFixedCosts, platformFeePct (15), cleaningPerStay, avgStayNights (2), managementFeePct. Percentages are whole numbers (6 = 6%). |
comps | body | No | Optional. 3–50 key values from candidates. The estimate then uses only those listings: asking prices, and booked-night ADR and occupancy from their own tracked calendars once they reach 7 days and 100 observed nights, with no wider fallback. Keys that are no longer among the candidates are left out and counted in selection.ignored. |
Property types
1 Resort, 2 Chalet, 3 Rest house, 4 Farm, 5 Camp, 6 Apartment, 7 Villa, 8 Room, 9 Studio, 11 Serviced apartment
Example request
curl -X POST -H "Authorization: Bearer $JOKERPRICE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"latitude":24.7743,"longitude":46.7386,"radiusKm":3,"bedrooms":3,"typeId":"7"}' \
"https://jokerprice.com/api/v1/estimate"Example response
{
"estimate": {
"input": {
"latitude": 24.7743,
"longitude": 46.7386,
"radiusKm": 3,
"bedrooms": 3,
"typeId": "7"
},
"asking": {
"count": 64,
"median": 900,
"p25": 700,
"p75": 1200
},
"adr": {
"value": 860,
"basis": "booked nights nearby"
},
"occupancy": {
"value": 0.44,
"basis": "tracked calendars nearby",
"trackingDays": 41,
"trackedNearby": 58
},
"projection": {
"occupancy": 0.44,
"adr": 860,
"monthly": 11352,
"annual": 138116
},
"range": {
"low": {
"occupancy": 0.44,
"adr": 700,
"monthly": 9240,
"annual": 112420
},
"high": {
"occupancy": 0.44,
"adr": 1200,
"monthly": 15840,
"annual": 192720
}
},
"scenarios": [],
"seasonality": [
{
"month": "2026-09",
"period": "observed",
"occupancy": 0.41,
"adr": 840,
"revenue": 10332
}
],
"comparables": [
{
"id": "50991",
"source": "gathern",
"title": "Villa with pool",
"nightly": 950,
"bedrooms": 3,
"typeId": "7",
"rating": 9.1,
"url": "https://gathern.co/view/2211/unit/50991",
"latitude": 24.771,
"longitude": 46.741,
"distanceKm": 0.43
}
],
"selection": {
"mode": "all",
"status": "ok",
"inRadius": 64,
"candidates": 50,
"kept": 50,
"requested": 0,
"ignored": 0,
"minimum": 3,
"maximum": 50
},
"candidates": [
{
"key": "gathern:50991",
"ref": "3f9c2a7e01b4",
"kept": true,
"source": "gathern",
"title": "Villa with pool",
"url": "https://gathern.co/view/2211/unit/50991",
"nightly": 950,
"checkIn": "2026-10-29",
"bedrooms": 3,
"typeId": "7",
"rating": {
"value": 9.1,
"scale": 10
},
"reviews": 42,
"distanceKm": 0.43,
"position": "within",
"tracked": {
"since": "2026-09-14T06:00:00.000Z",
"observedNights": 44,
"bookedNights": 19,
"minNights": 30,
"occupancy": 0.4318,
"adr": 905
}
}
]
}
}Key fields
| Field | Meaning |
|---|---|
asking | Count and quartiles of the comparables' asking rates. |
adr, occupancy | Value used and its basis, so you can tell measured figures from fallbacks. |
projection | Monthly (× 30) and annual (× 365) revenue, or null without measured occupancy. |
range | The projection at the 25th and 75th percentile asking rate. |
scenarios | 40%, 55% and 70% occupancy cases when occupancy is not measured. |
comparables | Up to 12 nearest comparables with distance in km. |
candidates | The 50 nearest comparables, each with its key, whether it was kept, its asking rate and the night it was asked for, its rating on its platform's scale, its position against the middle half of the asking rates used, and its own tracked calendar over the last 90 nights. |
selection | Whether the estimate used every comparable in the radius (all) or a chosen set (chosen), with the counts; status is too-few when fewer than 3 chosen keys matched. |
With investment inputs
{
"latitude": 24.7743,
"longitude": 46.7386,
"bedrooms": 3,
"typeId": "7",
"investment": {
"purchasePrice": 1500000,
"downPaymentPct": 30,
"loanRatePct": 6,
"loanTermYears": 25,
"monthlyFixedCosts": 900,
"platformFeePct": 15,
"cleaningPerStay": 120,
"avgStayNights": 2
}
}The response gains estimate.investment:
{
"investment": {
"inputs": {
"purchasePrice": 1500000,
"downPaymentPct": 30,
"loanRatePct": 6,
"loanTermYears": 25,
"monthlyFixedCosts": 900,
"platformFeePct": 15,
"cleaningPerStay": 120,
"avgStayNights": 2,
"setupCost": 0,
"managementFeePct": 0
},
"basis": "projection",
"projection": {
"occupancy": 0.44,
"adr": 860,
"revenue": 138116,
"expenses": {
"platformFees": 20717,
"management": 0,
"cleaning": 9636,
"fixed": 10800
},
"operatingExpenses": 41153,
"netOperatingIncome": 96963,
"capRate": 0.0646,
"loanAmount": 1050000,
"annualDebtService": 81181,
"cashInvested": 450000,
"annualCashFlow": 15782,
"monthlyCashFlow": 1315,
"cashOnCash": 0.0351,
"paybackYears": 28.5,
"breakEvenOccupancy": 0.3756
},
"scenarios": []
}
}