StayingAPI Data API

Accommodation data endpoints

Operations 7

GET /search Search properties across platforms (per-result: RATE×results per platform, min 5 credits; airbnb 2×, booking/vrbo 1×, google 15/page). #
POST /search Search properties (JSON body form of GET /search). #
GET /availability Nightly availability for a listing (max(5, ⌈days/2⌉) credits by requested date range). #
GET /listing/{platform}/{id} Full normalized listing (3 credits/leg, flat). #
GET /price Live price for a listing + dates (3 credits/leg, flat). #
GET /price-compare Cross-OTA price comparison — via Google (30 credits, flat) or across listing ids you supply (sum of the per-platform price legs). #
GET /reviews Listing reviews (per-review: RATE×reviews, min 5 credits; airbnb 5×, booking/vrbo 1×). #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/stayingapi-data-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no email required.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

stayingapi-data-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Staying Data API
  version: 1.0.0
  description: 'One accommodation-data API for Airbnb, Booking.com, Vrbo and Google Hotels — availability, search and cross-OTA price comparison in a single unified schema. Every endpoint returns the canonical envelope (§6.3.3); errors use the locked sub-code catalog (§6.4). Failed, empty and blocked calls are never billed; cached results bill at tier (caching is margin, not a discount). Full docs: https://stayingapi.com/docs.'
  contact:
    name: StayingAPI
    url: https://stayingapi.com/docs
  license:
    name: Proprietary
servers:
- url: https://api.stayingapi.com/v1
  description: REST API (v1)
security:
- bearerAuth: []
tags:
- name: Data
  description: Accommodation data endpoints
