Skip to main content
GET
Paginated adventure search

Authorizations

Authorization
string
header
default:sk_test_DEMO0000_replace_with_your_sandbox_key
required

API key authentication. Issued by the Safariat admin or via the partner portal. The secret is shown only once at generation.

Production sk_live_* keys must additionally sign every write request (POST/PUT/DELETE) with the X-Timestamp and X-Signature headers. Sandbox sk_test_* keys are exempt from request signing: X-Signature and X-Timestamp are not required for writes in the sandbox (so the developer-portal "Try it" playground works end to end). The Idempotency-Key header remains required on writes in both environments.

Headers

Accept-Language
enum<string>
default:fr

Language of the returned labels (titles, descriptions, categories).

Available options:
fr,
en,
ar

Query Parameters

query
string

Full-text search on title / description / destination.

Maximum string length: 100
type
enum<string>

Filter on EXPERIENCE (short-duration) or TRIP (multi-day). The internal spellings SHORT_DURATION and MULTI_DAY are also accepted on input; responses always use EXPERIENCE / TRIP.

  • EXPERIENCE: short adventure (a few hours to 1 day), hourly slots.
  • TRIP: multi-day tour with an itinerary.
Available options:
EXPERIENCE,
TRIP
category_codes
string[]

One or more category codes (e.g. trek, desert, cultural). Repeat the parameter to combine.

destination_locality
string

Free-text locality match (city or area name, e.g. marrakech).

Maximum string length: 100
agency_id
string<uuid>

Restrict results to a single agency.

date_from
string<date>

Keep adventures bookable on or after this date (inclusive). Combined with date_to it forms a range; alone it leaves the upper bound open.

date_to
string<date>

Keep adventures bookable on or before this date (inclusive). Alone it leaves the lower bound open. Availability is evaluated on the calendar that actually applies to each rate pack, so results agree with GET /adventures/{slug}/availability.

available_months
string[]

One or more months in YYYY-MM format for flexible monthly availability. Up to 12 entries.

Maximum array length: 12
Pattern: ^[0-9]{4}-(0[1-9]|1[0-2])$
participants
integer

Total number of travelers (adults + children).

Required range: 1 <= x <= 30
price_min
number<double>

Minimum net price per traveler in MAD (inclusive).

Required range: x >= 0
price_max
number<double>

Maximum net price per traveler in MAD (inclusive). Must be greater than or equal to price_min.

Required range: x >= 0
duration_min_hours
integer

Minimum total adventure duration in hours.

Required range: x >= 0
duration_max_hours
integer

Maximum total adventure duration in hours. Must be greater than or equal to duration_min_hours.

Required range: x >= 0
rating_min
integer

Minimum average customer rating (1-5).

Required range: 1 <= x <= 5
lat
number<double>

Latitude of the reference point for geo-proximity search. Required if lng or radius_km is set.

Required range: -90 <= x <= 90
lng
number<double>

Longitude of the reference point. Required if lat or radius_km is set.

Required range: -180 <= x <= 180
radius_km
number<double>

Search radius in kilometers from the reference point. Required if lat or lng is set.

sort
enum<string>
default:rating_desc

Sort order. Default rating_desc (best-rated first). Available options:

  • rating_desc — highest customer rating first
  • price_asc / price_desc — by base price (MAD)
  • created_desc — most recently added first
Available options:
rating_desc,
price_asc,
price_desc,
created_desc
page
integer

1-based page number. Alternative to cursor for random access and backward navigation. When both are supplied, page wins. Combine with meta.total_results to build a classic pager. Note that page-based paging can drift if the catalogue changes between two calls.

Required range: x >= 1
cursor
string

Opaque pagination cursor returned by the previous response in meta.next_cursor. Pass null/omit on the first request; absence of next_cursor in the response signals the last page. Treat the cursor as fully opaque — its format is internal and may evolve.

Keyset pagination (all listing endpoints except /adventures). The cursor is anchored on the last row of the previous page, so results are stable under concurrent writes — no duplicates, no skipped rows when items are inserted between page fetches. Two cursors are not interchangeable across endpoints: a cursor obtained from /reviews will be rejected with 400 on /bookings.

/adventures is offset-based by design (dynamic sort: popularity, price, distance) and will not migrate to keyset. Its cursor cannot be passed to other endpoints.

Behavior change (Phase B): /webhooks/deliveries now sorts by created_at instead of updated_at. The previous sort field is mutable (retry attempts), which is incompatible with the keyset invariant. Use the status filter to surface deliveries currently being retried (status=PENDING,FAILED).

Maximum string length: 256
limit
integer
default:25

Maximum number of items per page.

Required range: 1 <= x <= 100

Response

Page of results

data
object[]
required
meta
object
required