SafariOffice.

SafariOffice API Manual

Authentication: All API endpoints require a Bearer token with either read or read_write permissions. This /v1/manual page is public for convenience.
If you do not have an API token, please create one in your SafariOffice account under Settings → SafariOffice API.
If you need help, please contact us at dev@safarioffice.com.

Status-specific fields: For requests with status booked, responses include booked_value, booked_currency, booked_at, start_date and booked_quotes (IDs). For requests with status notbooked, responses include notbooked_reason when provided.

Clients

MethodPathDescriptionParameters
GET/v1/clientsList clientsQuery:
page (int, optional)
limit (int, optional)
search (string, optional)
GET/v1/clients/{id}Get client by ID
GET/v1/clients/{id}/requestsList requests for clientQuery:
status (string, optional): new|working|open|prebooked|booked|completed|notbooked
search (string, optional)
page (int, optional)
limit (int, optional)
GET/v1/clients/{id}/quotesList quotes for clientQuery:
status (string, optional): draft|sent|archived
search (string, optional)
page (int, optional)
limit (int, optional)
POST/v1/clientsCreate clientJSON Body:
lastname (string, required)
email (string, required, valid email)
salutation (string, optional)
firstname (string, optional)
phone (string, optional)
country (string, optional)
PUT/v1/clients/{id}Update clientJSON Body:
salutation (string, optional)
firstname (string, optional)
lastname (string, optional)
email (string, optional, valid email)
phone (string, optional)
country (string, optional)
DELETE/v1/clients/{id}Delete client (no non-deleted requests)

Requests

MethodPathDescriptionParameters
GET/v1/requestsList requestsQuery:
status (string, optional): new|working|workingopen|open|prebooked|booked|completed|notbooked
client_id (int, optional)
source (string, optional): filter by lead source, exact match (e.g. "SafariBookings", "Website")
search (string, optional)
page (int, optional)
limit (int, optional)
GET/v1/requests/{id}Get request by ID
GET/v1/requests/{id}/quotesList quotes for a requestQuery:
status (string, optional): draft|sent|archived
page (int, optional)
limit (int, optional)
POST/v1/requestsCreate a new requestJSON Body:
client_id (int, required)
language (string, optional): en|de|es|fr|it — defaults to account default language
lead_source (string, optional): e.g. "Zoho CRM", "Website"
reference_id (string, optional): external reference ID (e.g. CRM lead ID)
tour_template_id (int, optional): template ID from GET /v1/templates
tour_title (string, optional): ignored when tour_template_id is set
tour_type (string, optional): ignored when tour_template_id is set
tour_length (int or string, optional): e.g. 14 or "14 days" — ignored when tour_template_id is set
countries (array[int], optional): country IDs — ignored when tour_template_id is set
start_destination (string, optional)
end_destination (string, optional)
start_date (string, optional): YYYY-MM-DD format
travelers (array, optional): [{"amount": 2, "name": "Adults"}]
room_settings (array, optional): [{"amount": 1, "name": "Double Room"}]
notes (string, optional): client question or request info

Requires read_write token. New traveler types, room types, lead sources, and tour types are automatically added to your autocomplete suggestions. When tour_template_id is set, tour details (title, type, length, countries) are derived from the template.
PUT/v1/requests/{id}Update request (limited fields)JSON Body:
lead_source (string, optional)
reference_id (string, optional)

Only lead_source and reference_id can be updated via API. Other status changes use dedicated endpoints.
POST/v1/requests/{id}/bookedBook a requestJSON Body:
quote_ids (array[int], required)
booking_value (number, required)
booking_currency (string, required)
booking_confirmation_date (string, required, ISO datetime)
start_date (string, required, ISO datetime)

Only available with read_write tokens. Quotes must be in sent status. When booked, responses include booked_value, booked_currency, booked_at, start_date and booked_quotes. GET /v1/requests/{id} additionally returns payment_milestones for the booked quote — see the Quotes group for its shape.
POST/v1/requests/{id}/notbookedMark request as not bookedJSON Body:
reason (string, optional)

Can be used on open, working, pre-booked, or booked requests. Optional reason is stored for audit purposes.
DELETE/v1/requests/{id}Delete request (only if it has no quotes)

Templates

MethodPathDescriptionParameters
GET/v1/templatesList tour templatesQuery:
search (string, optional): filter by template name
page (int, optional)
limit (int, optional)
GET/v1/templates/{id}Get template details (includes day-level itinerary)Response always includes: template_id, name, status, language (code), days_count, countries, created_at, updated_at. Included only when set (omitted otherwise): image_url (cover image, 1240x1754), image_thumb_url (400x566), online_tour_url (public tour page URL, when the Share Tours add-on is active and the template is published), from_price ({currency, rates: {"Rate for 2026": 9500, ...}}). The detail endpoint also returns days. Each day always has day_number and no_of_days, and — only when set — country, title, main_destination, accommodation, meal_plan (a string, or an object keyed by day number when it varies across a multi-day block), and activities (each with name, location, from, to, via, transfer_time, time and optional, each present only when set). The list endpoint returns the same top-level fields except days.

Quotes

MethodPathDescriptionParameters
GET/v1/quotesList quotesQuery:
status (string, optional): draft|sent|archived
request_id (int, optional)
page (int, optional)
limit (int, optional)
GET/v1/quotes/{id}Get quote by IDIncludes payment_milestones when the company has the Payment Milestones feature, otherwise null — null means no feature, an empty milestones array means the feature with nothing set up. Each milestone carries label, description, timing_kind, timing_offset, percentage, amount, currency, status (pending|invoice_sent|payment_received), due_date and excluded_from_total. Amount and percentage are null on a quote with no priced lines: 25% of nothing is not 0.00. due_date is only calculable for departure-relative milestones on a quote with a parseable start_date; where it is null, due_date_unresolved_reason says which case it was rather than implying no deadline. The block also returns quote_total, scheduled_total, outstanding_total (excludes payment_received and anything excluded_from_total; a magnitude for triage, not an invoice), by_status and inherited_from_company_default.
GET/v1/quotes/for-request/{requestId}List quotes for a request
DELETE/v1/quotes/{id}Delete quote

Analytics

MethodPathDescriptionParameters
GET/v1/analytics/usageAPI usage metrics
GET/v1/analytics/rate-limitRate limit status

Errors

Standard error response contains: success=false, error, error_msg, error_code. HTTP statuses: 4xx for client errors, 5xx for server errors.

Notes