Creates a booking in CONFIRMED status from a valid quote. The booking is
confirmed immediately (no PENDING/24h window) — payment is recorded via the
payment_confirmation fields.
The traveler (traveler field) is resolved / created as a Keycloak shadow user
on the Safariat side (see ADR-018). The PDF voucher and confirmation email are sent
directly to the traveler at the provided email address.
Idempotency
The Idempotency-Key header is required. Same key + same body → the cached
response is returned. Same key + different body → 409 Conflict. Retained for 24 h.
Payment validation
payment_confirmation.paid_amount_netmust equal the
quote.pricing.amount_due_to_safariat.amount returned by POST /quotes (anti-fraud).
Otherwise → 422 payment.amount.mismatch.
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.
The partner channel skips the PENDING status (no payment-wait window).
Additional internal Safariat statuses (PAYMENT_PROCESSING, REFUND_PENDING)
are never exposed on this API.
Payment confirmation echoed back on the booking (response projection). The monetary
amounts (customer total, net due to Safariat, surcharge) are exposed via pricing.
true when the booking was issued with a sandbox key. A sandbox booking never reaches
an operator, never produces a settlement, and its notifications are limited to the
traveller address supplied in the request, with a [TEST] subject prefix.
{"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/bookings/create-a-booking","slug":"/api-reference/bookings/create-a-booking","pageMetadata":{"title":"Create a booking","description":"Creates a booking in `CONFIRMED` status from a valid quote. The booking is\n**confirmed immediately** (no PENDING/24h window) — payment is recorded via the\n`payment_confirmation` fields.\n\nThe traveler (`traveler` field) is resolved / created as a **Keycloak shadow user**\non the Safariat side (see ADR-018). The PDF voucher and confirmation email are sent\ndirectly to the traveler at the provided email address.\n\n## Idempotency\nThe `Idempotency-Key` header is **required**. Same key + same body → the cached\nresponse is returned. Same key + different body → `409 Conflict`. Retained for 24 h.\n\n## Payment validation\n`payment_confirmation.paid_amount_net` **must equal** the\n`quote.pricing.amount_due_to_safariat.amount` returned by `POST /quotes` (anti-fraud).\nOtherwise → `422 payment.amount.mismatch`.\n","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /bookings","href":"/api-reference/bookings/create-a-booking","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 h2: \"h2\",\n p: \"p\",\n strong: \"strong\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsxs(_Fragment, {\n children: [_jsxs(_components.p, {\n children: [\"Creates a booking in \", _jsx(_components.code, {\n children: \"CONFIRMED\"\n }), \" status from a valid quote. The booking is\\n\", _jsx(_components.strong, {\n children: \"confirmed immediately\"\n }), \" (no PENDING/24h window) — payment is recorded via the\\n\", _jsx(_components.code, {\n children: \"payment_confirmation\"\n }), \" fields.\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"The traveler (\", _jsx(_components.code, {\n children: \"traveler\"\n }), \" field) is resolved / created as a \", _jsx(_components.strong, {\n children: \"Keycloak shadow user\"\n }), \"\\non the Safariat side (see ADR-018). The PDF voucher and confirmation email are sent\\ndirectly to the traveler at the provided email address.\"]\n }), \"\\n\", _jsx(_components.h2, {\n children: \"Idempotency\"\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"The \", _jsx(_components.code, {\n children: \"Idempotency-Key\"\n }), \" header is \", _jsx(_components.strong, {\n children: \"required\"\n }), \". Same key + same body → the cached\\nresponse is returned. Same key + different body → \", _jsx(_components.code, {\n children: \"409 Conflict\"\n }), \". Retained for 24 h.\"]\n }), \"\\n\", _jsx(_components.h2, {\n children: \"Payment validation\"\n }), \"\\n\", _jsxs(_components.p, {\n children: [_jsx(_components.code, {\n children: \"payment_confirmation.paid_amount_net\"\n }), \" \", _jsx(_components.strong, {\n children: \"must equal\"\n }), \" the\\n\", _jsx(_components.code, {\n children: \"quote.pricing.amount_due_to_safariat.amount\"\n }), \" returned by \", _jsx(_components.code, {\n children: \"POST /quotes\"\n }), \" (anti-fraud).\\nOtherwise → \", _jsx(_components.code, {\n children: \"422 payment.amount.mismatch\"\n }), \".\"]\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 booking","description":"Creates a booking in `CONFIRMED` status from a valid quote. The booking is\n**confirmed immediately** (no PENDING/24h window) — payment is recorded via the\n`payment_confirmation` fields.\n\nThe traveler (`traveler` field) is resolved / created as a **Keycloak shadow user**\non the Safariat side (see ADR-018). The PDF voucher and confirmation email are sent\ndirectly to the traveler at the provided email address.\n\n## Idempotency\nThe `Idempotency-Key` header is **required**. Same key + same body → the cached\nresponse is returned. Same key + different body → `409 Conflict`. Retained for 24 h.\n\n## Payment validation\n`payment_confirmation.paid_amount_net` **must equal** the\n`quote.pricing.amount_due_to_safariat.amount` returned by `POST /quotes` (anti-fraud).\nOtherwise → `422 payment.amount.mismatch`.\n","deprecated":null,"version":null,"openapi":"/api-reference/openapi.yaml post /bookings","href":"/api-reference/bookings/create-a-booking","autogeneratedByOpenApi":true}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[],"codeExamples":{}},"jsLinks":["/_mintlify/custom/safariat/f751755c840beb5a/trust/tools/generate-cobranded-pdf.js"],"openApiReferenceData":{"operation":{"tags":["Bookings"],"operationId":"createBooking","summary":"Create a booking","description":"Creates a booking in `CONFIRMED` status from a valid quote. The booking is\n**confirmed immediately** (no PENDING/24h window) — payment is recorded via the\n`payment_confirmation` fields.\n\nThe traveler (`traveler` field) is resolved / created as a **Keycloak shadow user**\non the Safariat side (see ADR-018). The PDF voucher and confirmation email are sent\ndirectly to the traveler at the provided email address.\n\n## Idempotency\nThe `Idempotency-Key` header is **required**. Same key + same body → the cached\nresponse is returned. Same key + different body → `409 Conflict`. Retained for 24 h.\n\n## Payment validation\n`payment_confirmation.paid_amount_net` **must equal** the\n`quote.pricing.amount_due_to_safariat.amount` returned by `POST /quotes` (anti-fraud).\nOtherwise → `422 payment.amount.mismatch`.\n","parameters":["e347a3dc-5871-4879-b3d4-b70d8ac534af","418aea25-b719-4aed-8745-978e6ead808c","b53ad748-628e-4c4d-80c9-e5f6d48691bd"],"requestBody":"13638432-d0af-4a5b-b255-e32a9e20a3bc","responses":{"201":"b0dff5fb-9bd4-4ee4-af66-4d3d4cf1450b","400":"78a9a1d2-05cd-45ed-afbd-bf8550b88f46","401":"efde0d18-66a7-4ba3-b43c-abc1658a39ed","403":"cd779f38-e6e5-4e91-94f8-f73e04fa3d86","404":"7c7fb4c9-dd86-437d-964d-98024c40f9f1","409":"a08f74da-fab9-41e0-8890-fe30882df094","422":"abb8c6b6-4718-4b95-873a-792671486323","429":"6b4b25b7-f08e-49f5-af7d-a5e92b181158"},"method":"post","type":"path","servers":["bef6bbb6-8b53-47c4-b0bd-53ed06e38170"],"security":["509b5ed1-5a9c-40f6-a981-6928a3ac2aa3"],"path":"/bookings","baseUrlOptions":["https://api.safarapi.com/api/partner/v1"],"title":"Create a booking","codeSamples":[],"requiredOnlyExamples":false,"requestExampleType":"generated","responseExampleType":"generated"},"dependencies":{"parameters":{"e347a3dc-5871-4879-b3d4-b70d8ac534af":{"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"},"418aea25-b719-4aed-8745-978e6ead808c":{"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"},"b53ad748-628e-4c4d-80c9-e5f6d48691bd":{"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":["quote_id","traveler","rooms_allocation","partner_reference","payment_confirmation"],"properties":{"quote_id":{"type":"string","format":"uuid","isRequired":true,"uniqueKey":"quote_id","typeLabel":"string\u003cuuid>"},"partner_reference":{"type":"string","minLength":1,"maxLength":100,"description":"The bank's internal reference (booking ID on the bank side). Unique per partner.\nLets the bank locate the Safariat booking from its own primary key.\n","isRequired":true,"uniqueKey":"partner_reference","typeLabel":"string"},"traveler":{"type":"object","required":["first_name","last_name","email","phone","language","customer_reference"],"properties":{"first_name":{"type":"string","minLength":1,"maxLength":100,"isRequired":true,"uniqueKey":"traveler.first_name","typeLabel":"string"},"last_name":{"type":"string","minLength":1,"maxLength":100,"isRequired":true,"uniqueKey":"traveler.last_name","typeLabel":"string"},"email":{"type":"string","format":"email","isRequired":true,"uniqueKey":"traveler.email","typeLabel":"string\u003cemail>"},"phone":{"type":"string","pattern":"^\\+?[1-9]\\d{6,14}$","description":"E.164 format recommended.","isRequired":true,"uniqueKey":"traveler.phone","typeLabel":"string"},"language":{"type":"string","enum":["fr","en","ar"],"isRequired":true,"uniqueKey":"traveler.language","typeLabel":"enum\u003cstring>"},"customer_reference":{"type":"string","minLength":1,"maxLength":100,"description":"The bank's internal customer ID. **Pseudonymized server-side with keyed\nHMAC-SHA256, namespaced per partner** before storage (non-reversible,\ndeterministic per partner). Lets the bank locate the traveler in its own\nsystems, with no cross-bank correlation in the event of a Safariat breach.\nAlso accepted as the `customer_reference` filter on `GET /bookings`.\n","isRequired":true,"uniqueKey":"traveler.customer_reference","typeLabel":"string"}},"isRequired":true,"uniqueKey":"traveler","typeLabel":"object"},"rooms_allocation":{"type":"array","minItems":1,"items":{"type":"object","required":["room_index","occupants"],"properties":{"room_index":{"type":"integer","minimum":0,"description":"Room index (correlated with the position in `quote.rooms`).","isRequired":true,"uniqueKey":"rooms_allocation.items.[INDEX].room_index","typeLabel":"integer"},"occupants":{"type":"array","minItems":1,"items":{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["ADULT","CHILD"],"isRequired":true,"uniqueKey":"rooms_allocation.items.[INDEX].occupants.items.[INDEX].type","typeLabel":"enum\u003cstring>"},"age":{"type":"integer","minimum":0,"maximum":17,"description":"Required if type=CHILD.","uniqueKey":"rooms_allocation.items.[INDEX].occupants.items.[INDEX].age","typeLabel":"integer"}},"uniqueKey":"rooms_allocation.items.[INDEX].occupants.items.[INDEX]","typeLabel":"object"},"isRequired":true,"uniqueKey":"rooms_allocation.items.[INDEX].occupants","typeLabel":"object[]"}},"uniqueKey":"rooms_allocation.items.[INDEX]","typeLabel":"object"},"isRequired":true,"uniqueKey":"rooms_allocation","typeLabel":"object[]"},"payment_confirmation":{"type":"object","required":["bank_payment_ref","paid_amount_total","paid_amount_net","paid_at","payment_method"],"description":"Payment confirmation supplied by the bank on booking creation (request input).","properties":{"bank_payment_ref":{"type":"string","minLength":1,"maxLength":255,"description":"The bank's internal payment reference (for reconciliation).","isRequired":true,"uniqueKey":"payment_confirmation.bank_payment_ref","typeLabel":"string"},"paid_amount_total":{"type":"number","format":"double","minimum":0,"multipleOf":0.01,"example":1116,"description":"Total amount (in MAD) debited from the bank customer — a **plain decimal**, not a Money\nobject. The bank may apply its own surcharge on top of the net price. Echoed back on the\nbooking as `pricing.customer_price`.\n","isRequired":true,"uniqueKey":"payment_confirmation.paid_amount_total","typeLabel":"number\u003cdouble>"},"paid_amount_net":{"type":"number","format":"double","minimum":0,"multipleOf":0.01,"example":949.9,"description":"**Net amount due to Safariat** (in MAD), a **plain decimal**. Must be strictly equal to\n`quote.pricing.amount_due_to_safariat.amount`, otherwise `422 payment.amount.mismatch`.\n","isRequired":true,"uniqueKey":"payment_confirmation.paid_amount_net","typeLabel":"number\u003cdouble>"},"paid_at":{"type":"string","format":"date-time","isRequired":true,"uniqueKey":"payment_confirmation.paid_at","typeLabel":"string\u003cdate-time>"},"payment_method":{"type":"string","enum":["CARD","BANK_TRANSFER","ACCOUNT_DEBIT","CASH","WAFACASH","OTHER"],"isRequired":true,"uniqueKey":"payment_confirmation.payment_method","typeLabel":"enum\u003cstring>"}},"isRequired":true,"uniqueKey":"payment_confirmation","typeLabel":"object"},"special_requests":{"type":"string","maxLength":1000,"description":"Special requests (dietary requirements, accessibility, etc.).","uniqueKey":"special_requests","typeLabel":"string"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"quote_id":"3c90c3cc-0d44-4b50-8888-8dd25736052a","partner_reference":"\u003cstring>","traveler":{"first_name":"\u003cstring>","last_name":"\u003cstring>","email":"jsmith@example.com","phone":"\u003cstring>","customer_reference":"\u003cstring>"},"rooms_allocation":[{"room_index":1,"occupants":[{"age":8}]}],"payment_confirmation":{"bank_payment_ref":"\u003cstring>","paid_amount_total":1116,"paid_amount_net":949.9,"paid_at":"2023-11-07T05:31:56Z"},"special_requests":"\u003cstring>"}}},"exampleType":"generated"}},"exampleType":"generated"},"responses":{"b0dff5fb-9bd4-4ee4-af66-4d3d4cf1450b":{"description":"Booking created and confirmed","headers":{"Location":{"schema":{"type":"string"},"description":"Absolute URL of the created booking."}},"content":{"application/json":{"schema":{"type":"object","required":["traveler","rooms_allocation","payment_confirmation","snapshot_id","cancellation_tiers","booking_number","partner_reference","status","adventure_slug","travel_date","pricing","created_at"],"properties":{"booking_number":{"type":"string","example":"MV-AB7X92","isRequired":true,"uniqueKey":"booking_number","typeLabel":"string"},"partner_reference":{"type":"string","isRequired":true,"uniqueKey":"partner_reference","typeLabel":"string"},"status":{"type":"string","enum":["CONFIRMED","COMPLETED","CANCELLED"],"description":"The partner channel skips the `PENDING` status (no payment-wait window).\nAdditional internal Safariat statuses (`PAYMENT_PROCESSING`, `REFUND_PENDING`)\nare never exposed on this API.\n","isRequired":true,"uniqueKey":"status","typeLabel":"enum\u003cstring>"},"adventure_slug":{"type":"string","isRequired":true,"uniqueKey":"adventure_slug","typeLabel":"string"},"travel_date":{"type":"string","format":"date","isRequired":true,"uniqueKey":"travel_date","typeLabel":"string\u003cdate>"},"pricing":{"type":"object","description":"Revenue breakdown with the real surcharge recorded at booking (`indicative = false`).","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"},"created_at":{"type":"string","format":"date-time","isRequired":true,"uniqueKey":"created_at","typeLabel":"string\u003cdate-time>"},"traveler":{"type":"object","required":["first_name","last_name","email","phone","language","customer_reference"],"properties":{"first_name":{"type":"string","minLength":1,"maxLength":100,"isRequired":true,"uniqueKey":"traveler.first_name","typeLabel":"string"},"last_name":{"type":"string","minLength":1,"maxLength":100,"isRequired":true,"uniqueKey":"traveler.last_name","typeLabel":"string"},"email":{"type":"string","format":"email","isRequired":true,"uniqueKey":"traveler.email","typeLabel":"string\u003cemail>"},"phone":{"type":"string","pattern":"^\\+?[1-9]\\d{6,14}$","description":"E.164 format recommended.","isRequired":true,"uniqueKey":"traveler.phone","typeLabel":"string"},"language":{"type":"string","enum":["fr","en","ar"],"isRequired":true,"uniqueKey":"traveler.language","typeLabel":"enum\u003cstring>"},"customer_reference":{"type":"string","minLength":1,"maxLength":100,"description":"The bank's internal customer ID. **Pseudonymized server-side with keyed\nHMAC-SHA256, namespaced per partner** before storage (non-reversible,\ndeterministic per partner). Lets the bank locate the traveler in its own\nsystems, with no cross-bank correlation in the event of a Safariat breach.\nAlso accepted as the `customer_reference` filter on `GET /bookings`.\n","isRequired":true,"uniqueKey":"traveler.customer_reference","typeLabel":"string"}},"isRequired":true,"uniqueKey":"traveler","typeLabel":"object"},"rooms_allocation":{"type":"array","items":{"type":"object","required":["room_index","occupants"],"properties":{"room_index":{"type":"integer","minimum":0,"description":"Room index (correlated with the position in `quote.rooms`).","isRequired":true,"uniqueKey":"rooms_allocation.items.[INDEX].room_index","typeLabel":"integer"},"occupants":{"type":"array","minItems":1,"items":{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["ADULT","CHILD"],"isRequired":true,"uniqueKey":"rooms_allocation.items.[INDEX].occupants.items.[INDEX].type","typeLabel":"enum\u003cstring>"},"age":{"type":"integer","minimum":0,"maximum":17,"description":"Required if type=CHILD.","uniqueKey":"rooms_allocation.items.[INDEX].occupants.items.[INDEX].age","typeLabel":"integer"}},"uniqueKey":"rooms_allocation.items.[INDEX].occupants.items.[INDEX]","typeLabel":"object"},"isRequired":true,"uniqueKey":"rooms_allocation.items.[INDEX].occupants","typeLabel":"object[]"}},"uniqueKey":"rooms_allocation.items.[INDEX]","typeLabel":"object"},"isRequired":true,"uniqueKey":"rooms_allocation","typeLabel":"object[]"},"payment_confirmation":{"type":"object","required":["bank_payment_ref","paid_at","payment_method"],"description":"Payment confirmation echoed back on the booking (response projection). The monetary\namounts (customer total, net due to Safariat, surcharge) are exposed via `pricing`.\n","properties":{"bank_payment_ref":{"type":"string","description":"The bank's internal payment reference (for reconciliation).","isRequired":true,"uniqueKey":"payment_confirmation.bank_payment_ref","typeLabel":"string"},"paid_at":{"type":"string","format":"date-time","isRequired":true,"uniqueKey":"payment_confirmation.paid_at","typeLabel":"string\u003cdate-time>"},"payment_method":{"type":"string","enum":["CARD","BANK_TRANSFER","ACCOUNT_DEBIT","CASH","WAFACASH","OTHER"],"isRequired":true,"uniqueKey":"payment_confirmation.payment_method","typeLabel":"enum\u003cstring>"}},"isRequired":true,"uniqueKey":"payment_confirmation","typeLabel":"object"},"snapshot_id":{"type":"string","format":"uuid","description":"ID of the adventure snapshot captured at creation (see ADR-013). Guarantees\nthe traveler receives the experience as it was at the time of booking.\n","isRequired":true,"uniqueKey":"snapshot_id","typeLabel":"string\u003cuuid>"},"cancellation_tiers":{"type":"array","items":{"type":"object","properties":{"days_before":{"type":"integer","uniqueKey":"cancellation_tiers.items.[INDEX].days_before","typeLabel":"integer"},"refund_percent":{"type":"integer","uniqueKey":"cancellation_tiers.items.[INDEX].refund_percent","typeLabel":"integer"},"refundable_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":"cancellation_tiers.items.[INDEX].refundable_amount.amount","typeLabel":"string"},"currency":{"type":"string","enum":["MAD"],"description":"Currency — MAD only in V1.","example":"MAD","isRequired":true,"uniqueKey":"cancellation_tiers.items.[INDEX].refundable_amount.currency","typeLabel":"enum\u003cstring>"}},"uniqueKey":"cancellation_tiers.items.[INDEX].refundable_amount","typeLabel":"object"}},"uniqueKey":"cancellation_tiers.items.[INDEX]","typeLabel":"object"},"isRequired":true,"uniqueKey":"cancellation_tiers","typeLabel":"object[]"},"adventure_title":{"type":"string","uniqueKey":"adventure_title","typeLabel":"string"},"traveler_name":{"type":"string","description":"Initialed (e.g. 'A. B.') for PII protection in lists.","uniqueKey":"traveler_name","typeLabel":"string"},"settlement_id":{"oneOf":[{"type":"string","format":"uuid","description":"ID of the settlement this booking is included in (null if not yet invoiced).","uniqueKey":"settlement_id.oneOf.0","typeLabel":"string\u003cuuid>"},{"type":"null","format":"uuid","description":"ID of the settlement this booking is included in (null if not yet invoiced).","uniqueKey":"settlement_id.oneOf.1","typeLabel":"null"}],"uniqueKey":"settlement_id","typeLabel":"string\u003cuuid> | null"},"test_mode":{"type":"boolean","description":"`true` when the booking was issued with a sandbox key. A sandbox booking never reaches\nan operator, never produces a settlement, and its notifications are limited to the\ntraveller address supplied in the request, with a `[TEST]` subject prefix.\n","uniqueKey":"test_mode","typeLabel":"boolean"},"special_requests":{"oneOf":[{"type":"string","uniqueKey":"special_requests.oneOf.0","typeLabel":"string"},{"type":"null","uniqueKey":"special_requests.oneOf.1","typeLabel":"null"}],"uniqueKey":"special_requests","typeLabel":"string | null"},"voucher_url":{"type":"string","format":"uri","description":"Pre-signed URL to the PDF voucher (7-day TTL).","uniqueKey":"voucher_url","typeLabel":"string\u003curi>"}},"uniqueKey":"","typeLabel":"object"},"example":{"booking_number":"MV-AB7X92","partner_reference":"YBANK-BOOK-001","status":"CONFIRMED","adventure_slug":"marrakech-3-jours-desert-sandbox","adventure_title":"[DEMO] 3-day Sahara desert circuit from Marrakech","travel_date":"2026-07-12","traveler_name":"A. B.","pricing":{"b2c_price":{"amount":"5250.00","currency":"MAD"},"customer_price":{"amount":"6210.00","currency":"MAD"},"amount_due_to_safariat":{"amount":"5162.50","currency":"MAD"},"awb_commission_share":{"amount":"87.50","currency":"MAD"},"sandbox_surcharge":{"amount":"960.00","currency":"MAD"},"partner_revenue":{"amount":"1047.50","currency":"MAD"},"indicative":false},"settlement_id":null,"created_at":"2026-07-12T10:05:00Z","traveler":{"first_name":"Amina","last_name":"Benali","email":"amina.benali@example.com","phone":"+212600112233","language":"fr","customer_reference":"YBANK-CUST-77310"},"rooms_allocation":[{"room_index":0,"occupants":[{"type":"ADULT"},{"type":"ADULT"},{"type":"CHILD","age":8},{"type":"CHILD","age":12}]}],"special_requests":null,"payment_confirmation":{"bank_payment_ref":"YBANK-PAY-2026-07-12-00891","paid_at":"2026-07-12T10:04:30Z","payment_method":"ACCOUNT_DEBIT"},"snapshot_id":"5e6d7c8b-9a0f-4b1c-8d2e-3f4a5b6c7d8e","cancellation_tiers":[{"days_before":30,"refund_percent":100,"refundable_amount":{"amount":"5400.00","currency":"MAD"}},{"days_before":14,"refund_percent":50,"refundable_amount":{"amount":"2700.00","currency":"MAD"}},{"days_before":7,"refund_percent":0,"refundable_amount":{"amount":"0.00","currency":"MAD"}}],"voucher_url":"https://placehold.co/600x400?text=DEMO"},"examples":{"Example":{"title":"Example","value":{"booking_number":"MV-AB7X92","partner_reference":"YBANK-BOOK-001","status":"CONFIRMED","adventure_slug":"marrakech-3-jours-desert-sandbox","adventure_title":"[DEMO] 3-day Sahara desert circuit from Marrakech","travel_date":"2026-07-12","traveler_name":"A. B.","pricing":{"b2c_price":{"amount":"5250.00","currency":"MAD"},"customer_price":{"amount":"6210.00","currency":"MAD"},"amount_due_to_safariat":{"amount":"5162.50","currency":"MAD"},"awb_commission_share":{"amount":"87.50","currency":"MAD"},"sandbox_surcharge":{"amount":"960.00","currency":"MAD"},"partner_revenue":{"amount":"1047.50","currency":"MAD"},"indicative":false},"settlement_id":null,"created_at":"2026-07-12T10:05:00Z","traveler":{"first_name":"Amina","last_name":"Benali","email":"amina.benali@example.com","phone":"+212600112233","language":"fr","customer_reference":"YBANK-CUST-77310"},"rooms_allocation":[{"room_index":0,"occupants":[{"type":"ADULT"},{"type":"ADULT"},{"type":"CHILD","age":8},{"type":"CHILD","age":12}]}],"special_requests":null,"payment_confirmation":{"bank_payment_ref":"YBANK-PAY-2026-07-12-00891","paid_at":"2026-07-12T10:04:30Z","payment_method":"ACCOUNT_DEBIT"},"snapshot_id":"5e6d7c8b-9a0f-4b1c-8d2e-3f4a5b6c7d8e","cancellation_tiers":[{"days_before":30,"refund_percent":100,"refundable_amount":{"amount":"5400.00","currency":"MAD"}},{"days_before":14,"refund_percent":50,"refundable_amount":{"amount":"2700.00","currency":"MAD"}},{"days_before":7,"refund_percent":0,"refundable_amount":{"amount":"0.00","currency":"MAD"}}],"voucher_url":"https://placehold.co/600x400?text=DEMO"}}},"exampleType":"examples"}},"exampleType":"examples"},"78a9a1d2-05cd-45ed-afbd-bf8550b88f46":{"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"},"efde0d18-66a7-4ba3-b43c-abc1658a39ed":{"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"},"cd779f38-e6e5-4e91-94f8-f73e04fa3d86":{"description":"Partner credit limit would be exceeded, or booking for a traveler whose identity is already linked to another partner under dispute.","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":{"creditLimitExceeded":{"title":"creditLimitExceeded","value":{"code":"partner.credit.limit.exceeded","message":"Outstanding amount would exceed the partner credit limit.","request_id":"01HXY2ZRPM3R8K9PSBTRQYNFHC","details":{"credit_limit":{"amount":"50000.00","currency":"MAD"},"outstanding":{"amount":"48200.00","currency":"MAD"},"this_booking":{"amount":"3200.00","currency":"MAD"}}}}},"exampleType":"examples"}},"exampleType":"examples"},"7c7fb4c9-dd86-437d-964d-98024c40f9f1":{"description":"Unknown or expired quote.","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":"adventure.not.found","message":"The adventure referenced by the quote no longer exists or is not available to this partner.","request_id":"req_8f3a1c9e2b7d40"},"examples":{"Example":{"title":"Example","value":{"code":"adventure.not.found","message":"The adventure referenced by the quote no longer exists or is not available to this partner.","request_id":"req_8f3a1c9e2b7d40"}}},"exampleType":"examples"}},"exampleType":"examples"},"a08f74da-fab9-41e0-8890-fe30882df094":{"description":"Conflict — no booking created. Either the `Idempotency-Key` was reused with a different body, or a uniqueness guard fired (ADR-024): quote already used (`partner.booking.quote.already.used`), bank payment reference already used (`payment.confirmation.replayed`), or duplicate `partner_reference` (`partner.booking.partnerreference.duplicate`).","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":"partner.booking.quote.already.used","message":"This quote has already been used for a booking.","request_id":"req_8f3a1c9e2b7d40"},"examples":{"Example":{"title":"Example","value":{"code":"partner.booking.quote.already.used","message":"This quote has already been used for a booking.","request_id":"req_8f3a1c9e2b7d40"}}},"exampleType":"examples"}},"exampleType":"examples"},"abb8c6b6-4718-4b95-873a-792671486323":{"description":"Business rule violated. The slot is re-validated at booking time (the quote may be up to 30 min stale): `adventure.capacity.exhausted` (no capacity left), `partner.booking.cutoff.too.late` (cut-off passed), `payment.amount.mismatch` / `payment.amount.total.invalid`.","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":{"amountMismatch":{"title":"amountMismatch","value":{"code":"payment.amount.mismatch","message":"payment_confirmation.paid_amount_net does not match quote.pricing.amount_due_to_safariat.","request_id":"01HXY2ZRPM3R8K9PSBTRQYNFHC"}},"capacityExhausted":{"title":"capacityExhausted","value":{"code":"adventure.capacity.exhausted","message":"No remaining capacity for this slot.","request_id":"01HXY2ZRPM3R8K9PSBTRQYNFHD"}}},"exampleType":"examples"}},"exampleType":"examples"},"6b4b25b7-f08e-49f5-af7d-a5e92b181158":{"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.980Z","originalFileLocation":"api-reference/bookings/create-a-booking.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=\"Creates a booking in CONFIRMED status from a valid quote. The booking is confirmed immediately (no PENDING/24h window) — payment is recorded via the payment_confirmation fields. The traveler (traveler field) is resolved / created as a Keycloak shadow user on the Safariat side (see ADR-018). The PDF voucher and confirmation email are sent directly to the traveler at the provided email address. ## Idempotency The Idempotency-Key header is required. Same key + same body → the cached response is returned. Same key + different body → 409 Conflict. Retained for 24 h. ## Payment validation payment_confirmation.paid_amount_net must equal the quote.pricing.amount_due_to_safariat.amount returned by POST /quotes (anti-fraud). Otherwise → 422 payment.amount.mismatch.\">\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/bookings/create-a-booking\">\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=Bookings\u0026amp;title=Create+a+booking\u0026amp;description=Creates+a+booking+in+%60CONFIRMED%60+status+from+a+valid+quote.+The+booking+is%0A**confirmed+immediately**+%28no+PENDING%2F24h+window%29+%E2%80%94+payment+is+recorded+via+the%0A%60paym\u0026amp;theme=3b8c95b43b12f994ae542965\u0026amp;signature=00a212223b2ca1a563a335405cb88e8f1a2c44d128573b0ca2714d5300ae1183\">\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=Bookings\u0026amp;title=Create+a+booking\u0026amp;description=Creates+a+booking+in+%60CONFIRMED%60+status+from+a+valid+quote.+The+booking+is%0A**confirmed+immediately**+%28no+PENDING%2F24h+window%29+%E2%80%94+payment+is+recorded+via+the%0A%60paym\u0026amp;theme=3b8c95b43b12f994ae542965\u0026amp;signature=00a212223b2ca1a563a335405cb88e8f1a2c44d128573b0ca2714d5300ae1183\">\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/bookings/create-a-booking\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/api-reference/bookings/create-a-booking.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/bookings/create-a-booking#webpage\",\"url\":\"https://developers.safarapi.com/api-reference/bookings/create-a-booking\",\"name\":\"Create a booking\",\"description\":\"Creates a booking in CONFIRMED status from a valid quote. The booking is confirmed immediately (no PENDING/24h window) — payment is recorded via the payment_confirmation fields. The traveler (traveler field) is resolved / created as a Keycloak shadow user on the Safariat side (see ADR-018). The PDF voucher and confirmation email are sent directly to the traveler at the provided email address. ## Idempotency The Idempotency-Key header is required. Same key + same body → the cached response is returned. Same key + different body → 409 Conflict. Retained for 24 h. ## Payment validation payment_confirmation.paid_amount_net must equal the quote.pricing.amount_due_to_safariat.amount returned by POST /quotes (anti-fraud). Otherwise → 422 payment.amount.mismatch.\",\"dateModified\":\"2026-09-05T20:07:20.980Z\",\"isPartOf\":{\"@id\":\"https://developers.safarapi.com#website\"},\"breadcrumb\":{\"@id\":\"https://developers.safarapi.com/api-reference/bookings/create-a-booking#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://developers.safarapi.com/api-reference/bookings/create-a-booking#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Endpoints\",\"item\":\"https://developers.safarapi.com/api-reference/meta/service-status\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Bookings\",\"item\":\"https://developers.safarapi.com/api-reference/bookings/paginated-list-of-the-partners-bookings\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Create a booking\",\"item\":\"https://developers.safarapi.com/api-reference/bookings/create-a-booking\"}]},{\"@type\":[\"TechArticle\",\"APIReference\"],\"@id\":\"https://developers.safarapi.com/api-reference/bookings/create-a-booking#apireference\",\"headline\":\"Create a booking\",\"name\":\"Create a booking\",\"description\":\"Creates a booking in CONFIRMED status from a valid quote. The booking is confirmed immediately (no PENDING/24h window) — payment is recorded via the payment_confirmation fields. The traveler (traveler field) is resolved / created as a Keycloak shadow user on the Safariat side (see ADR-018). The PDF voucher and confirmation email are sent directly to the traveler at the provided email address. ## Idempotency The Idempotency-Key header is required. Same key + same body → the cached response is returned. Same key + different body → 409 Conflict. Retained for 24 h. ## Payment validation payment_confirmation.paid_amount_net must equal the quote.pricing.amount_due_to_safariat.amount returned by POST /quotes (anti-fraud). Otherwise → 422 payment.amount.mismatch.\",\"url\":\"https://developers.safarapi.com/api-reference/bookings/create-a-booking\",\"mainEntityOfPage\":{\"@id\":\"https://developers.safarapi.com/api-reference/bookings/create-a-booking#webpage\"},\"dateModified\":\"2026-09-05T20:07:20.980Z\",\"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","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","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","description":"Bookings created by your account, most recent first. Cursor-paginated; filter by status and creation window. Traveler names are initialed for PII protection — full details are on `GET /bookings/{booking_number}`.","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","description":"Full booking record: traveler, room allocation, payment confirmation, the immutable adventure snapshot id, and the cancellation tiers that apply to this 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"]}