Developer docs menu

Endpoints

8 read-only endpoints under https://jokerprice.com/api/v1. All need Authorization: Bearer ss_…; all return JSON.

Summary

EndpointPurposeRequired input
GET/api/v1/marketsList marketsnone
GET/api/v1/markets/{slug}Get a market reportslug
GET/api/v1/metricsGet performance metricscity, or north, south, east and west
GET/api/v1/trendsGet daily trendscity
GET/api/v1/paceGet market pacecity
GET/api/v1/eventsList events and holidaysnone
GET/api/v1/listingsList listingscity
POST/api/v1/estimateEstimate revenuelatitude, 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

Shell
curl -H "Authorization: Bearer $JOKERPRICE_API_KEY" \
  "https://jokerprice.com/api/v1/markets"

Example response

200 OK, application/json
{
  "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

FieldMeaning
slugIdentifier used by every other endpoint.
listingsCollected listings for the destination, all sources.
sourcesListing counts from Gathern and Airbnb.
nightlyMedian, 25th and 75th percentile asking rate in SAR.
trackerCalendar-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

ParameterInRequiredDescription
slugpathYesLowercase market slug from List markets, e.g. riyadh, dubai, cairo.

Example request

Shell
curl -H "Authorization: Bearer $JOKERPRICE_API_KEY" \
  "https://jokerprice.com/api/v1/markets/riyadh"

Example response

200 OK, application/json
{
  "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

FieldMeaning
bedroomsMedian asking rate per bedroom count, for groups of at least 5 listings.
typesUp to 8 property types by listing count.
ratingAverage rating out of 10.
tracker.byWeekdayweekday 0 is Sunday. Booked nights, observed nights, occupancy and ADR.
tracker.byMonthperiod is observed, mixed or ahead (future nights already booked).
tracker.leadTimesBooked 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

ParameterInRequiredDescription
cityqueryNoMarket slug or name. Pass city, or all four of north, south, east and west.
north, south, east, westqueryNoRectangle in decimal degrees, up to 5 degrees across.
past_daysqueryNoNights to look back, 1–365. Default 30.
forward_daysqueryNoNights to look ahead, 1–365. Default 60.

Example request

Shell
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

200 OK, application/json
{
  "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

FieldMeaning
maturity"collecting" or "estimating". Treat occupancy and ADR as indicative only while collecting.
pastObserved nights, booked nights, occupancy, ADR, RevPAR and ADR × occupancy × 30.
forward.onTheBooksShare of upcoming observed nights that are already booked.
listingsTracked listings in scope, their median asking rate and bedroom and type mix (type ids).
seriesOne row per night: booked and eligible listings, occupancy and ADR.

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

ParameterInRequiredDescription
cityqueryYesMarket slug or name.

Example request

Shell
curl -H "Authorization: Bearer $JOKERPRICE_API_KEY" \
  "https://jokerprice.com/api/v1/pace?city=dubai"

Example response

200 OK, application/json
{
  "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

FieldMeaning
status"collecting" or "ready".
stayDatesstayDate, onTheBooks, eligible tracked nights, pickup7 and pickup14 (null without that much history).
curvelead (days before arrival 0–30), mean onTheBooks and how many stay dates it averages; null below three.
basisShares 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

ParameterInRequiredDescription
cityqueryNoMarket slug or name; omit for every event.
from, toqueryNoDate range, YYYY-MM-DD. Events overlapping the range are returned.
kindqueryNoComma-separated kinds: religious, national, school, season, sports, culture, business.

Example request

Shell
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

200 OK, application/json
{
  "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

FieldMeaning
eventsid, name (en, ar), kind, cities, start, end, certainty, sourceUrl, verifiedAt and an optional note.
certaintyWhat official and expected mean.
version, lastReviewedCalendar 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

ParameterInRequiredDescription
cityqueryYesMarket slug or name.
limitqueryNoListings per page, 1–500. Default 100.
cursorqueryNonextCursor from the previous page.

Example request

Shell
curl -H "Authorization: Bearer $JOKERPRICE_API_KEY" \
  "https://jokerprice.com/api/v1/listings?city=riyadh&limit=100"

Example response

200 OK, application/json
{
  "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

FieldMeaning
listingKeysource:id. Stable across collections and used as the cursor.
typeIdProperty type id (table below).
nightlyLast asking nightly rate in SAR, before fees.
rating, reviewsRating out of 10 and review count, where the platform shows them.
updatedAtWhen 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

ParameterInRequiredDescription
latitude, longitudebodyYesProperty location in decimal degrees.
radiusKmbodyNoComparable radius, 0.5–20 km. Default 3.
bedroomsbodyNoExact bedroom count 1–6, or 0 for any. Default 0.
typeIdbodyNoProperty type id (see below) or "all". Default "all".
investmentbodyNoOptional. purchasePrice, downPaymentPct (default 25), loanRatePct (6), loanTermYears (25), setupCost, monthlyFixedCosts, platformFeePct (15), cleaningPerStay, avgStayNights (2), managementFeePct. Percentages are whole numbers (6 = 6%).
compsbodyNoOptional. 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

Shell
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

200 OK, application/json
{
  "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

FieldMeaning
askingCount and quartiles of the comparables' asking rates.
adr, occupancyValue used and its basis, so you can tell measured figures from fallbacks.
projectionMonthly (× 30) and annual (× 365) revenue, or null without measured occupancy.
rangeThe projection at the 25th and 75th percentile asking rate.
scenarios40%, 55% and 70% occupancy cases when occupancy is not measured.
comparablesUp to 12 nearest comparables with distance in km.
candidatesThe 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.
selectionWhether 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

Request body
{
  "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:

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": []
  }
}