paths:
  /search:
    get:
      tags:
      - Data
      operationId: searchGet
      summary: 'Search properties across platforms (per-result: RATE×results per platform, min 5 credits; airbnb 2×, booking/vrbo 1×, google 15/page).'
      parameters:
      - name: location
        in: query
        required: true
        schema:
          type: string
        description: Destination (city, region, address).
      - name: checkIn
        in: query
        required: false
        schema:
          type: string
        description: YYYY-MM-DD.
      - name: checkOut
        in: query
        required: false
        schema:
          type: string
        description: YYYY-MM-DD.
      - name: platforms
        in: query
        required: false
        schema:
          type: string
        description: Comma-separated platforms; defaults to all enabled. `limit` applies per platform.
      - name: platform
        in: query
        required: false
        schema:
          type: string
        description: Alias for `platforms=<value>` when requesting exactly one platform.
      - name: adults
        in: query
        required: false
        schema:
          type: integer
        description: Default 2.
      - name: children
        in: query
        required: false
        schema:
          type: integer
        description: Default 0; requires matching childAges.
      - name: rooms
        in: query
        required: false
        schema:
          type: integer
        description: Default 1.
      - name: currency
        in: query
        required: false
        schema:
          type: string
        description: ISO-4217; default USD.
      - name: limit
        in: query
        required: false
        schema:
          type: integer
        description: '1–40; default 10. Applies per platform: a 3-platform search with limit=5 returns up to 15 results.'
      - name: cursor
        in: query
        required: false
        schema:
          type: string
        description: Opaque pagination cursor.
      - name: sort
        in: query
        required: false
        schema:
          type: string
        description: recommended | price_asc | price_desc | rating_desc.
      responses:
        '200':
          description: Success.
          headers:
            X-Request-Id:
              schema:
                type: string
          content:
            application/json:
              schema:
                allOf:
                - $ref: '#/components/schemas/SuccessEnvelope'
                - type: object
                  properties:
                    data:
                      type: array
                      items:
                        $ref: '#/components/schemas/Property'
        '202':
          description: Accepted — async job created; poll pollUrl. Retry-After hints the back-off.
          headers:
            Retry-After:
              schema:
                type: integer
              description: Seconds to wait before polling.
            X-Request-Id:
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AsyncAccepted'
        '400':
          description: Validation error (invalid_request).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '401':
          description: Authentication error (missing/invalid API key).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '402':
          description: Insufficient credits (credit_balance_too_low).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '403':
          description: Permission denied (e.g. email_unverified on live credits; subscription_required on top-ups).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '429':
          description: Rate limited (rate_limit_exceeded); carries Retry-After.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '503':
          description: All upstream sources failed or were blocked (no charge).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
    post:
      tags:
      - Data
      operationId: searchPost
      summary: Search properties (JSON body form of GET /search).
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        '200':
          description: Success.
          headers:
            X-Request-Id:
              schema:
                type: string
          content:
            application/json:
              schema:
                allOf:
                - $ref: '#/components/schemas/SuccessEnvelope'
                - type: object
                  properties:
                    data:
                      type: array
                      items:
                        $ref: '#/components/schemas/Property'
        '202':
          description: Accepted — async job created; poll pollUrl. Retry-After hints the back-off.
          headers:
            Retry-After:
              schema:
                type: integer
              description: Seconds to wait before polling.
            X-Request-Id:
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AsyncAccepted'
        '400':
          description: Validation error (invalid_request).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '401':
          description: Authentication error (missing/invalid API key).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '402':
          description: Insufficient credits (credit_balance_too_low).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '403':
          description: Permission denied (e.g. email_unverified on live credits; subscription_required on top-ups).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '429':
          description: Rate limited (rate_limit_exceeded); carries Retry-After.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '503':
          description: All upstream sources failed or were blocked (no charge).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
  /availability:
    get:
      tags:
      - Data
      operationId: availability
      summary: Nightly availability for a listing (max(5, ⌈days/2⌉) credits by requested date range).
      description: 'Provide EXACTLY ONE identification form: listingId, listingIds, or url. None → missing_parameter; conflicting forms → mutually_exclusive_params; a url that is not a well-formed listing URL for the platform → invalid_listing_url.'
      parameters:
      - name: platform
        in: query
        required: true
        schema:
          $ref: '#/components/schemas/Platform'
        description: Target platform (must be enabled for availability).
      - name: listingId
        in: query
        required: false
        schema:
          type: string
        description: Platform listing id (one identification form).
      - name: listingIds
        in: query
        required: false
        schema:
          type: string
        description: Comma-separated listing ids (one identification form).
      - name: url
        in: query
        required: false
        schema:
          type: string
        description: Full listing URL for the platform (one identification form).
      - name: startDate
        in: query
        required: true
        schema:
          type: string
        description: YYYY-MM-DD (required).
      - name: endDate
        in: query
        required: true
        schema:
          type: string
        description: YYYY-MM-DD (required).
      - name: onlyAvailable
        in: query
        required: false
        schema:
          type: boolean
        description: Only return available dates.
      responses:
        '200':
          description: Success.
          headers:
            X-Request-Id:
              schema:
                type: string
          content:
            application/json:
              schema:
                allOf:
                - $ref: '#/components/schemas/SuccessEnvelope'
                - type: object
                  properties:
                    data:
                      type: array
                      items:
                        $ref: '#/components/schemas/Availability'
        '202':
          description: Accepted — async job created; poll pollUrl. Retry-After hints the back-off.
          headers:
            Retry-After:
              schema:
                type: integer
              description: Seconds to wait before polling.
            X-Request-Id:
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AsyncAccepted'
        '400':
          description: Validation error (invalid_request).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '401':
          description: Authentication error (missing/invalid API key).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '402':
          description: Insufficient credits (credit_balance_too_low).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '403':
          description: Permission denied (e.g. email_unverified on live credits; subscription_required on top-ups).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '429':
          description: Rate limited (rate_limit_exceeded); carries Retry-After.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '503':
          description: All upstream sources failed or were blocked (no charge).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
  /listing/{platform}/{id}:
    get:
      tags:
      - Data
      operationId: listing
      summary: Full normalized listing (3 credits/leg, flat).
      parameters:
      - name: platform
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/Platform'
      - name: id
        in: path
        required: true
        schema:
          type: string
      - name: country
        in: query
        required: false
        schema:
          type: string
        description: ISO-3166 alpha-2 country hint (booking). Disambiguates a bare booking.com slug (slugs are not globally unique) without the %2F-encoded /hotel/{cc}/{slug} id — e.g. /v1/listing/booking/casa-de-alba?country=co. A bare booking slug with no country returns 400 needs_country.
      - name: checkIn
        in: query
        required: false
        schema:
          type: string
        description: YYYY-MM-DD.
      - name: checkOut
        in: query
        required: false
        schema:
          type: string
        description: YYYY-MM-DD.
      - name: currency
        in: query
        required: false
        schema:
          type: string
        description: ISO-4217; default USD.
      responses:
        '200':
          description: Success.
          headers:
            X-Request-Id:
              schema:
                type: string
          content:
            application/json:
              schema:
                allOf:
                - $ref: '#/components/schemas/SuccessEnvelope'
                - type: object
                  properties:
                    data:
                      $ref: '#/components/schemas/Property'
        '202':
          description: Accepted — async job created; poll pollUrl. Retry-After hints the back-off.
          headers:
            Retry-After:
              schema:
                type: integer
              description: Seconds to wait before polling.
            X-Request-Id:
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AsyncAccepted'
        '400':
          description: Validation error (invalid_request).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '401':
          description: Authentication error (missing/invalid API key).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '402':
          description: Insufficient credits (credit_balance_too_low).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '403':
          description: Permission denied (e.g. email_unverified on live credits; subscription_required on top-ups).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '429':
          description: Rate limited (rate_limit_exceeded); carries Retry-After.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '503':
          description: All upstream sources failed or were blocked (no charge).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
  /price:
    get:
      tags:
      - Data
      operationId: price
      summary: Live price for a listing + dates (3 credits/leg, flat).
      parameters:
      - name: platform
        in: query
        required: true
        schema:
          $ref: '#/components/schemas/Platform'
        description: Target platform (must be enabled for price).
      - name: listingId
        in: query
        required: true
        schema:
          type: string
        description: Platform listing id.
      - name: checkIn
        in: query
        required: true
        schema:
          type: string
        description: YYYY-MM-DD (required).
      - name: checkOut
        in: query
        required: true
        schema:
          type: string
        description: YYYY-MM-DD (required).
      - name: currency
        in: query
        required: false
        schema:
          type: string
        description: ISO-4217; default USD.
      responses:
        '200':
          description: Success.
          headers:
            X-Request-Id:
              schema:
                type: string
          content:
            application/json:
              schema:
                allOf:
                - $ref: '#/components/schemas/SuccessEnvelope'
                - type: object
                  properties:
                    data:
                      $ref: '#/components/schemas/Price'
        '202':
          description: Accepted — async job created; poll pollUrl. Retry-After hints the back-off.
          headers:
            Retry-After:
              schema:
                type: integer
              description: Seconds to wait before polling.
            X-Request-Id:
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AsyncAccepted'
        '400':
          description: Validation error (invalid_request).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '401':
          description: Authentication error (missing/invalid API key).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '402':
          description: Insufficient credits (credit_balance_too_low).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '403':
          description: Permission denied (e.g. email_unverified on live credits; subscription_required on top-ups).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '429':
          description: Rate limited (rate_limit_exceeded); carries Retry-After.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '503':
          description: All upstream sources failed or were blocked (no charge).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
  /price-compare:
    get:
      tags:
      - Data
      operationId: priceCompare
      summary: Cross-OTA price comparison — via Google (30 credits, flat) or across listing ids you supply (sum of the per-platform price legs).
      description: 'TWO modes, one response type.


        **Google-aggregator mode** (`name` / `location` / `googleHotelId`): we resolve the property on Google Hotels and report the offers it surfaces. You need no ids. Flat 30 credits.


        **Direct fan-out mode** (`listings=`): you supply 2–6 `platform:listingId` pairs for the SAME property and we run one real price call per listing, in parallel, then normalize the comparison ourselves. Each offer carries `platform`, `listingId`, `nightlyPrice`, `nights` and a best-effort `fees` breakdown, and the response is marked `source: ''direct_fanout''`. Billed as the SUM of the per-platform price legs; a leg that fails or returns nothing is charged 0 and is reported in `meta.platformResults` with `meta.partial: true`.


        FEE COVERAGE IS UNEVEN and this is deliberate rather than a gap we hide: Airbnb reports cleaning, service and taxes; Booking.com reports taxes only; Vrbo and Google report none. Compare on `totalPrice`, which is present and comparable everywhere. A null fee means we could not read it, NOT that the platform does not charge it.


        `min` and `median` cover only the offers quoted in the response `currency`; offers in another currency are still returned but excluded from the summary.'
      parameters:
      - name: listings
        in: query
        required: false
        schema:
          type: string
        description: DIRECT MODE. 2–6 comma-separated (or repeated) platform:listingId pairs for the same property, e.g. listings=airbnb:12345,booking:co/casa-de-alba,vrbo:987654. Split on the FIRST colon, so a full listing URL works as the id. Mutually exclusive with name/location/googleHotelId. An id containing a comma must be sent as a repeated param.
      - name: name
        in: query
        required: false
        schema:
          type: string
        description: GOOGLE MODE. Property name (one of name/location/googleHotelId).
      - name: location
        in: query
        required: false
        schema:
          type: string
        description: GOOGLE MODE. Location hint (one of name/location/googleHotelId).
      - name: googleHotelId
        in: query
        required: false
        schema:
          type: string
        description: GOOGLE MODE. Google hotel id (mutually exclusive with name/location).
      - name: checkIn
        in: query
        required: true
        schema:
          type: string
        description: YYYY-MM-DD (required).
      - name: checkOut
        in: query
        required: true
        schema:
          type: string
        description: YYYY-MM-DD (required).
      - name: adults
        in: query
        required: false
        schema:
          type: integer
        description: Default 2.
      - name: children
        in: query
        required: false
        schema:
          type: integer
        description: Default 0.
      - name: currency
        in: query
        required: false
        schema:
          type: string
        description: ISO-4217; default USD.
      responses:
        '200':
          description: Success.
          headers:
            X-Request-Id:
              schema:
                type: string
          content:
            application/json:
              schema:
                allOf:
                - $ref: '#/components/schemas/SuccessEnvelope'
                - type: object
                  properties:
                    data:
                      $ref: '#/components/schemas/PriceCompare'
        '202':
          description: Accepted — async job created; poll pollUrl. Retry-After hints the back-off.
          headers:
            Retry-After:
              schema:
                type: integer
              description: Seconds to wait before polling.
            X-Request-Id:
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AsyncAccepted'
        '400':
          description: Validation error (invalid_request).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '401':
          description: Authentication error (missing/invalid API key).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '402':
          description: Insufficient credits (credit_balance_too_low).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '403':
          description: Permission denied (e.g. email_unverified on live credits; subscription_required on top-ups).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '429':
          description: Rate limited (rate_limit_exceeded); carries Retry-After.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '503':
          description: All upstream sources failed or were blocked (no charge).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
  /reviews:
    get:
      tags:
      - Data
      operationId: reviews
      summary: 'Listing reviews (per-review: RATE×reviews, min 5 credits; airbnb 5×, booking/vrbo 1×).'
      description: Provide EXACTLY ONE of listingId or url. None → missing_parameter; both → mutually_exclusive_params; a bad url → invalid_listing_url. Required params are platform plus either listingId or url. listingId should be the platform-native id from /v1/search `platformListingId`; a `stays_<platform>_<platformListingId>` object id is accepted, normalized, and may supply platform when platform is omitted.
      parameters:
      - name: platform
        in: query
        required: true
        schema:
          $ref: '#/components/schemas/Platform'
        description: Target platform (must be enabled for reviews).
      - name: listingId
        in: query
        required: false
        schema:
          type: string
        description: Platform-native id from /v1/search `platformListingId` (one identification form); a `stays_<platform>_<platformListingId>` id is accepted, normalized, and may supply platform when platform is omitted.
      - name: url
        in: query
        required: false
        schema:
          type: string
        description: Full listing URL (one identification form).
      - name: limit
        in: query
        required: false
        schema:
          type: integer
        description: 1–100; default 20.
      - name: cursor
        in: query
        required: false
        schema:
          type: string
        description: Opaque pagination cursor.
      - name: language
        in: query
        required: false
        schema:
          type: string
        description: ISO-639-1 filter.
      - name: sort
        in: query
        required: false
        schema:
          type: string
        description: recent | rating_desc | rating_asc.
      responses:
        '200':
          description: Success.
          headers:
            X-Request-Id:
              schema:
                type: string
          content:
            application/json:
              schema:
                allOf:
                - $ref: '#/components/schemas/SuccessEnvelope'
                - type: object
                  properties:
                    data:
                      type: array
                      items:
                        $ref: '#/components/schemas/Review'
        '202':
          description: Accepted — async job created; poll pollUrl. Retry-After hints the back-off.
          headers:
            Retry-After:
              schema:
                type: integer
              description: Seconds to wait before polling.
            X-Request-Id:
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AsyncAccepted'
        '400':
          description: Validation error (invalid_request).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '401':
          description: Authentication error (missing/invalid API key).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '402':
          description: Insufficient credits (credit_balance_too_low).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '403':
          description: Permission denied (e.g. email_unverified on live credits; subscription_required on top-ups).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '429':
          description: Rate limited (rate_limit_exceeded); carries Retry-After.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '503':
          description: All upstream sources failed or were blocked (no charge).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
