| limit | No | | |
| offset | No | Pagination position: omit for the first page, then pass back the `next_offset` token from the previous response VERBATIM. The token is opaque and bound to the catalogue as it was when the page was issued — if services were added, removed or reordered since, the call returns `cursor_expired` and you should restart without an offset. A plain integer offset is still accepted in EITHER spelling — as a JSON number (20) or as its exact string form ("20") — and skips that many results with no catalogue binding. Only a string that is neither an exact integer nor a token this endpoint issued (for example a mangled or truncated token) is refused with `cursor_expired` rather than resumed. | |
| sort_by | No | Field to sort by. Recognised values: price, duration, name, category (unrecognised values are ignored — results stay unsorted). | |
| business | Yes | Which business to ask: its CoreLoop slug, or the `business_id` returned by search_businesses. `business_id` is an opaque, stable, public routing identifier — safe to store and re-use across sessions, unchanged by a rename or a slug change, and carrying no sensitive information. Pass back exactly the value search_businesses gave you: do not parse it, do not infer meaning from its format, and do not construct one. | |
| category | No | Filter by service category | |
| max_price | No | Only services priced at or below this amount | |
| min_price | No | Only services priced at or above this amount | |
| price_type | No | Filter by price type (e.g. fixed, from, range, hourly, free, contact, or unpublished for services with no price set) | |
| sort_order | No | Sort direction (defaults to asc) | |
| max_duration | No | Only services lasting at most this many minutes | |
| min_duration | No | Only services lasting at least this many minutes | |