Computes the net price for a traveler composition on a specific slot. The price is
locked for 30 minutes: POST /bookings with this quote_id uses the computed
price even if the rate pack’s rate has changed in the meantime.
After 30 min the quote_id is invalidated and POST /bookings returns
quote.expired. The bank must then create a new quote at the current rate.
Every age in rooms[].children[].age is classified against the adventure’s age_brackets
before pricing: at or below infant_max_age an infant, up to child_max_age a child,
above it an adult paying the adult rate. The rate pack tells you in advance what the
classification will cost you, through children_allowed, infants_allowed, child_price,
infant_price, max_children and max_infants, so a composition can be checked against
GET /adventures/{slug} without issuing a quote.
Four 400 codes come from that composition: adventure.children.not.accepted,
adventure.infants.not.accepted, adventure.children.max.exceeded and
adventure.infants.max.exceeded. A fifth, adventure.room.occupancy.exceeded, is raised
when a room holds more travellers than its max_occupancy, infants excepted.
Example values are illustrative: take a real adventure_slug and
rate_pack_id from GET /adventures / GET /adventures/{slug} (in the
sandbox, slugs carry a -sandbox suffix).
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.
Opaque, client-generated string unique per logical operation (a UUID v4 is
recommended but any non-blank value up to 255 chars is accepted). Same key +
same body = the cached response is returned with the Idempotent-Replayed: true
header. Same key + different body = 409 Conflict. Retained for 24 h.
Unix timestamp in seconds at the time the request is issued. Validity window
±5 minutes — beyond that the request is rejected. Required for production
sk_live_* keys only; not required for sandbox sk_test_* keys.
hex(HMAC_SHA256(secret, "{X-Timestamp}\n{METHOD}\n{path}\n{body}")).
The path includes the query string. The body is the exact JSON representation
sent — any reformatting invalidates the signature. Required for production
sk_live_* keys only; not required for sandbox sk_test_* keys.
Required on an EXPERIENCE whose rate pack exposes start_times
(partner.quote.starttime.required otherwise). Optional on a TRIP, whose departure hour
is informative. In both cases a value that is not one of the pack start_times is
rejected (partner.quote.starttime.not.available). Returned as null for a pack that
exposes no start time, flexible packs included.
Priced lines making up the quote. travelers is always present; room_supplement appears
when the booked room types carry a supplement. The lines sum to the gross price found in
pricing.
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"SafarAPI","description":"Developer documentation for the SafarAPI partner channel — quote, book and settle Moroccan adventures from your app.","colors":{"primary":"#f2460d","light":"#fb923c","dark":"#c2410c"},"logo":{"light":"https://mintcdn.com/safariat/uq0i7jK0LmN_yZ-e/logo/safarapi-light.svg?fit=max\u0026auto=format\u0026n=uq0i7jK0LmN_yZ-e\u0026q=85\u0026s=6e54d448368f1737309eebb08e5e571c","dark":"https://mintcdn.com/safariat/uq0i7jK0LmN_yZ-e/logo/safarapi-dark.svg?fit=max\u0026auto=format\u0026n=uq0i7jK0LmN_yZ-e\u0026q=85\u0026s=007f52ec9befa6071011db06b432b61d"},"favicon":"https://mintcdn.com/safariat/uq0i7jK0LmN_yZ-e/favicon.svg?fit=max\u0026auto=format\u0026n=uq0i7jK0LmN_yZ-e\u0026q=85\u0026s=a5d5d7ecbe37e9205bda58ca868f2853","api":{"playground":{"display":"interactive","proxy":true}},"navbar":{"links":[{"href":"/status","label":"Status"},{"href":"https://console.safarapi.com","label":"Console"}],"primary":{"type":"button","label":"Get sandbox access","href":"https://console.safarapi.com/signup"}},"footer":{"socials":{"website":"https://safarapi.com","linkedin":"https://www.linkedin.com/company/safarapi"}},"search":{"prompt":"Search the SafarAPI docs — quotes, bookings, webhooks, settlements"},"seo":{"metatags":{"og:title":"SafarAPI — Morocco travel API for banks \u0026 fintechs","og:description":"Quote, book and settle curated Moroccan travel from your banking app. Sandbox in minutes, production in 7 days.","og:type":"website"},"indexing":"navigable"},"fonts":{"heading":{"family":"Space Grotesk"},"body":{"family":"Inter"}},"styling":{"eyebrows":"section","codeblocks":{"theme":"github-dark-dimmed"},"latex":false},"errors":{"404":{"redirect":false,"title":"Page not found","description":"This page does not exist. Start from the [welcome guide](/introduction/welcome), the [quickstart](/introduction/quickstart), or the [API reference](/api-reference/openapi)."}},"contextual":{"options":["copy","view","chatgpt","claude"],"display":"header"},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"safariat","hasAudioNarration":false,"actualSubdomain":"safariat","customDomains":["developers.safarapi.com"],"gitSource":{"type":"github","owner":"adnanahouzi","repo":"maroc-voyages-r-v-s","deployBranch":"main","contentDirectory":"docs-portal","isPrivate":true,"mountPath":"","label":""},"chroma":{"liveDeploymentHistoryId":"6a9c766b0d95020accd6ba30","collectionId":"ffbff38d-bd54-4930-96e6-24689d9a11de","schemaVersion":"v3","latestBuiltDeploymentHistoryId":"6a9c766b0d95020accd6ba30"},"entitlements":{"AI_CHAT":{"status":"DISABLED"}},"buildId":"6a9c766b0d95020accd6ba30","clientVersion":"0.0.4076","searchFilterCounts":[{"language":"default","tag":"API Reference","count":67},{"language":"default","tag":"Endpoints","count":58},{"language":"default","tag":"Guides","count":22},{"language":"default","tag":"API concepts","count":10},{"language":"default","tag":"Catalog","count":8},{"language":"default","tag":"Webhooks","count":7},{"language":"default","tag":"Bookings","count":6},{"language":"default","tag":"Dashboard","count":5},{"language":"default","tag":"Settlements","count":5},{"language":"default","tag":"Introduction","count":4}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableContextualStarterQuestions":false,"enableAskAiSearchBar":true},"basePath":"","hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"rbac-expansion","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-serve","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"live-agents","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"comment-mode","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":true},"customCss":[{"filePath":"style.css","content":":root{--safarapi-ink: #1a1a1a;--safarapi-rule: #ececec;--safarapi-accent: #f2460d}.dark{--safarapi-ink: #ededed;--safarapi-rule: #2a2a2a;--safarapi-accent: #fb923c}body{-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}main p,main li{line-height:1.68}main h2{margin-top:2.5rem;letter-spacing:-0.01em}main h3{margin-top:1.75rem}main a:not([class]){color:var(--safarapi-accent);text-decoration:none;border-bottom:1px solid transparent;transition:border-color 120ms ease}main a:not([class]):hover{border-bottom-color:currentColor}pre,code{border:1px solid var(--safarapi-rule);border-radius:6px}pre{box-shadow:none}table{border-collapse:collapse}table th,table td{border-color:var(--safarapi-rule)}a:focus-visible,button:focus-visible{outline:2px solid var(--safarapi-accent);outline-offset:2px}"}],"page":{"pagePath":"api-reference/quotes/create-a-price-locked-quote","slug":"/api-reference/quotes/create-a-price-locked-quote","pageMetadata":{"title":"Create a price-locked quote","description":"Computes the net price for a traveler composition on a specific slot. The price is\n**locked for 30 minutes**: `POST /bookings` with this `quote_id` uses the computed\nprice even if the rate pack's rate has changed in the meantime.\n\nAfter 30 min the `quote_id` is invalidated and `POST /bookings` returns\n`quote.expired`. The bank must then create a new quote at the current rate.\n\nEvery age in `rooms[].children[].age` is classified against the adventure's `age_brackets`\nbefore pricing: at or below `infant_max_age` an infant, up to `child_max_age` a child,\nabove it an adult paying the adult rate. The rate pack tells you in advance what the\nclassification will cost you, through `children_allowed`, `infants_allowed`, `child_price`,\n`infant_price`, `max_children` and `max_infants`, so a composition can be checked against\n`GET /adventures/{slug}` without issuing a quote.\n\nFour `400` codes come from that composition: `adventure.children.not.accepted`,\n`adventure.infants.not.accepted`, `adventure.children.max.exceeded` and\n`adventure.infants.max.exceeded`. A fifth, `adventure.room.occupancy.exceeded`, is raised\nwhen a room holds more travellers than its `max_occupancy`, infants excepted.\n\nExample values are illustrative: take a real `adventure_slug` and\n`rate_pack_id` from `GET /adventures` / `GET /adventures/{slug}` (in the\nsandbox, slugs carry a `-sandbox` suffix).\n","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /quotes","href":"/api-reference/quotes/create-a-price-locked-quote","autogeneratedByOpenApi":true},"description":{"compiledSource":"\"use strict\";\nconst {Fragment: _Fragment, jsx: _jsx, jsxs: _jsxs} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n code: \"code\",\n p: \"p\",\n strong: \"strong\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsxs(_Fragment, {\n children: [_jsxs(_components.p, {\n children: [\"Computes the net price for a traveler composition on a specific slot. The price is\\n\", _jsx(_components.strong, {\n children: \"locked for 30 minutes\"\n }), \": \", _jsx(_components.code, {\n children: \"POST /bookings\"\n }), \" with this \", _jsx(_components.code, {\n children: \"quote_id\"\n }), \" uses the computed\\nprice even if the rate pack’s rate has changed in the meantime.\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"After 30 min the \", _jsx(_components.code, {\n children: \"quote_id\"\n }), \" is invalidated and \", _jsx(_components.code, {\n children: \"POST /bookings\"\n }), \" returns\\n\", _jsx(_components.code, {\n children: \"quote.expired\"\n }), \". The bank must then create a new quote at the current rate.\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"Every age in \", _jsx(_components.code, {\n children: \"rooms[].children[].age\"\n }), \" is classified against the adventure’s \", _jsx(_components.code, {\n children: \"age_brackets\"\n }), \"\\nbefore pricing: at or below \", _jsx(_components.code, {\n children: \"infant_max_age\"\n }), \" an infant, up to \", _jsx(_components.code, {\n children: \"child_max_age\"\n }), \" a child,\\nabove it an adult paying the adult rate. The rate pack tells you in advance what the\\nclassification will cost you, through \", _jsx(_components.code, {\n children: \"children_allowed\"\n }), \", \", _jsx(_components.code, {\n children: \"infants_allowed\"\n }), \", \", _jsx(_components.code, {\n children: \"child_price\"\n }), \",\\n\", _jsx(_components.code, {\n children: \"infant_price\"\n }), \", \", _jsx(_components.code, {\n children: \"max_children\"\n }), \" and \", _jsx(_components.code, {\n children: \"max_infants\"\n }), \", so a composition can be checked against\\n\", _jsx(_components.code, {\n children: \"GET /adventures/{slug}\"\n }), \" without issuing a quote.\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"Four \", _jsx(_components.code, {\n children: \"400\"\n }), \" codes come from that composition: \", _jsx(_components.code, {\n children: \"adventure.children.not.accepted\"\n }), \",\\n\", _jsx(_components.code, {\n children: \"adventure.infants.not.accepted\"\n }), \", \", _jsx(_components.code, {\n children: \"adventure.children.max.exceeded\"\n }), \" and\\n\", _jsx(_components.code, {\n children: \"adventure.infants.max.exceeded\"\n }), \". A fifth, \", _jsx(_components.code, {\n children: \"adventure.room.occupancy.exceeded\"\n }), \", is raised\\nwhen a room holds more travellers than its \", _jsx(_components.code, {\n children: \"max_occupancy\"\n }), \", infants excepted.\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"Example values are illustrative: take a real \", _jsx(_components.code, {\n children: \"adventure_slug\"\n }), \" and\\n\", _jsx(_components.code, {\n children: \"rate_pack_id\"\n }), \" from \", _jsx(_components.code, {\n children: \"GET /adventures\"\n }), \" / \", _jsx(_components.code, {\n children: \"GET /adventures/{slug}\"\n }), \" (in the\\nsandbox, slugs carry a \", _jsx(_components.code, {\n children: \"-sandbox\"\n }), \" suffix).\"]\n })]\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){return _jsx(_Fragment,{})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent}","frontmatter":{},"scope":{"codeStyling":{"theme":"github-dark-dimmed"},"config":{},"pageMetadata":{"title":"Create a price-locked quote","description":"Computes the net price for a traveler composition on a specific slot. The price is\n**locked for 30 minutes**: `POST /bookings` with this `quote_id` uses the computed\nprice even if the rate pack's rate has changed in the meantime.\n\nAfter 30 min the `quote_id` is invalidated and `POST /bookings` returns\n`quote.expired`. The bank must then create a new quote at the current rate.\n\nEvery age in `rooms[].children[].age` is classified against the adventure's `age_brackets`\nbefore pricing: at or below `infant_max_age` an infant, up to `child_max_age` a child,\nabove it an adult paying the adult rate. The rate pack tells you in advance what the\nclassification will cost you, through `children_allowed`, `infants_allowed`, `child_price`,\n`infant_price`, `max_children` and `max_infants`, so a composition can be checked against\n`GET /adventures/{slug}` without issuing a quote.\n\nFour `400` codes come from that composition: `adventure.children.not.accepted`,\n`adventure.infants.not.accepted`, `adventure.children.max.exceeded` and\n`adventure.infants.max.exceeded`. A fifth, `adventure.room.occupancy.exceeded`, is raised\nwhen a room holds more travellers than its `max_occupancy`, infants excepted.\n\nExample values are illustrative: take a real `adventure_slug` and\n`rate_pack_id` from `GET /adventures` / `GET /adventures/{slug}` (in the\nsandbox, slugs carry a `-sandbox` suffix).\n","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /quotes","href":"/api-reference/quotes/create-a-price-locked-quote","autogeneratedByOpenApi":true}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[],"codeExamples":{}},"jsLinks":["/_mintlify/custom/safariat/f751755c840beb5a/trust/tools/generate-cobranded-pdf.js"],"openApiReferenceData":{"operation":{"tags":["Quotes"],"operationId":"createQuote","summary":"Create a price-locked quote","description":"Computes the net price for a traveler composition on a specific slot. The price is\n**locked for 30 minutes**: `POST /bookings` with this `quote_id` uses the computed\nprice even if the rate pack's rate has changed in the meantime.\n\nAfter 30 min the `quote_id` is invalidated and `POST /bookings` returns\n`quote.expired`. The bank must then create a new quote at the current rate.\n\nEvery age in `rooms[].children[].age` is classified against the adventure's `age_brackets`\nbefore pricing: at or below `infant_max_age` an infant, up to `child_max_age` a child,\nabove it an adult paying the adult rate. The rate pack tells you in advance what the\nclassification will cost you, through `children_allowed`, `infants_allowed`, `child_price`,\n`infant_price`, `max_children` and `max_infants`, so a composition can be checked against\n`GET /adventures/{slug}` without issuing a quote.\n\nFour `400` codes come from that composition: `adventure.children.not.accepted`,\n`adventure.infants.not.accepted`, `adventure.children.max.exceeded` and\n`adventure.infants.max.exceeded`. A fifth, `adventure.room.occupancy.exceeded`, is raised\nwhen a room holds more travellers than its `max_occupancy`, infants excepted.\n\nExample values are illustrative: take a real `adventure_slug` and\n`rate_pack_id` from `GET /adventures` / `GET /adventures/{slug}` (in the\nsandbox, slugs carry a `-sandbox` suffix).\n","parameters":["edc95e8b-40b0-4db8-a62c-6425a5c278eb","52f785e9-91e7-43e2-b909-2996701a1f63","784cd47a-61e9-44de-b756-15511df45503"],"requestBody":"6ab5ca5b-7f79-431d-a61f-257240f4ffef","responses":{"201":"f46e8e4c-71b2-49ca-8256-8c1e88a7e608","400":"ebe5fee4-b860-4b67-aa8e-c8d8b92b7763","401":"d1f2dd29-e0ae-4a9e-819a-185c69a4b180","404":"6f35b35e-2ecc-4738-9c47-60ec753e3a38","409":"f71edc3a-6a1e-40f9-aac0-681429d722f2","422":"fd96e41c-8406-4fdc-be38-e29d8431fe26","429":"de8e56fb-de4a-4749-a007-20e17d90f31b"},"method":"post","type":"path","servers":["bef6bbb6-8b53-47c4-b0bd-53ed06e38170"],"security":["509b5ed1-5a9c-40f6-a981-6928a3ac2aa3"],"path":"/quotes","baseUrlOptions":["https://api.safarapi.com/api/partner/v1"],"title":"Create a price-locked quote","codeSamples":[],"requiredOnlyExamples":false,"requestExampleType":"generated","responseExampleType":"generated"},"dependencies":{"parameters":{"edc95e8b-40b0-4db8-a62c-6425a5c278eb":{"in":"header","name":"Idempotency-Key","required":true,"schema":{"type":"string","maxLength":255,"isRequired":true,"description":"Opaque, client-generated string unique per logical operation (a UUID v4 is\nrecommended but any non-blank value up to 255 chars is accepted). Same key +\nsame body = the cached response is returned with the `Idempotent-Replayed: true`\nheader. Same key + different body = `409 Conflict`. Retained for 24 h.\n","uniqueKey":"","typeLabel":"string"},"description":"Opaque, client-generated string unique per logical operation (a UUID v4 is\nrecommended but any non-blank value up to 255 chars is accepted). Same key +\nsame body = the cached response is returned with the `Idempotent-Replayed: true`\nheader. Same key + different body = `409 Conflict`. Retained for 24 h.\n"},"52f785e9-91e7-43e2-b909-2996701a1f63":{"in":"header","name":"X-Timestamp","required":true,"schema":{"type":"integer","format":"int64","isRequired":true,"description":"Unix timestamp in seconds at the time the request is issued. Validity window\n±5 minutes — beyond that the request is rejected. Required for production\n`sk_live_*` keys only; not required for sandbox `sk_test_*` keys.\n","uniqueKey":"","typeLabel":"integer\u003cint64>"},"description":"Unix timestamp in seconds at the time the request is issued. Validity window\n±5 minutes — beyond that the request is rejected. Required for production\n`sk_live_*` keys only; not required for sandbox `sk_test_*` keys.\n"},"784cd47a-61e9-44de-b756-15511df45503":{"in":"header","name":"X-Signature","required":true,"schema":{"type":"string","pattern":"^[a-f0-9]{64}$","isRequired":true,"description":"`hex(HMAC_SHA256(secret, \"{X-Timestamp}\\n{METHOD}\\n{path}\\n{body}\"))`.\nThe `path` includes the query string. The `body` is the exact JSON representation\nsent — any reformatting invalidates the signature. Required for production\n`sk_live_*` keys only; not required for sandbox `sk_test_*` keys.\n","uniqueKey":"","typeLabel":"string"},"description":"`hex(HMAC_SHA256(secret, \"{X-Timestamp}\\n{METHOD}\\n{path}\\n{body}\"))`.\nThe `path` includes the query string. The `body` is the exact JSON representation\nsent — any reformatting invalidates the signature. Required for production\n`sk_live_*` keys only; not required for sandbox `sk_test_*` keys.\n"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["adventure_slug","rate_pack_id","start_date","rooms"],"properties":{"adventure_slug":{"type":"string","pattern":"^[a-z0-9-]+$","isRequired":true,"uniqueKey":"adventure_slug","typeLabel":"string"},"rate_pack_id":{"type":"string","format":"uuid","isRequired":true,"uniqueKey":"rate_pack_id","typeLabel":"string\u003cuuid>"},"start_date":{"type":"string","format":"date","isRequired":true,"uniqueKey":"start_date","typeLabel":"string\u003cdate>"},"rooms":{"type":"array","minItems":1,"maxItems":10,"items":{"type":"object","description":"One entry per room booked: its traveller composition (adults + children with ages) and, when the rate pack exposes `room_types`, the room type booked. The room supplement is priced from these entries, so two adults in one room and two adults in two rooms no longer quote the same amount.","required":["adults"],"properties":{"adults":{"type":"integer","minimum":1,"maximum":6,"isRequired":true,"uniqueKey":"rooms.items.[INDEX].adults","typeLabel":"integer"},"children":{"type":"array","maxItems":6,"items":{"type":"object","required":["age"],"properties":{"age":{"type":"integer","minimum":0,"maximum":17,"isRequired":true,"uniqueKey":"rooms.items.[INDEX].children.items.[INDEX].age","typeLabel":"integer"}},"uniqueKey":"rooms.items.[INDEX].children.items.[INDEX]","typeLabel":"object"},"uniqueKey":"rooms.items.[INDEX].children","typeLabel":"object[]"},"room_type":{"oneOf":[{"type":"string","maxLength":100,"description":"Name of the booked room type, taken from `room_types[].name` on the rate pack.\nRequired when the rate pack exposes room types (`partner.quote.roomtype.required` /\n`partner.quote.roomtype.not.found` otherwise), ignored when it exposes none.\n","example":"Double","uniqueKey":"rooms.items.[INDEX].room_type.oneOf.0","typeLabel":"string"},{"type":"null","maxLength":100,"description":"Name of the booked room type, taken from `room_types[].name` on the rate pack.\nRequired when the rate pack exposes room types (`partner.quote.roomtype.required` /\n`partner.quote.roomtype.not.found` otherwise), ignored when it exposes none.\n","example":"Double","uniqueKey":"rooms.items.[INDEX].room_type.oneOf.1","typeLabel":"null"}],"uniqueKey":"rooms.items.[INDEX].room_type","typeLabel":"string | null"}},"uniqueKey":"rooms.items.[INDEX]","typeLabel":"object"},"isRequired":true,"uniqueKey":"rooms","typeLabel":"object[]"},"start_time":{"oneOf":[{"type":"string","pattern":"^[0-2][0-9]:[0-5][0-9]$","description":"Required on an EXPERIENCE whose rate pack exposes `start_times`\n(`partner.quote.starttime.required` otherwise). Optional on a TRIP, whose departure hour\nis informative. In both cases a value that is not one of the pack `start_times` is\nrejected (`partner.quote.starttime.not.available`). Returned as null for a pack that\nexposes no start time, flexible packs included.\n","uniqueKey":"start_time.oneOf.0","typeLabel":"string"},{"type":"null","pattern":"^[0-2][0-9]:[0-5][0-9]$","description":"Required on an EXPERIENCE whose rate pack exposes `start_times`\n(`partner.quote.starttime.required` otherwise). Optional on a TRIP, whose departure hour\nis informative. In both cases a value that is not one of the pack `start_times` is\nrejected (`partner.quote.starttime.not.available`). Returned as null for a pack that\nexposes no start time, flexible packs included.\n","uniqueKey":"start_time.oneOf.1","typeLabel":"null"}],"uniqueKey":"start_time","typeLabel":"string | null"}},"uniqueKey":"","typeLabel":"object"},"example":{"adventure_slug":"marrakech-3-jours-desert-sandbox","rate_pack_id":"4a700002-0000-4000-8000-0000000000f2","start_date":"2026-07-12","rooms":[{"adults":2,"children":[{"age":8},{"age":12}]}]},"examples":{"Example":{"title":"Example","value":{"adventure_slug":"marrakech-3-jours-desert-sandbox","rate_pack_id":"4a700002-0000-4000-8000-0000000000f2","start_date":"2026-07-12","rooms":[{"adults":2,"children":[{"age":8},{"age":12}]}]}}},"exampleType":"examples"}},"exampleType":"examples"},"responses":{"f46e8e4c-71b2-49ca-8256-8c1e88a7e608":{"description":"Quote created","content":{"application/json":{"schema":{"type":"object","required":["id","expires_at","pricing","breakdown"],"properties":{"id":{"type":"string","format":"uuid","isRequired":true,"uniqueKey":"id","typeLabel":"string\u003cuuid>"},"pricing":{"type":"object","description":"Revenue breakdown (locked price; `indicative = false`, `sandbox_surcharge = 0`).\n`pricing.amount_due_to_safariat` is the amount-match anchor for booking creation.\n","required":["b2c_price","customer_price","amount_due_to_safariat","awb_commission_share","sandbox_surcharge","partner_revenue","indicative"],"properties":{"b2c_price":{"type":"object","required":["amount","currency"],"properties":{"amount":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Amount as a decimal string with 2 decimals to preserve precision.","example":"3200.00","isRequired":true,"uniqueKey":"pricing.b2c_price.amount","typeLabel":"string"},"currency":{"type":"string","enum":["MAD"],"description":"Currency — MAD only in V1.","example":"MAD","isRequired":true,"uniqueKey":"pricing.b2c_price.currency","typeLabel":"enum\u003cstring>"}},"description":"Public B2C reference price (price floor guaranteed to the customer).","isRequired":true,"uniqueKey":"pricing.b2c_price","typeLabel":"object"},"customer_price":{"type":"object","required":["amount","currency"],"properties":{"amount":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Amount as a decimal string with 2 decimals to preserve precision.","example":"3200.00","isRequired":true,"uniqueKey":"pricing.customer_price.amount","typeLabel":"string"},"currency":{"type":"string","enum":["MAD"],"description":"Currency — MAD only in V1.","example":"MAD","isRequired":true,"uniqueKey":"pricing.customer_price.currency","typeLabel":"enum\u003cstring>"}},"description":"Total price paid by the customer = `b2c_price + sandbox_surcharge`. Equals `b2c_price` before booking.","isRequired":true,"uniqueKey":"pricing.customer_price","typeLabel":"object"},"amount_due_to_safariat":{"type":"object","required":["amount","currency"],"properties":{"amount":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Amount as a decimal string with 2 decimals to preserve precision.","example":"3200.00","isRequired":true,"uniqueKey":"pricing.amount_due_to_safariat.amount","typeLabel":"string"},"currency":{"type":"string","enum":["MAD"],"description":"Currency — MAD only in V1.","example":"MAD","isRequired":true,"uniqueKey":"pricing.amount_due_to_safariat.currency","typeLabel":"enum\u003cstring>"}},"description":"Net reversed to Safariat = operator share + 65% of the base commission (the daily wire amount).","isRequired":true,"uniqueKey":"pricing.amount_due_to_safariat","typeLabel":"object"},"awb_commission_share":{"type":"object","required":["amount","currency"],"properties":{"amount":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Amount as a decimal string with 2 decimals to preserve precision.","example":"3200.00","isRequired":true,"uniqueKey":"pricing.awb_commission_share.amount","typeLabel":"string"},"currency":{"type":"string","enum":["MAD"],"description":"Currency — MAD only in V1.","example":"MAD","isRequired":true,"uniqueKey":"pricing.awb_commission_share.currency","typeLabel":"enum\u003cstring>"}},"description":"AWB's 35% share of the base commission.","isRequired":true,"uniqueKey":"pricing.awb_commission_share","typeLabel":"object"},"sandbox_surcharge":{"type":"object","required":["amount","currency"],"properties":{"amount":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Amount as a decimal string with 2 decimals to preserve precision.","example":"3200.00","isRequired":true,"uniqueKey":"pricing.sandbox_surcharge.amount","typeLabel":"string"},"currency":{"type":"string","enum":["MAD"],"description":"Currency — MAD only in V1.","example":"MAD","isRequired":true,"uniqueKey":"pricing.sandbox_surcharge.currency","typeLabel":"enum\u003cstring>"}},"description":"AWB's own surcharge (100% AWB), derived as `customer_price − b2c_price`. `0` before booking.","isRequired":true,"uniqueKey":"pricing.sandbox_surcharge","typeLabel":"object"},"partner_revenue":{"type":"object","required":["amount","currency"],"properties":{"amount":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Amount as a decimal string with 2 decimals to preserve precision.","example":"3200.00","isRequired":true,"uniqueKey":"pricing.partner_revenue.amount","typeLabel":"string"},"currency":{"type":"string","enum":["MAD"],"description":"Currency — MAD only in V1.","example":"MAD","isRequired":true,"uniqueKey":"pricing.partner_revenue.currency","typeLabel":"enum\u003cstring>"}},"description":"Total kept by the partner on this booking = `awb_commission_share + sandbox_surcharge`.\nProvided so reporting never has to add the two components client-side.\n","isRequired":true,"uniqueKey":"pricing.partner_revenue","typeLabel":"object"},"indicative":{"type":"boolean","description":"`true` for catalog/quote \"from\" prices (final amounts confirmed at booking);\n`false` on booking responses.\n","isRequired":true,"uniqueKey":"pricing.indicative","typeLabel":"boolean"}},"isRequired":true,"uniqueKey":"pricing","typeLabel":"object"},"breakdown":{"type":"array","description":"Priced lines making up the quote. `travelers` is always present; `room_supplement` appears\nwhen the booked room types carry a supplement. The lines sum to the gross price found in\n`pricing`.\n","items":{"type":"object","required":["label","quantity","unit_amount","subtotal"],"properties":{"label":{"type":"string","enum":["travelers","room_supplement"],"isRequired":true,"uniqueKey":"breakdown.items.[INDEX].label","typeLabel":"enum\u003cstring>"},"quantity":{"type":"integer","description":"Traveller count for `travelers`, room count for `room_supplement`.","isRequired":true,"uniqueKey":"breakdown.items.[INDEX].quantity","typeLabel":"integer"},"unit_amount":{"type":"object","required":["amount","currency"],"properties":{"amount":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Amount as a decimal string with 2 decimals to preserve precision.","example":"3200.00","isRequired":true,"uniqueKey":"breakdown.items.[INDEX].unit_amount.amount","typeLabel":"string"},"currency":{"type":"string","enum":["MAD"],"description":"Currency — MAD only in V1.","example":"MAD","isRequired":true,"uniqueKey":"breakdown.items.[INDEX].unit_amount.currency","typeLabel":"enum\u003cstring>"}},"isRequired":true,"uniqueKey":"breakdown.items.[INDEX].unit_amount","typeLabel":"object"},"subtotal":{"type":"object","required":["amount","currency"],"properties":{"amount":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Amount as a decimal string with 2 decimals to preserve precision.","example":"3200.00","isRequired":true,"uniqueKey":"breakdown.items.[INDEX].subtotal.amount","typeLabel":"string"},"currency":{"type":"string","enum":["MAD"],"description":"Currency — MAD only in V1.","example":"MAD","isRequired":true,"uniqueKey":"breakdown.items.[INDEX].subtotal.currency","typeLabel":"enum\u003cstring>"}},"isRequired":true,"uniqueKey":"breakdown.items.[INDEX].subtotal","typeLabel":"object"}},"uniqueKey":"breakdown.items.[INDEX]","typeLabel":"object"},"isRequired":true,"uniqueKey":"breakdown","typeLabel":"object[]"},"expires_at":{"type":"string","format":"date-time","description":"30-minute TTL after creation.","isRequired":true,"uniqueKey":"expires_at","typeLabel":"string\u003cdate-time>"},"adventure_slug":{"type":"string","uniqueKey":"adventure_slug","typeLabel":"string"},"rate_pack_id":{"type":"string","format":"uuid","uniqueKey":"rate_pack_id","typeLabel":"string\u003cuuid>"},"start_date":{"type":"string","format":"date","uniqueKey":"start_date","typeLabel":"string\u003cdate>"},"start_time":{"oneOf":[{"type":"string","uniqueKey":"start_time.oneOf.0","typeLabel":"string"},{"type":"null","uniqueKey":"start_time.oneOf.1","typeLabel":"null"}],"uniqueKey":"start_time","typeLabel":"string | null"},"rooms":{"type":"array","items":{"type":"object","description":"One entry per room booked: its traveller composition (adults + children with ages) and, when the rate pack exposes `room_types`, the room type booked. The room supplement is priced from these entries, so two adults in one room and two adults in two rooms no longer quote the same amount.","required":["adults"],"properties":{"adults":{"type":"integer","minimum":1,"maximum":6,"isRequired":true,"uniqueKey":"rooms.items.[INDEX].adults","typeLabel":"integer"},"children":{"type":"array","maxItems":6,"items":{"type":"object","required":["age"],"properties":{"age":{"type":"integer","minimum":0,"maximum":17,"isRequired":true,"uniqueKey":"rooms.items.[INDEX].children.items.[INDEX].age","typeLabel":"integer"}},"uniqueKey":"rooms.items.[INDEX].children.items.[INDEX]","typeLabel":"object"},"uniqueKey":"rooms.items.[INDEX].children","typeLabel":"object[]"},"room_type":{"oneOf":[{"type":"string","maxLength":100,"description":"Name of the booked room type, taken from `room_types[].name` on the rate pack.\nRequired when the rate pack exposes room types (`partner.quote.roomtype.required` /\n`partner.quote.roomtype.not.found` otherwise), ignored when it exposes none.\n","example":"Double","uniqueKey":"rooms.items.[INDEX].room_type.oneOf.0","typeLabel":"string"},{"type":"null","maxLength":100,"description":"Name of the booked room type, taken from `room_types[].name` on the rate pack.\nRequired when the rate pack exposes room types (`partner.quote.roomtype.required` /\n`partner.quote.roomtype.not.found` otherwise), ignored when it exposes none.\n","example":"Double","uniqueKey":"rooms.items.[INDEX].room_type.oneOf.1","typeLabel":"null"}],"uniqueKey":"rooms.items.[INDEX].room_type","typeLabel":"string | null"}},"uniqueKey":"rooms.items.[INDEX]","typeLabel":"object"},"uniqueKey":"rooms","typeLabel":"object[]"}},"uniqueKey":"","typeLabel":"object"},"example":{"id":"9b2e4c7a-1f3d-4a8b-9c0e-2d5f6a7b8c90","adventure_slug":"marrakech-3-jours-desert-sandbox","rate_pack_id":"4a700002-0000-4000-8000-0000000000f2","start_date":"2026-07-12","start_time":null,"rooms":[{"adults":2,"children":[{"age":8},{"age":12}]}],"pricing":{"b2c_price":{"amount":"6000.00","currency":"MAD"},"customer_price":{"amount":"6000.00","currency":"MAD"},"amount_due_to_safariat":{"amount":"5900.00","currency":"MAD"},"awb_commission_share":{"amount":"100.00","currency":"MAD"},"sandbox_surcharge":{"amount":"0.00","currency":"MAD"},"partner_revenue":{"amount":"100.00","currency":"MAD"},"indicative":false},"breakdown":{"adults":{"count":2,"unit_price":{"amount":"2400.00","currency":"MAD"},"subtotal":{"amount":"4800.00","currency":"MAD"}},"children":{"count":2,"subtotal":{"amount":"600.00","currency":"MAD"}},"extra_beds":{"count":0,"unit_price":{"amount":"0.00","currency":"MAD"},"subtotal":{"amount":"0.00","currency":"MAD"}},"rooms_total":{"amount":"5400.00","currency":"MAD"}},"expires_at":"2026-07-12T10:30:00Z"},"examples":{"Example":{"title":"Example","value":{"id":"9b2e4c7a-1f3d-4a8b-9c0e-2d5f6a7b8c90","adventure_slug":"marrakech-3-jours-desert-sandbox","rate_pack_id":"4a700002-0000-4000-8000-0000000000f2","start_date":"2026-07-12","start_time":null,"rooms":[{"adults":2,"children":[{"age":8},{"age":12}]}],"pricing":{"b2c_price":{"amount":"6000.00","currency":"MAD"},"customer_price":{"amount":"6000.00","currency":"MAD"},"amount_due_to_safariat":{"amount":"5900.00","currency":"MAD"},"awb_commission_share":{"amount":"100.00","currency":"MAD"},"sandbox_surcharge":{"amount":"0.00","currency":"MAD"},"partner_revenue":{"amount":"100.00","currency":"MAD"},"indicative":false},"breakdown":{"adults":{"count":2,"unit_price":{"amount":"2400.00","currency":"MAD"},"subtotal":{"amount":"4800.00","currency":"MAD"}},"children":{"count":2,"subtotal":{"amount":"600.00","currency":"MAD"}},"extra_beds":{"count":0,"unit_price":{"amount":"0.00","currency":"MAD"},"subtotal":{"amount":"0.00","currency":"MAD"}},"rooms_total":{"amount":"5400.00","currency":"MAD"}},"expires_at":"2026-07-12T10:30:00Z"}}},"exampleType":"examples"}},"exampleType":"examples"},"ebe5fee4-b860-4b67-aa8e-c8d8b92b7763":{"description":"Malformed request (syntactic validation).\n\nA request body carrying a field this endpoint does not declare is rejected with\n`partner.request.field.unknown`, naming the offending field. Unknown fields are never\nignored: a misspelling would otherwise drop data silently, and on `POST /quotes` that\nmeans quoting a party smaller than the one you sent.\n","content":{"application/json":{"schema":{"type":"object","required":["code","message","request_id"],"properties":{"code":{"type":"string","description":"Stable, documented i18n code. Form `domain.subdomain.detail`\n(e.g. `payment.amount.mismatch`, `auth.api_key.invalid`).\n","example":"validation.required.field","isRequired":true,"uniqueKey":"code","typeLabel":"string"},"message":{"type":"string","description":"English message (for bank logs). API errors are never localized on the Safariat side.","example":"Field 'rate_pack_id' is required.","isRequired":true,"uniqueKey":"message","typeLabel":"string"},"request_id":{"type":"string","description":"Unique request ID on the Safariat side.","isRequired":true,"uniqueKey":"request_id","typeLabel":"string"},"details":{"type":"object","description":"Optional structured details (offending field, expected value, etc.).","additionalProperties":true,"uniqueKey":"details","typeLabel":"object"}},"uniqueKey":"","typeLabel":"object"},"examples":{"missingField":{"title":"missingField","value":{"code":"validation.required.field","message":"Field 'rate_pack_id' is required.","request_id":"01HXY2ZRPM3R8K9PSBTRQYNFHC"}},"unknownField":{"title":"unknownField","value":{"code":"partner.request.field.unknown","message":"Unknown field 'children_ages' in the request body.","request_id":"01HXY2ZRPM3R8K9PSBTRQYNFHD"}}},"exampleType":"examples"}},"exampleType":"examples"},"d1f2dd29-e0ae-4a9e-819a-185c69a4b180":{"description":"API key missing, invalid, expired, or incorrect HMAC signature.","content":{"application/json":{"schema":{"type":"object","required":["code","message","request_id"],"properties":{"code":{"type":"string","description":"Stable, documented i18n code. Form `domain.subdomain.detail`\n(e.g. `payment.amount.mismatch`, `auth.api_key.invalid`).\n","example":"validation.required.field","isRequired":true,"uniqueKey":"code","typeLabel":"string"},"message":{"type":"string","description":"English message (for bank logs). API errors are never localized on the Safariat side.","example":"Field 'rate_pack_id' is required.","isRequired":true,"uniqueKey":"message","typeLabel":"string"},"request_id":{"type":"string","description":"Unique request ID on the Safariat side.","isRequired":true,"uniqueKey":"request_id","typeLabel":"string"},"details":{"type":"object","description":"Optional structured details (offending field, expected value, etc.).","additionalProperties":true,"uniqueKey":"details","typeLabel":"object"}},"uniqueKey":"","typeLabel":"object"},"examples":{"missing":{"title":"missing","value":{"code":"auth.api_key.missing","message":"Authorization header is required.","request_id":"01HXY2ZRPM3R8K9PSBTRQYNFHC"}},"invalid":{"title":"invalid","value":{"code":"auth.api_key.invalid","message":"The provided API key is invalid or has been revoked.","request_id":"01HXY2ZRPM3R8K9PSBTRQYNFHC"}},"signatureInvalid":{"title":"signatureInvalid","value":{"code":"auth.signature.invalid","message":"HMAC signature does not match.","request_id":"01HXY2ZRPM3R8K9PSBTRQYNFHC"}},"timestampSkew":{"title":"timestampSkew","value":{"code":"auth.timestamp.skew","message":"Timestamp is more than 5 minutes off server time.","request_id":"01HXY2ZRPM3R8K9PSBTRQYNFHC"}}},"exampleType":"examples"}},"exampleType":"examples"},"6f35b35e-2ecc-4738-9c47-60ec753e3a38":{"description":"Resource does not exist or is inaccessible for this partner.","content":{"application/json":{"schema":{"type":"object","required":["code","message","request_id"],"properties":{"code":{"type":"string","description":"Stable, documented i18n code. Form `domain.subdomain.detail`\n(e.g. `payment.amount.mismatch`, `auth.api_key.invalid`).\n","example":"validation.required.field","isRequired":true,"uniqueKey":"code","typeLabel":"string"},"message":{"type":"string","description":"English message (for bank logs). API errors are never localized on the Safariat side.","example":"Field 'rate_pack_id' is required.","isRequired":true,"uniqueKey":"message","typeLabel":"string"},"request_id":{"type":"string","description":"Unique request ID on the Safariat side.","isRequired":true,"uniqueKey":"request_id","typeLabel":"string"},"details":{"type":"object","description":"Optional structured details (offending field, expected value, etc.).","additionalProperties":true,"uniqueKey":"details","typeLabel":"object"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"code":"validation.required.field","message":"Field 'rate_pack_id' is required.","request_id":"\u003cstring>","details":{}}}},"exampleType":"generated"}},"exampleType":"generated"},"f71edc3a-6a1e-40f9-aac0-681429d722f2":{"description":"The same `Idempotency-Key` was reused with a different body. No action performed.\n","content":{"application/json":{"schema":{"type":"object","required":["code","message","request_id"],"properties":{"code":{"type":"string","description":"Stable, documented i18n code. Form `domain.subdomain.detail`\n(e.g. `payment.amount.mismatch`, `auth.api_key.invalid`).\n","example":"validation.required.field","isRequired":true,"uniqueKey":"code","typeLabel":"string"},"message":{"type":"string","description":"English message (for bank logs). API errors are never localized on the Safariat side.","example":"Field 'rate_pack_id' is required.","isRequired":true,"uniqueKey":"message","typeLabel":"string"},"request_id":{"type":"string","description":"Unique request ID on the Safariat side.","isRequired":true,"uniqueKey":"request_id","typeLabel":"string"},"details":{"type":"object","description":"Optional structured details (offending field, expected value, etc.).","additionalProperties":true,"uniqueKey":"details","typeLabel":"object"}},"uniqueKey":"","typeLabel":"object"},"example":{"code":"idempotency.key.conflict","message":"Idempotency-Key already used with a different request body.","request_id":"01HXY2ZRPM3R8K9PSBTRQYNFHC"},"examples":{"Example":{"title":"Example","value":{"code":"idempotency.key.conflict","message":"Idempotency-Key already used with a different request body.","request_id":"01HXY2ZRPM3R8K9PSBTRQYNFHC"}}},"exampleType":"examples"}},"exampleType":"examples"},"fd96e41c-8406-4fdc-be38-e29d8431fe26":{"description":"Business rule violated: `adventure.capacity.exhausted` (the requested party size exceeds the remaining capacity of the slot). A quote never holds capacity, so a slot validated here may still be exhausted by the time the booking is created.","content":{"application/json":{"schema":{"type":"object","required":["code","message","request_id"],"properties":{"code":{"type":"string","description":"Stable, documented i18n code. Form `domain.subdomain.detail`\n(e.g. `payment.amount.mismatch`, `auth.api_key.invalid`).\n","example":"validation.required.field","isRequired":true,"uniqueKey":"code","typeLabel":"string"},"message":{"type":"string","description":"English message (for bank logs). API errors are never localized on the Safariat side.","example":"Field 'rate_pack_id' is required.","isRequired":true,"uniqueKey":"message","typeLabel":"string"},"request_id":{"type":"string","description":"Unique request ID on the Safariat side.","isRequired":true,"uniqueKey":"request_id","typeLabel":"string"},"details":{"type":"object","description":"Optional structured details (offending field, expected value, etc.).","additionalProperties":true,"uniqueKey":"details","typeLabel":"object"}},"uniqueKey":"","typeLabel":"object"},"examples":{"capacityExhausted":{"title":"capacityExhausted","value":{"code":"adventure.capacity.exhausted","message":"No remaining capacity for this slot.","request_id":"01HXY2ZRPM3R8K9PSBTRQYNFHE"}}},"exampleType":"examples"}},"exampleType":"examples"},"de8e56fb-de4a-4749-a007-20e17d90f31b":{"description":"Rate limit exceeded for the current key.","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait before the next attempt (RFC 7231)."},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Request limit per minute for the current key."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp (s) at which the window resets."}},"content":{"application/json":{"schema":{"type":"object","required":["code","message","request_id"],"properties":{"code":{"type":"string","description":"Stable, documented i18n code. Form `domain.subdomain.detail`\n(e.g. `payment.amount.mismatch`, `auth.api_key.invalid`).\n","example":"validation.required.field","isRequired":true,"uniqueKey":"code","typeLabel":"string"},"message":{"type":"string","description":"English message (for bank logs). API errors are never localized on the Safariat side.","example":"Field 'rate_pack_id' is required.","isRequired":true,"uniqueKey":"message","typeLabel":"string"},"request_id":{"type":"string","description":"Unique request ID on the Safariat side.","isRequired":true,"uniqueKey":"request_id","typeLabel":"string"},"details":{"type":"object","description":"Optional structured details (offending field, expected value, etc.).","additionalProperties":true,"uniqueKey":"details","typeLabel":"object"}},"uniqueKey":"","typeLabel":"object"},"example":{"code":"rate_limit.exceeded","message":"Rate limit exceeded for this API key.","request_id":"01HXY2ZRPM3R8K9PSBTRQYNFHC"},"examples":{"Example":{"title":"Example","value":{"code":"rate_limit.exceeded","message":"Rate limit exceeded for this API key.","request_id":"01HXY2ZRPM3R8K9PSBTRQYNFHC"}}},"exampleType":"examples"}},"exampleType":"examples"}},"security":{"509b5ed1-5a9c-40f6-a981-6928a3ac2aa3":{"apiKey":{"type":"http","scheme":"bearer","bearerFormat":"sk_live_\u003cprefix>_\u003csecret> or sk_test_\u003cprefix>_\u003csecret>","x-default":"sk_test_DEMO0000_replace_with_your_sandbox_key","description":"API key authentication. Issued by the Safariat admin or via the partner portal.\nThe secret is shown only once at generation.\n\nProduction `sk_live_*` keys must additionally sign every write request\n(`POST`/`PUT`/`DELETE`) with the `X-Timestamp` and `X-Signature` headers.\nSandbox `sk_test_*` keys are exempt from request signing: `X-Signature` and\n`X-Timestamp` are not required for writes in the sandbox (so the developer-portal\n\"Try it\" playground works end to end). The `Idempotency-Key` header remains\nrequired on writes in both environments.\n","scopes":[]}}},"servers":{"bef6bbb6-8b53-47c4-b0bd-53ed06e38170":{"url":"https://api.safarapi.com/api/partner/v1","description":"Production and sandbox share this host. The environment is selected by the API key prefix: sk_live_ targets production, sk_test_ targets the sandbox."}},"processedSecurityOptions":[{"schemes":[{"scheme":{"type":"http","scheme":"bearer","bearerFormat":"sk_live_\u003cprefix>_\u003csecret> or sk_test_\u003cprefix>_\u003csecret>","x-default":"sk_test_DEMO0000_replace_with_your_sandbox_key","description":"API key authentication. Issued by the Safariat admin or via the partner portal.\nThe secret is shown only once at generation.\n\nProduction `sk_live_*` keys must additionally sign every write request\n(`POST`/`PUT`/`DELETE`) with the `X-Timestamp` and `X-Signature` headers.\nSandbox `sk_test_*` keys are exempt from request signing: `X-Signature` and\n`X-Timestamp` are not required for writes in the sandbox (so the developer-portal\n\"Try it\" playground works end to end). The `Idempotency-Key` header remains\nrequired on writes in both environments.\n","scopes":[]},"schema":{"title":"Bearer Auth","type":"string","isRequired":true,"description":"API key authentication. Issued by the Safariat admin or via the partner portal.\nThe secret is shown only once at generation.\n\nProduction `sk_live_*` keys must additionally sign every write request\n(`POST`/`PUT`/`DELETE`) with the `X-Timestamp` and `X-Signature` headers.\nSandbox `sk_test_*` keys are exempt from request signing: `X-Signature` and\n`X-Timestamp` are not required for writes in the sandbox (so the developer-portal\n\"Try it\" playground works end to end). The `Idempotency-Key` header remains\nrequired on writes in both environments.\n","format":"bearer","default":"sk_test_DEMO0000_replace_with_your_sandbox_key","typeLabel":"string\u003cbearer>","deprecated":false},"schemeName":"apiKey","name":"Authorization"}],"title":"apiKey"}]},"originalFileLocation":"api-reference/openapi.yaml"},"subdomain":"safariat","siteName":"SafarAPI","title":"SafarAPI — Morocco travel API for banks \u0026 fintechs","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-09-05T20:07:20.962Z","originalFileLocation":"api-reference/quotes/create-a-price-locked-quote.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"system\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Computes the net price for a traveler composition on a specific slot. The price is locked for 30 minutes: POST /bookings with this quote_id uses the computed price even if the rate pack\u0026#x27;s rate has changed in the meantime. After 30 min the quote_id is invalidated and POST /bookings returns quote.expired. The bank must then create a new quote at the current rate. Every age in rooms[].children[].age is classified against the adventure\u0026#x27;s age_brackets before pricing: at or below infant_max_age an infant, up to child_max_age a child, above it an adult paying the adult rate. The rate pack tells you in advance what the classification will cost you, through children_allowed, infants_allowed, child_price, infant_price, max_children and max_infants, so a composition can be checked against GET /adventures/{slug} without issuing a quote. Four 400 codes come from that composition: adventure.children.not.accepted, adventure.infants.not.accepted, adventure.children.max.exceeded and adventure.infants.max.exceeded. A fifth, adventure.room.occupancy.exceeded, is raised when a room holds more travellers than its max_occupancy, infants excepted. Example values are illustrative: take a real adventure_slug and rate_pack_id from GET /adventures / GET /adventures/{slug} (in the sandbox, slugs carry a -sandbox suffix).\">\u003cmeta data-mint-head name=\"application-name\" content=\"SafarAPI\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/safariat/edKFf_9gmlxKUwaY/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/safariat/edKFf_9gmlxKUwaY/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/safariat/edKFf_9gmlxKUwaY/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/safariat/edKFf_9gmlxKUwaY/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/safariat/edKFf_9gmlxKUwaY/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/safariat/edKFf_9gmlxKUwaY/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/safariat/edKFf_9gmlxKUwaY/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/safariat/edKFf_9gmlxKUwaY/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/safariat/edKFf_9gmlxKUwaY/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"SafarAPI — Morocco travel API for banks \u0026amp; fintechs\">\u003cmeta data-mint-head property=\"og:description\" content=\"Quote, book and settle curated Moroccan travel from your banking app. Sandbox in minutes, production in 7 days.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"SafarAPI\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://developers.safarapi.com/api-reference/quotes/create-a-price-locked-quote\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://safariat.mintlify.site/_mintlify/api/og/v2?division=Quotes\u0026amp;title=Create+a+price-locked+quote\u0026amp;description=Computes+the+net+price+for+a+traveler+composition+on+a+specific+slot.+The+price+is%0A**locked+for+30+minutes**%3A+%60POST+%2Fbookings%60+with+this+%60quote_id%60+uses+the+com\u0026amp;theme=3b8c95b43b12f994ae542965\u0026amp;signature=222128dbad05de5f19690b0149b57ff25300ae511aa85aa233990878a1de9644\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"SafarAPI — Morocco travel API for banks \u0026amp; fintechs\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Quote, book and settle curated Moroccan travel from your banking app. Sandbox in minutes, production in 7 days.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://safariat.mintlify.site/_mintlify/api/og/v2?division=Quotes\u0026amp;title=Create+a+price-locked+quote\u0026amp;description=Computes+the+net+price+for+a+traveler+composition+on+a+specific+slot.+The+price+is%0A**locked+for+30+minutes**%3A+%60POST+%2Fbookings%60+with+this+%60quote_id%60+uses+the+com\u0026amp;theme=3b8c95b43b12f994ae542965\u0026amp;signature=222128dbad05de5f19690b0149b57ff25300ae511aa85aa233990878a1de9644\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/safariat/edKFf_9gmlxKUwaY/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"SafarAPI\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#f2460d\">\u003clink data-mint-head rel=\"canonical\" href=\"https://developers.safarapi.com/api-reference/quotes/create-a-price-locked-quote\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/api-reference/quotes/create-a-price-locked-quote.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://developers.safarapi.com/#organization\",\"name\":\"SafarAPI\",\"url\":\"https://developers.safarapi.com\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/safariat/uq0i7jK0LmN_yZ-e/logo/safarapi-light.svg?fit=max\u0026auto=format\u0026n=uq0i7jK0LmN_yZ-e\u0026q=85\u0026s=6e54d448368f1737309eebb08e5e571c\"}},{\"@type\":\"WebSite\",\"@id\":\"https://developers.safarapi.com#website\",\"name\":\"SafarAPI\",\"url\":\"https://developers.safarapi.com\",\"publisher\":{\"@id\":\"https://developers.safarapi.com/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://developers.safarapi.com/api-reference/quotes/create-a-price-locked-quote#webpage\",\"url\":\"https://developers.safarapi.com/api-reference/quotes/create-a-price-locked-quote\",\"name\":\"Create a price-locked quote\",\"description\":\"Computes the net price for a traveler composition on a specific slot. The price is locked for 30 minutes: POST /bookings with this quote_id uses the computed price even if the rate pack's rate has changed in the meantime. After 30 min the quote_id is invalidated and POST /bookings returns quote.expired. The bank must then create a new quote at the current rate. Every age in rooms[].children[].age is classified against the adventure's age_brackets before pricing: at or below infant_max_age an infant, up to child_max_age a child, above it an adult paying the adult rate. The rate pack tells you in advance what the classification will cost you, through children_allowed, infants_allowed, child_price, infant_price, max_children and max_infants, so a composition can be checked against GET /adventures/{slug} without issuing a quote. Four 400 codes come from that composition: adventure.children.not.accepted, adventure.infants.not.accepted, adventure.children.max.exceeded and adventure.infants.max.exceeded. A fifth, adventure.room.occupancy.exceeded, is raised when a room holds more travellers than its max_occupancy, infants excepted. Example values are illustrative: take a real adventure_slug and rate_pack_id from GET /adventures / GET /adventures/{slug} (in the sandbox, slugs carry a -sandbox suffix).\",\"dateModified\":\"2026-09-05T20:07:20.962Z\",\"isPartOf\":{\"@id\":\"https://developers.safarapi.com#website\"},\"breadcrumb\":{\"@id\":\"https://developers.safarapi.com/api-reference/quotes/create-a-price-locked-quote#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://developers.safarapi.com/api-reference/quotes/create-a-price-locked-quote#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Endpoints\",\"item\":\"https://developers.safarapi.com/api-reference/meta/service-status\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Quotes\",\"item\":\"https://developers.safarapi.com/api-reference/quotes/list-quotes\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Create a price-locked quote\",\"item\":\"https://developers.safarapi.com/api-reference/quotes/create-a-price-locked-quote\"}]},{\"@type\":[\"TechArticle\",\"APIReference\"],\"@id\":\"https://developers.safarapi.com/api-reference/quotes/create-a-price-locked-quote#apireference\",\"headline\":\"Create a price-locked quote\",\"name\":\"Create a price-locked quote\",\"description\":\"Computes the net price for a traveler composition on a specific slot. The price is locked for 30 minutes: POST /bookings with this quote_id uses the computed price even if the rate pack's rate has changed in the meantime. After 30 min the quote_id is invalidated and POST /bookings returns quote.expired. The bank must then create a new quote at the current rate. Every age in rooms[].children[].age is classified against the adventure's age_brackets before pricing: at or below infant_max_age an infant, up to child_max_age a child, above it an adult paying the adult rate. The rate pack tells you in advance what the classification will cost you, through children_allowed, infants_allowed, child_price, infant_price, max_children and max_infants, so a composition can be checked against GET /adventures/{slug} without issuing a quote. Four 400 codes come from that composition: adventure.children.not.accepted, adventure.infants.not.accepted, adventure.children.max.exceeded and adventure.infants.max.exceeded. A fifth, adventure.room.occupancy.exceeded, is raised when a room holds more travellers than its max_occupancy, infants excepted. Example values are illustrative: take a real adventure_slug and rate_pack_id from GET /adventures / GET /adventures/{slug} (in the sandbox, slugs carry a -sandbox suffix).\",\"url\":\"https://developers.safarapi.com/api-reference/quotes/create-a-price-locked-quote\",\"mainEntityOfPage\":{\"@id\":\"https://developers.safarapi.com/api-reference/quotes/create-a-price-locked-quote#webpage\"},\"dateModified\":\"2026-09-05T20:07:20.962Z\",\"publisher\":{\"@id\":\"https://developers.safarapi.com/#organization\"},\"isPartOf\":{\"@id\":\"https://developers.safarapi.com#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"SafarAPI\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"SafarAPI","nav":{"global":null,"tabs":[{"tab":"Guides","pages":[{"title":"Guides","href":"/introduction/welcome"}]},{"tab":"API Reference","groups":[{"group":"Using the API","pages":[{"title":"Overview","href":"/api-reference/openapi"},{"title":"SDKs \u0026 tooling","href":"/api-reference/tooling"}]},{"group":"Endpoints","pages":[{"group":"Meta","pages":[{"title":"Service status","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /health","href":"/api-reference/meta/service-status"},{"title":"Read partner configuration","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /me/config","href":"/api-reference/meta/read-partner-configuration"},{"title":"Update the surcharge rate","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml patch /me/config","href":"/api-reference/meta/update-the-surcharge-rate"},{"title":"Current key information","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /me","href":"/api-reference/meta/current-key-information"}]},{"group":"Catalog","pages":[{"title":"List adventure categories","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /categories","href":"/api-reference/catalog/list-adventure-categories"},{"title":"List destinations","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /destinations","href":"/api-reference/catalog/list-destinations"},{"title":"Autocomplete free-text places","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /places/autocomplete","href":"/api-reference/catalog/autocomplete-free-text-places"},{"title":"Resolve a place prediction to coordinates","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /places/details","href":"/api-reference/catalog/resolve-a-place-prediction-to-coordinates"},{"title":"Paginated adventure search","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /adventures","href":"/api-reference/catalog/paginated-adventure-search"},{"title":"Detailed adventure record","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /adventures/{slug}","href":"/api-reference/catalog/detailed-adventure-record"},{"title":"Adventure availability over a period","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /adventures/{slug}/availability","href":"/api-reference/catalog/adventure-availability-over-a-period"},{"title":"Detailed agency record","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /agencies/{id}","href":"/api-reference/catalog/detailed-agency-record"}]},{"group":"Files","pages":[{"title":"Issue a presigned PUT URL to upload a review photo to R2","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /files/presigned-upload","href":"/api-reference/files/issue-a-presigned-put-url-to-upload-a-review-photo-to-r2"}]},{"group":"Reviews","pages":[{"title":"Paginated traveler reviews","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /reviews","href":"/api-reference/reviews/paginated-traveler-reviews"},{"title":"Post a traveler review on behalf of a completed booking","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /reviews","href":"/api-reference/reviews/post-a-traveler-review-on-behalf-of-a-completed-booking"},{"title":"Edit a previously posted review","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml put /reviews/{id}","href":"/api-reference/reviews/edit-a-previously-posted-review"}]},{"group":"Quotes","pages":[{"title":"List quotes","description":"Returns the partner's quotes, most recent first. Cursor-paginated.","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /quotes","href":"/api-reference/quotes/list-quotes"},{"title":"Create a price-locked quote","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /quotes","href":"/api-reference/quotes/create-a-price-locked-quote"},{"title":"Retrieve a quote by id","description":null,"deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /quotes/{quote_id}","href":"/api-reference/quotes/retrieve-a-quote-by-id"}]},{"group":"Bookings","pages":[{"title":"Paginated list of the partner's bookings","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /bookings","href":"/api-reference/bookings/paginated-list-of-the-partners-bookings"},{"title":"Create a booking","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /bookings","href":"/api-reference/bookings/create-a-booking"},{"title":"Retrieve a booking","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /bookings/{booking_number}","href":"/api-reference/bookings/retrieve-a-booking"},{"title":"Cancel a booking","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /bookings/{booking_number}/cancel","href":"/api-reference/bookings/cancel-a-booking"},{"title":"Preview the cancellation refund","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /bookings/{booking_number}/cancellation-quote","href":"/api-reference/bookings/preview-the-cancellation-refund"},{"title":"Retrieve the PDF voucher","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /bookings/{booking_number}/voucher.pdf","href":"/api-reference/bookings/retrieve-the-pdf-voucher"}]},{"group":"Webhooks","pages":[{"title":"List webhook delivery attempts","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /webhooks/deliveries","href":"/api-reference/webhooks/list-webhook-delivery-attempts"},{"title":"Replay a webhook delivery","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /webhooks/deliveries/{id}/replay","href":"/api-reference/webhooks/replay-a-webhook-delivery"},{"title":"List configured webhook endpoints","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /webhooks","href":"/api-reference/webhooks/list-configured-webhook-endpoints"},{"title":"Register a webhook endpoint","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /webhooks","href":"/api-reference/webhooks/register-a-webhook-endpoint"},{"title":"Retrieve a webhook endpoint","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /webhooks/{id}","href":"/api-reference/webhooks/retrieve-a-webhook-endpoint"},{"title":"Delete a webhook endpoint","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /webhooks/{id}","href":"/api-reference/webhooks/delete-a-webhook-endpoint"},{"title":"Emit a test event","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /webhooks/{id}/test","href":"/api-reference/webhooks/emit-a-test-event"}]},{"group":"Sandbox","pages":[{"title":"Reset the sandbox dataset","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /sandbox/reset","href":"/api-reference/sandbox/reset-the-sandbox-dataset"}]},{"group":"Settlements","pages":[{"title":"Paginated list of monthly invoices","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /settlements","href":"/api-reference/settlements/paginated-list-of-monthly-invoices"},{"title":"Settlement detail (with lines)","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /settlements/{id}","href":"/api-reference/settlements/settlement-detail-with-lines"},{"title":"Invoice PDF (Safariat → partner)","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /settlements/{id}/invoice.pdf","href":"/api-reference/settlements/invoice-pdf-safariat-→-partner"},{"title":"Statement of Account CSV (Safariat → partner)","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /settlements/{id}/statement.csv","href":"/api-reference/settlements/statement-of-account-csv-safariat-→-partner"},{"title":"Daily transactions ledger CSV","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /settlements/daily","href":"/api-reference/settlements/daily-transactions-ledger-csv"}]},{"group":"Team","pages":[{"title":"List team members","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /team/members","href":"/api-reference/team/list-team-members"},{"title":"Invite a member","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /team/members","href":"/api-reference/team/invite-a-member"},{"title":"Change a member's role","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml patch /team/members/{user_id}/role","href":"/api-reference/team/change-a-members-role"},{"title":"Remove a member","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /team/members/{user_id}","href":"/api-reference/team/remove-a-member"}]},{"group":"API keys","pages":[{"title":"List API keys for the current partner","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /api-keys","href":"/api-reference/api-keys/list-api-keys-for-the-current-partner"},{"title":"Issue a new API key","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /api-keys","href":"/api-reference/api-keys/issue-a-new-api-key"},{"title":"Revoke an API key","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml delete /api-keys/{key_id}","href":"/api-reference/api-keys/revoke-an-api-key"}]},{"group":"Audit","pages":[{"title":"List HTTP audit trail for this partner","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /audit-logs","href":"/api-reference/audit/list-http-audit-trail-for-this-partner"}]},{"group":"Dashboard","pages":[{"title":"KPI overview for the Console home","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /dashboard","href":"/api-reference/dashboard/kpi-overview-for-the-console-home"},{"title":"Commercial performance over a period","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /metrics/commercial","href":"/api-reference/dashboard/commercial-performance-over-a-period"},{"title":"How many quotes turn into bookings","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /metrics/quote-funnel","href":"/api-reference/dashboard/how-many-quotes-turn-into-bookings"},{"title":"Travelers leaving soon","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /metrics/departures","href":"/api-reference/dashboard/travelers-leaving-soon"},{"title":"Same commercial figures, as a CSV file","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml get /metrics/commercial.csv","href":"/api-reference/dashboard/same-commercial-figures-as-a-csv-file"}]},{"group":"API Reference","pages":[{"title":"Booking confirmed echo","version":null,"deprecated":null,"openapi":"/api-reference/openapi.yaml webhook bookingConfirmed","href":"/api-reference/booking-confirmed-echo"},{"title":"Booking cancelled","version":null,"deprecated":null,"openapi":"/api-reference/openapi.yaml webhook bookingCancelled","href":"/api-reference/booking-cancelled"},{"title":"Booking completed trip taken","version":null,"deprecated":null,"openapi":"/api-reference/openapi.yaml webhook bookingCompleted","href":"/api-reference/booking-completed-trip-taken"},{"title":"Monthly invoice available","version":null,"deprecated":null,"openapi":"/api-reference/openapi.yaml webhook settlementIssued","href":"/api-reference/monthly-invoice-available"},{"title":"Settlement marked paid","version":null,"deprecated":null,"openapi":"/api-reference/openapi.yaml webhook settlementPaid","href":"/api-reference/settlement-marked-paid"},{"title":"Adventure rate pack became unavailable","version":null,"deprecated":null,"openapi":"/api-reference/openapi.yaml webhook adventureUnavailable","href":"/api-reference/adventure-rate-pack-became-unavailable"},{"title":"Review hidden restored or deleted by a safariat admin","version":null,"deprecated":null,"openapi":"/api-reference/openapi.yaml webhook reviewModerated","href":"/api-reference/review-hidden-restored-or-deleted-by-a-safariat-admin"}]}]}]}]},"basePath":"","title":"SafarAPI — Morocco travel API for banks \u0026 fintechs","buildId":"dpl_8LJbrAiZvr1K98WQNZXCyY5AvT34","deploymentId":"dpl_8LJbrAiZvr1K98WQNZXCyY5AvT34","dynamics":["c2aa737661","2b790eda92","b0f84f53ff","a9bb46feb3"],"chunks":["OpenApiReferenceProvider-i2a3QZ8E.js","utils-ChLwp8m0.js","cloneDeep-izs3Hzxb.js","_Uint8Array-BVIqJ90l.js","isObjectLike-C8vmzPEN.js","isArray-Dcu1dQ5t.js","utils-DRktVTDc.js","toString-BX-iyh8G.js","isSymbol-CSH9U2Gm.js","addUniqueKeysToSchema-CA2pEs4T.js","snippetPresets-ClQ6XrKD.js","style-to-object-BY3JEAdk.js","v4-DIgz8zy6.js","ApiExamples-Ct_Lv36y.js","isEqual-BfaiBbcl.js","usePlaygroundInputsStore-Cn2PYw9e.js","shallow-rkyymjXQ.js","getApiPlaygroundDisplay-BB9vkXtE.js","CodeSnippet-Bm5RU7m1.js","CodeSnippets-BgU9Deuz.js","Page-BUDYNlhG.js","getPastedJson-BD-6NNum.js","icon-8Z6tud2e.js","MethodPill-Tuzr4g3V.js","DuplicateIcon-0ceWFYhN.js","createIcon-FBXow_ST.js","DynamicMarkdown-CD8713Yy.js","SectionHeading-7zgzQbH-.js","axios-vUo_bRtp.js","Markdown-D7Ofw1oz.js","clsx-eKJ4rcii.js","lib-DuNMoZ05.js","lib-B8HbPgcC.js","html-void-elements-mCSPHezU.js","dist-CwjSCXIK.js","katex-YMM-FMeD.js","marked.esm-CZWythHk.js","AssistantPageLink-9EK5IAXV.js"]}