components:
  schemas:
    SuccessEnvelope:
      type: object
      required:
      - data
      - meta
      properties:
        data:
          $ref: '#/components/schemas/AnyData'
        meta:
          $ref: '#/components/schemas/Meta'
    Warning:
      type: object
      properties:
        code:
          type: string
        message:
          type: string
        platform:
          $ref: '#/components/schemas/Platform'
        docUrl:
          type: string
          format: uri
    AnyData:
      description: Endpoint-specific data payload.
    Availability:
      type: object
      properties:
        platform:
          type: string
          enum:
          - airbnb
          - booking
          - vrbo
          - expedia
          - hotels
          - google
          - tripadvisor
        listingId:
          type: string
          minLength: 1
        dates:
          type: array
          items:
            type: object
            properties:
              date:
                type: string
                pattern: ^\d{4}-\d{2}-\d{2}$
              available:
                type: boolean
              minNights:
                type: integer
                exclusiveMinimum: 0
                maximum: 9007199254740991
              checkIn:
                type: boolean
              checkOut:
                type: boolean
              bookable:
                type: boolean
            required:
            - date
            - available
            - minNights
            - checkIn
            - checkOut
            - bookable
      required:
      - platform
      - listingId
      - dates
    PlatformFailureError:
      type: object
      properties:
        type:
          type: string
          enum:
          - invalid_request
          - authentication_error
          - permission_denied
          - not_found
          - insufficient_credits
          - rate_limited
          - upstream_unavailable
          - upstream_timeout
          - internal_error
        code:
          type: string
          enum:
          - missing_parameter
          - invalid_parameter
          - invalid_date_range
          - date_in_past
          - child_ages_mismatch
          - stay_too_long
          - window_too_long
          - invalid_listing_url
          - invalid_property_type
          - invalid_amenity
          - invalid_price_range
          - invalid_language
          - invalid_sort
          - invalid_cursor
          - limit_out_of_range
          - mutually_exclusive_params
          - platform_not_enabled
          - no_enabled_platform
          - needs_country
          - missing_api_key
          - invalid_api_key
          - revoked_api_key
          - scope_insufficient
          - email_unverified
          - subscription_required
          - listing_not_found
          - job_not_found
          - identity_mismatch
          - credit_balance_too_low
          - rate_limit_exceeded
          - all_actors_failed
          - actor_blocked
          - upstream_degraded
          - actor_timeout
          - internal_error
        message:
          type: string
          minLength: 1
        retryable:
          type: boolean
      required:
      - type
      - code
      - message
      - retryable
    Pagination:
      type: object
      properties:
        limit:
          type: integer
        cursor:
          type:
          - string
          - 'null'
        nextCursor:
          type:
          - string
          - 'null'
          description: Opaque base64 cursor for the next page; null on the last page.
        hasMore:
          type: boolean
    PlatformResult:
      type: object
      properties:
        platform:
          $ref: '#/components/schemas/Platform'
        status:
          type: string
          enum:
          - ok
          - failed
          - skipped
        reason:
          type: string
          enum:
          - not_enabled
          - requires_dates
          description: Present on skipped platform results; explains why a requested platform was not called.
        creditsCharged:
          type: integer
          minimum: 0
        cached:
          type: boo

# --- truncated at 32 KB (53 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/stayingapi/refs/heads/main/openapi/stayingapi-data-api-openapi.yml