Paginated adventure search
Search the Safariat catalog. Returned prices are the net prices for the partner (Safariat public price − Safariat margin ± negotiated partner margin). The bank then applies its own commission on its front end to compute the customer price.
Pagination is cursor-based: pass the cursor received in meta.next_cursor to fetch
the next page. No next_cursor → end of the result set.
Authorizations
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
Language of the returned labels (titles, descriptions, categories).
fr, en, ar Query Parameters
Full-text search on title / description / destination.
100Filter on EXPERIENCE (short-duration) or TRIP (multi-day).
EXPERIENCE: short adventure (a few hours to 1 day), hourly slots.TRIP: multi-day tour with an itinerary.
EXPERIENCE, TRIP One or more category codes (e.g. trek, desert, cultural). Repeat the parameter to combine.
Free-text locality match (city or area name, e.g. marrakech).
100Restrict results to a single agency.
Availability from this date (inclusive).
Availability up to this date (inclusive).
One or more months in YYYY-MM format for flexible monthly availability. Up to 12 entries.
12^[0-9]{4}-(0[1-9]|1[0-2])$Total number of travelers (adults + children).
1 <= x <= 30Minimum net price per traveler in MAD (inclusive).
x >= 0Maximum net price per traveler in MAD (inclusive). Must be greater than or equal to price_min.
x >= 0Minimum total adventure duration in hours.
x >= 0Maximum total adventure duration in hours. Must be greater than or equal to duration_min_hours.
x >= 0Minimum average customer rating (1-5).
1 <= x <= 5Latitude of the reference point for geo-proximity search. Required if lng or radius_km is set.
-90 <= x <= 90Longitude of the reference point. Required if lat or radius_km is set.
-180 <= x <= 180Search radius in kilometers from the reference point. Required if lat or lng is set.
Sort order. Default rating_desc (best-rated first). Available options:
rating_desc— highest customer rating firstprice_asc/price_desc— by base price (MAD)created_desc— most recently added first
rating_desc, price_asc, price_desc, created_desc 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).
256Maximum number of items per page.
1 <= x <= 100