Skip to main content
GET
/
adventures
/
{slug}
Detailed adventure record
curl --request GET \
  --url https://api.safarapi.com/api/partner/v1/adventures/{slug} \
  --header 'Authorization: Bearer <token>'
import requests

url = "https://api.safarapi.com/api/partner/v1/adventures/{slug}"

headers = {"Authorization": "Bearer <token>"}

response = requests.get(url, headers=headers)

print(response.text)
const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};

fetch('https://api.safarapi.com/api/partner/v1/adventures/{slug}', options)
  .then(res => res.json())
  .then(res => console.log(res))
  .catch(err => console.error(err));
<?php

$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_URL => "https://api.safarapi.com/api/partner/v1/adventures/{slug}",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "GET",
  CURLOPT_HTTPHEADER => [
    "Authorization: Bearer <token>"
  ],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://api.safarapi.com/api/partner/v1/adventures/{slug}"

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("Authorization", "Bearer <token>")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(string(body))

}
HttpResponse<String> response = Unirest.get("https://api.safarapi.com/api/partner/v1/adventures/{slug}")
  .header("Authorization", "Bearer <token>")
  .asString();
require 'uri'
require 'net/http'

url = URI("https://api.safarapi.com/api/partner/v1/adventures/{slug}")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'

response = http.request(request)
puts response.read_body
{ "id": "ad000002-0000-4000-8000-0000000000d2", "slug": "marrakech-3-jours-desert-sandbox", "type": "TRIP", "title": "[DEMO] 3-day Sahara desert circuit from Marrakech", "subtitle": null, "duration": { "days": 3, "hours": 0, "minutes": 0 }, "cover_image_url": "https://placehold.co/600x400?text=DEMO", "destinations": [ "Marrakech" ], "categories": [ "desert" ], "price_from": { "amount": "2400.00", "currency": "MAD" }, "rating": { "average": 4.7, "count": 23 }, "agency": { "id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f", "name": "Sahara Demo Trekking" }, "description": "A 3-day circuit from Marrakech to the Sahara dunes, with overnight stays in the desert.", "highlights": [ "Camel trek at sunset over the Erg Chebbi dunes", "Night under the stars in a desert camp" ], "includes": [ "Air-conditioned 4x4 transport", "2 nights accommodation", "Half board" ], "excludes": [ "Personal expenses", "Travel insurance" ], "what_to_bring": [ "Warm layer for the desert night", "Sunscreen" ], "good_to_know": [ "Departure at 07:00 from central Marrakech" ], "gallery": [ "https://placehold.co/600x400?text=DEMO" ], "itinerary": [ { "day_number": 1, "title": "Marrakech to Dades Valley", "description": "Drive over the Tizi n'Tichka pass with photo stops.", "steps": [ { "order": 1, "title": "Departure from Marrakech", "description": "Pickup at the central meeting point.", "duration": "30 min" } ] }, { "day_number": 2, "title": "Dades Valley to Merzouga", "description": "Camel trek into the dunes and night at the camp.", "steps": [ { "order": 1, "title": "Camel trek", "description": "Sunset ride over the Erg Chebbi dunes.", "duration": "2h" } ] }, { "day_number": 3, "title": "Merzouga back to Marrakech", "description": "Sunrise over the dunes then return drive.", "steps": [ { "order": 1, "title": "Sunrise viewpoint", "description": "Early morning over the dunes before breakfast.", "duration": "1h" } ] } ], "accommodations": [ { "name": "Desert Luxury Camp", "type": "Camp", "stars": 4 }, { "name": "Hotel Dades", "type": "Hotel", "stars": 3 } ], "age_brackets": { "infant_max_age": 2, "child_max_age": 11 }, "rate_packs": [ { "id": "4a700002-0000-4000-8000-0000000000f2", "name": "Comfort", "description": "Standard comfort package with half board.", "base_price": { "amount": "2400.00", "currency": "MAD" }, "child_supplement": { "applies_below_age": 12, "percent_of_adult": 50 }, "extra_bed_supplement": null, "room_allocation": "PER_ROOM", "capacity": 16, "cancellation_tiers": [ { "days_before": 30, "refund_percent": 100 }, { "days_before": 14, "refund_percent": 50 }, { "days_before": 7, "refund_percent": 0 } ] } ], "departure_cities": [ "Marrakech" ] }

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

Path Parameters

slug
string
required

Stable adventure slug (usable as an ID in partner links). The example is illustrative — obtain a real value from GET /adventures. The sandbox catalogue mirrors production with every slug suffixed -sandbox; production slugs have no suffix.

Maximum string length: 200
Pattern: ^[a-z0-9-]+$

Response

Adventure found

id
string<uuid>
required
slug
string
required
Example:

"marrakech-3-jours-desert-sandbox"

type
enum<string>
required
  • EXPERIENCE: short adventure (a few hours to 1 day), hourly slots.
  • TRIP: multi-day tour with an itinerary.
Available options:
EXPERIENCE,
TRIP
title
string
required
duration
object
required
cover_image_url
string<uri>
required
price_from
object
required
rating
object
required
description
string
required
includes
string[]
required
excludes
string[]
required
rate_packs
object[]
required
subtitle
string | null
cover_image_blurhash
string | null

Compact placeholder (BlurHash) for instant rendering before the cover image loads.

cover_image_variants
object | null

Responsive variant URLs of the cover image.

destinations
string[]

Main destination labels.

categories
string[]
pricing
object

Indicative revenue breakdown on price_from (indicative = true).

agency
object | null

Owning agency. name may be null if the agency record was deleted between indexing and read.

availability_hint
enum<string> | null

Computed at search-time from booking ratios. Surfaces UI badges ("plus que 2 places", "complet"). Null if no signal available.

Available options:
AVAILABLE,
FEW_LEFT,
SOLD_OUT
distance_km
number<double> | null

Haversine distance between the search reference point (lat/lng query params) and the adventure's primary location. Null if the search was not geo-anchored.

Required range: x >= 0
highlights
string[]
what_to_bring
string[]
good_to_know
string[]
itinerary
object[]
itinerary_periods
object[]

Multi-day periods grouping consecutive itinerary days (e.g. days 1-3 = "Marrakech to dunes"). Provided alongside itinerary for richer day-by-day rendering on long trips. Empty for SHORT_DURATION adventures.

accommodations
object[]
meeting_points
object[] | null

Geo-located meeting points (SHORT_DURATION only).

faq
object[]

Frequently asked questions, ordered by display index.

host
object | null

Host profile (SHORT_DURATION adventures only).

departure_cities
string[]
departure_dates
string<date>[]

Available departure dates (MULTI_DAY adventures only).

next_departure_date
string<date> | null

Soonest bookable future departure (respects per-pack booking cutoff).

translation_source
enum<string> | null

Set when the returned content has been translated from the source language for the requested Accept-Language. null if the requested locale equals the adventure's source language (content delivered as authored).

Available options:
auto,
manual
age_brackets
object

Age boundaries used to price travellers: 0..infant_max_age is an infant, infant_max_age+1..child_max_age a child, above child_max_age an adult.