Developer docs menu

API documentation

Read market reports, occupancy and revenue estimates, daily trends, collected listings and revenue projections for the Gulf and Egypt as JSON. Use it from spreadsheets, scripts, your own software, or AI assistants through the MCP server.

Authentication

Sign in, open Data & API, and create a key. Your plan sets how many active keys the account can hold (5 during the free trial). A key starts with ss_, is shown once, and is stored only as a hash, so copy it when you create it. Revoke a key there at any time; requests with it fail immediately.

Send the key in the Authorization header of every request. All responses are JSON over HTTPS.

Headers
Base URL: https://www.staytrend.ai

Authorization: Bearer ss_0123456789abcdef0123456789abcdef01234567

Start free trial

Rate limits

Limits are per account, and all of its keys share them. During the free trial the account may make 120 requests per minute and 25,000 per UTC day; each plan sets its own, listed on API pricing. Requests over the limit return 429 with a Retry-After header in seconds. After the trial without a plan, requests return 402 PLAN_REQUIRED until a plan is chosen. The Data & API page shows the account’s limits and each key’s usage today, this minute and when it was last used.

Errors

Errors use standard HTTP status codes and a JSON body with a stable code, a readable message and a requestId (also sent as X-Request-ID).

429 Too Many Requests
{
  "error": {
    "code": "RATE_LIMIT",
    "message": "Limit of 120 requests per minute reached."
  },
  "requestId": "6f1c2a9e-3b0d-4c55-9a51-2f7e0f0f4b11"
}
StatusCodesMeaning
400INVALID_INPUT, INVALID_AREA, INVALID_JSON, INVALID_METRIC, INVALID_SOURCEA parameter is missing or out of range. The message says which.
401API_KEY_REQUIRED, API_KEY_INVALIDNo Authorization header, or the key is wrong or revoked.
402PLAN_REQUIREDThe key is valid, but the account’s free trial has ended without a plan. Choose a plan and the key works again.
404NOT_FOUNDUnknown market or route.
429RATE_LIMIT, DAILY_LIMITPer-minute or daily limit reached. Wait for Retry-After seconds.
500INTERNAL_ERRORSomething failed on our side. Quote the requestId if you contact us.
503STORAGE_UNAVAILABLEStorage is temporarily unavailable. Retry later.

Pagination

Only List listings is paginated. It returns nextCursor; send it back as cursor until it is null. Pages are ordered by listingKey, so a cursor stays valid while new listings are collected.

Property types

Listings, metrics and estimates use these type ids.

1 Resort, 2 Chalet, 3 Rest house, 4 Farm, 5 Camp, 6 Apartment, 7 Villa, 8 Room, 9 Studio, 11 Serviced apartment

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://www.staytrend.ai/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
    }
  ]
}

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://www.staytrend.ai/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
        }
      ]
    }
  }
}

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://www.staytrend.ai/api/v1/metrics?city=riyadh&past_days=30&forward_days=60"

# Or a map rectangle
curl -H "Authorization: Bearer $JOKERPRICE_API_KEY" \
  "https://www.staytrend.ai/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
      }
    ]
  }
}

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://www.staytrend.ai/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
      }
    ]
  }
}

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://www.staytrend.ai/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"
    }
  ]
}

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://www.staytrend.ai/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"
}

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://www.staytrend.ai/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
        }
      }
    ]
  }
}

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

MCP endpoint

AI assistants can read the same data through the hosted MCP server at https://www.staytrend.ai/mcp: JSON-RPC 2.0 over HTTP POST (the MCP Streamable HTTP transport, with JSON responses), authenticated with the same key. Each tool call counts as one request against the limits above; initialize, tools/list and ping do not. See MCP setup and the tools.

Request
POST https://www.staytrend.ai/mcp
Authorization: Bearer ss_0123456789abcdef0123456789abcdef01234567
Content-Type: application/json
Accept: application/json, text/event-stream

{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_market","arguments":{"slug":"riyadh"}}}

About the data

  • Listings come from public searches on Airbnb, Gathern and Agoda. Amounts are SAR; nightly is the asking rate before cleaning and service fees.
  • Occupancy is estimated from public availability calendars checked daily: a night that closes between two checks counts as booked; long or far-ahead closures count as owner blocks. ADR is the asking price of booked nights, not the achieved rate.
  • Revenue per listing per month is ADR × occupancy × 30; RevPAR is ADR × occupancy.
  • Market reports are cached for up to 30 minutes.
  • JokerPrice is independent and not affiliated with Airbnb, Gathern or Agoda. Figures are estimates, not guarantees.