{"openapi":"3.1.0","info":{"title":"Travolyo Partner Integration API","version":"1.0.0","contact":{"name":"Travolyo Partner Support","email":"partners@travolyo.com"},"description":"REST API to search and book **Travolyo's hotels, activities, and rentals**\nprogrammatically.\n\n**Base URL:** `https://travolyob2b.com/api/partner/v1`\n\n## Authentication\nSend your partner API key in the `auth-api-key` header on **every** request.\nDepending on your contract, requests may additionally require:\n- **IP allowlist** — requests must originate from a pre-registered source IP/CIDR.\n- **mTLS** — a client certificate, verified at the edge.\n- **HMAC request signing** — `X-Partner-Signature` + `X-Partner-Timestamp` headers\n  (see *Request signing* below).\n\n## Pricing\nEvery price reflects your contract's pricing mode:\n- `net` — a net rate that you mark up before selling to your customer.\n- `markup` — Travolyo's ready-to-sell price.\n\nA single `price`/`total_price` is returned per item.\n\n## Idempotency\n`POST /bookings` **requires** an `Idempotency-Key` header. Replaying the same key\nreturns the original booking — never a duplicate, never a second credit charge.\n\n## Settlement\nBookings draw down your postpaid **credit line**. Query remaining credit at\n`GET /meta/credit`. A `402` response means insufficient credit.\n\n## Rate limiting\nRequests are throttled per partner (default 120/min, set by contract). Exceeding the\nlimit returns `429` with a `Retry-After` header.\n\n## Response envelope\nSuccess: `{ \"success\": true, \"message\": null, \"data\": \u003cobject|array\u003e, \"meta\": {...} }`\n\nError: `{ \"success\": false, \"message\": \"...\", \"code\": \"\u003cmachine_code\u003e\", \"errors\": [\"...\"] }`\n\n## Request signing (when enabled)\nCompute `HMAC-SHA256(secret, \"\u003ctimestamp\u003e.\u003cHTTP_METHOD\u003e.\u003cpath\u003e.\u003craw_body\u003e\")` using your\npartner secret, hex-encoded. Send it as `X-Partner-Signature` with the unix `X-Partner-Timestamp`.\nRequests older than 5 minutes are rejected (replay protection).\n\n## Error codes\n| HTTP | code | meaning |\n|------|------|---------|\n| 400 | `bad_request` / `idempotency_key_required` | malformed input / missing Idempotency-Key |\n| 401 | `unauthorized` / `signature_invalid` | bad/expired key or signature |\n| 402 | `insufficient_credit` / `credit_blocked` | settlement credit problem |\n| 403 | `ip_not_allowed` / `mtls_required` / `insufficient_scope` | request blocked by policy |\n| 404 | `not_found` | resource not found or not available to you |\n| 409 | `duplicate_partner_reference` | partner_reference already used |\n| 422 | `invalid_quote` / `prebook_expired` / `not_cancellable` | business-rule violation |\n| 429 | `rate_limited` | throttled |\n"},"servers":[{"url":"https://travolyob2b.com/api/partner/v1","description":"Production"}],"security":[{"ApiKeyAuth":[]}],"tags":[{"name":"Search","description":"Search a destination for available items on given dates, with a \"from\" price. Start here."},{"name":"Catalog","description":"Full content for one item by id (hotels, activities, rentals) — incl. photos. No flat listing; discovery is search-first."},{"name":"Availability","description":"Live rooms/rates for one chosen item on given dates."},{"name":"Bookings","description":"Prebook, book, retrieve, and cancel."},{"name":"Webhooks","description":"Manage subscriptions for push events."},{"name":"Meta","description":"Health check and credit balance."}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"auth-api-key","description":"Your partner API key (format `tvl_…`)."}},"schemas":{"Error":{"type":"object","properties":{"success":{"type":"boolean","example":false},"message":{"type":"string","example":"This API key is missing the required scope: booking:write"},"code":{"type":"string","example":"insufficient_scope"},"errors":{"type":"array","items":{"type":"string"}}}},"Meta":{"type":"object","properties":{"page":{"type":"integer","example":1},"per_page":{"type":"integer","example":25},"total":{"type":"integer","example":134},"total_pages":{"type":"integer","example":6}}},"Hotel":{"type":"object","properties":{"id":{"type":"integer","example":27},"type":{"type":"string","example":"hotel"},"name":{"type":"string","example":"Marina Bay Hotel"},"description":{"type":"string"},"property_type":{"type":"string","example":"Hotel"},"star_rating":{"type":"integer","example":5},"city":{"type":"string","example":"Dubai"},"country":{"type":"string","example":"UAE"},"address":{"type":"string"},"board_type":{"type":"string","example":"Room Only"},"facilities":{"type":"array","items":{"type":"string"}},"amenities":{"type":"object"},"meal_plans":{"type":"array","items":{"type":"string"}},"guest_rating":{"type":"number","example":8.6},"reviews_count":{"type":"integer","example":214},"average_rating":{"type":"number","example":4.3},"instant_confirmation":{"type":"boolean","example":true},"currency":{"type":"string","example":"AED"},"image_url":{"type":"string","format":"uri","description":"Cover photo (absolute URL)","example":"https://travolyob2b.com/rails/active_storage/blobs/.../cover.jpg"},"photos":{"type":"array","description":"All hotel photos as absolute URLs (links — never base64).","items":{"type":"string","format":"uri"},"example":["https://travolyob2b.com/rails/active_storage/blobs/.../1.jpg","https://travolyob2b.com/rails/active_storage/blobs/.../2.jpg"]},"from_price":{"type":"number","example":350.0,"description":"Indicative nightly price in the partner's pricing mode"},"rooms":{"type":"array","items":{"$ref":"#/components/schemas/HotelRoom"}}}},"HotelRoom":{"type":"object","properties":{"id":{"type":"integer","example":83},"name":{"type":"string","example":"Deluxe King"},"board_type":{"type":"string","example":"Bed \u0026 Breakfast"},"max_adults":{"type":"integer","example":2},"max_children":{"type":"integer","example":1},"refundable":{"type":"boolean","example":true},"price_per_night":{"type":"number","example":350.0},"currency":{"type":"string","example":"AED"}}},"Activity":{"type":"object","properties":{"id":{"type":"integer","example":20},"type":{"type":"string","example":"activity"},"name":{"type":"string","example":"Desert Safari"},"category":{"type":"string","example":"Tours"},"city":{"type":"string","example":"Dubai"},"description":{"type":"string"},"duration_hours":{"type":"number","example":4.0},"languages":{"type":"array","items":{"type":"string"}},"instant_confirmation":{"type":"boolean"},"currency":{"type":"string","example":"AED"},"image_url":{"type":"string","format":"uri","description":"Cover photo (absolute URL)"},"photos":{"type":"array","description":"All activity photos as absolute URLs (links — never base64).","items":{"type":"string","format":"uri"}},"pricing":{"type":"object","properties":{"adult":{"type":"number","example":150.0},"child":{"type":"number","example":90.0},"infant":{"type":"number","example":0.0},"currency":{"type":"string","example":"AED"}}}}},"Rental":{"type":"object","properties":{"id":{"type":"integer","example":1},"type":{"type":"string","example":"rental"},"name":{"type":"string","example":"Marina Bay Residences"},"property_type":{"type":"string","example":"apartment_building"},"city":{"type":"string","example":"Dubai"},"check_in_time":{"type":"string","example":"15:00"},"check_out_time":{"type":"string","example":"11:00"},"instant_booking":{"type":"boolean"},"currency":{"type":"string","example":"AED"},"image_url":{"type":"string","format":"uri","description":"Cover photo (absolute URL)"},"photos":{"type":"array","description":"All property photos as absolute URLs (links — never base64).","items":{"type":"string","format":"uri"}},"spaces":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","example":1},"name":{"type":"string","example":"Marina Studio"},"space_type":{"type":"string","example":"entire_apartment"},"max_guests":{"type":"integer","example":2},"from_price":{"type":"number","example":350.0},"currency":{"type":"string","example":"AED"},"photos":{"type":"array","description":"Photos of this space as absolute URLs.","items":{"type":"string","format":"uri"}}}}}}},"Booking":{"type":"object","properties":{"reference":{"type":"string","example":"TRV-VILRK1JM"},"partner_reference":{"type":"string","example":"ORD-2031"},"product_type":{"type":"string","enum":["hotel","activity","rental"]},"status":{"type":"string","example":"confirmed"},"total_price":{"type":"number","example":1050.0,"description":"Partner-facing price (what you are invoiced)"},"currency":{"type":"string","example":"AED"},"pricing_mode":{"type":"string","enum":["net","markup"]},"test":{"type":"boolean","example":false},"details":{"type":"object"},"created_at":{"type":"string","format":"date-time"}}},"WebhookEvent":{"type":"object","description":"Envelope POSTed to your webhook URL (also see the `webhooks` section).","properties":{"id":{"type":"string","example":"evt_9c5454337e73..."},"type":{"type":"string","enum":["booking.confirmed","booking.cancelled","availability.changed"]},"created_at":{"type":"string","format":"date-time"},"partner":{"type":"string","example":"acme-ota"},"data":{"type":"object"}}},"QuoteRequest":{"type":"object","required":["product_type"],"description":"Identifies an item to price/book. Required fields depend on product_type.","properties":{"product_type":{"type":"string","enum":["hotel","activity","rental"]},"hotel_id":{"type":"integer","description":"hotel: required"},"room_id":{"type":"integer","description":"hotel: required"},"activity_id":{"type":"integer","description":"activity: required"},"rental_id":{"type":"integer","description":"rental: required"},"space_id":{"type":"integer","description":"rental: required"},"check_in":{"type":"string","format":"date","description":"hotel/rental"},"check_out":{"type":"string","format":"date","description":"hotel/rental"},"date":{"type":"string","format":"date","description":"activity"},"adults":{"type":"integer"},"children":{"type":"integer"},"infants":{"type":"integer"},"rooms":{"type":"integer","description":"hotel"},"guests":{"type":"integer","description":"rental"}}}},"parameters":{"Page":{"name":"page","in":"query","schema":{"type":"integer","default":1}},"PerPage":{"name":"per_page","in":"query","schema":{"type":"integer","default":25,"maximum":100}}},"responses":{"Unauthorized":{"description":"Missing/invalid/expired API key or signature","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"IP not allowlisted, mTLS/signature failed, or missing scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"Resource not found or not available to you","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Too many requests","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/meta/ping":{"get":{"tags":["Meta"],"summary":"Auth / health check","description":"Verifies your credentials and returns your partner context. `mode` is `test` or `live` depending on the API key you sent (`sandbox` is the boolean equivalent, kept for backward compatibility). Test keys never draw real credit.\n","responses":{"200":{"description":"OK","content":{"application/json":{"example":{"success":true,"message":"pong","data":{"partner":"acme-ota","status":"active","pricing_mode":"net","mode":"live","sandbox":false,"products":["hotel","activity","rental"],"scopes":["catalog:read","booking:write"],"server_time":"2026-06-08T05:37:25Z"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/meta/credit":{"get":{"tags":["Meta"],"summary":"Remaining settlement credit line","x-required-scope":"(none)","responses":{"200":{"description":"OK","content":{"application/json":{"example":{"success":true,"data":{"currency":"AED","credit_limit":100000.0,"available":98950.0,"utilized":1050.0,"blocked":false}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/hotels/{id}":{"get":{"tags":["Catalog"],"summary":"Hotel detail (full content, photos \u0026 room types)","description":"Full hotel record — description, facilities, amenities, ratings, an array of photo URLs, and bookable room types. There is no flat catalog listing; find hotels with POST /hotels/search.","x-required-scope":"catalog:read","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Hotel"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/activities/{id}":{"get":{"tags":["Catalog"],"summary":"Activity detail (full content \u0026 photos)","description":"Full activity record incl. an array of photo URLs. Find activities with POST /activities/search.","x-required-scope":"catalog:read","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/rentals/{id}":{"get":{"tags":["Catalog"],"summary":"Rental detail (full content, photos \u0026 spaces)","description":"Full rental-property record incl. an array of photo URLs and bookable spaces. Find rentals with POST /rentals/search.","x-required-scope":"catalog:read","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/hotels/search":{"post":{"tags":["Search"],"summary":"Search a destination for available hotels (with a \"from\" price)","description":"Returns hotels in the destination that have a room available for the dates/occupancy, each with the cheapest \"from\" price for the stay. Drill into one hotel with /hotels/availability.","x-required-scope":"availability:read","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["destination","check_in","check_out"],"properties":{"destination":{"type":"string","description":"City (alias: city)"},"check_in":{"type":"string","format":"date"},"check_out":{"type":"string","format":"date"},"adults":{"type":"integer","default":2},"children":{"type":"integer","default":0},"rooms":{"type":"integer","default":1}}},"example":{"destination":"Dubai","check_in":"2026-08-01","check_out":"2026-08-04","adults":2,"rooms":1}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"success":true,"data":{"destination":"Dubai","check_in":"2026-08-01","check_out":"2026-08-04","nights":3,"pricing_mode":"net","hotels":[{"hotel_id":28,"name":"Sandbox Beach Hotel","city":"Dubai","country":"UAE","star_rating":4,"image_url":"https://travolyob2b.com/rails/active_storage/blobs/.../cover.jpg","board_type":"Bed \u0026 Breakfast","refundable":true,"instant_confirmation":true,"from_price":1200.0,"currency":"AED"}]},"meta":{"total":1}}}}},"400":{"description":"Invalid dates"}}}},"/activities/search":{"post":{"tags":["Search"],"summary":"Search a destination for activities on a date","x-required-scope":"availability:read","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["destination","date"],"properties":{"destination":{"type":"string","description":"City (alias: city)"},"date":{"type":"string","format":"date"},"adults":{"type":"integer","default":2},"children":{"type":"integer","default":0},"infants":{"type":"integer","default":0},"category":{"type":"string"}}},"example":{"destination":"Dubai","date":"2026-08-01","adults":2}}}},"responses":{"200":{"description":"OK"},"400":{"description":"Invalid input"}}}},"/rentals/search":{"post":{"tags":["Search"],"summary":"Search a destination for available rentals","x-required-scope":"availability:read","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["destination","check_in","check_out"],"properties":{"destination":{"type":"string","description":"City (alias: city)"},"check_in":{"type":"string","format":"date"},"check_out":{"type":"string","format":"date"},"guests":{"type":"integer","default":1}}},"example":{"destination":"Dubai","check_in":"2026-08-01","check_out":"2026-08-04","guests":2}}}},"responses":{"200":{"description":"OK"},"400":{"description":"Invalid dates"}}}},"/hotels/availability":{"post":{"tags":["Availability"],"summary":"Live rooms \u0026 rates for one hotel","x-required-scope":"availability:read","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["hotel_id","check_in","check_out"],"properties":{"hotel_id":{"type":"integer"},"check_in":{"type":"string","format":"date"},"check_out":{"type":"string","format":"date"},"adults":{"type":"integer","default":2},"children":{"type":"integer","default":0},"rooms":{"type":"integer","default":1}}},"example":{"hotel_id":27,"check_in":"2026-07-01","check_out":"2026-07-04","adults":2,"rooms":1}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"success":true,"data":{"hotel_id":27,"nights":3,"available_rooms":[{"room_id":83,"name":"Deluxe King","nights":3,"rooms":1,"total_price":1050.0,"currency":"AED"}],"pricing_mode":"net"}}}}},"400":{"description":"Invalid dates"}}}},"/activities/availability":{"post":{"tags":["Availability"],"summary":"Live activity pricing for a date","x-required-scope":"availability:read","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["activity_id","date"],"properties":{"activity_id":{"type":"integer"},"date":{"type":"string","format":"date"},"adults":{"type":"integer","default":1},"children":{"type":"integer","default":0},"infants":{"type":"integer","default":0}}},"example":{"activity_id":20,"date":"2026-07-01","adults":2,"children":1}}}},"responses":{"200":{"description":"OK"},"400":{"description":"Invalid input"}}}},"/rentals/availability":{"post":{"tags":["Availability"],"summary":"Live rental space availability \u0026 rates","x-required-scope":"availability:read","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["rental_id","check_in","check_out"],"properties":{"rental_id":{"type":"integer"},"check_in":{"type":"string","format":"date"},"check_out":{"type":"string","format":"date"},"guests":{"type":"integer","default":1}}},"example":{"rental_id":1,"check_in":"2026-07-01","check_out":"2026-07-05","guests":2}}}},"responses":{"200":{"description":"OK"},"400":{"description":"Invalid dates"}}}},"/bookings/prebook":{"post":{"tags":["Bookings"],"summary":"Validate \u0026 price-lock, returns a prebook_token","description":"Re-checks availability and locks the price for 15 minutes. Pass the returned `prebook_token` to `POST /bookings`.","x-required-scope":"availability:read","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteRequest"},"examples":{"hotel":{"summary":"Hotel — needs hotel_id + room_id, check_in/check_out, occupancy","value":{"product_type":"hotel","hotel_id":27,"room_id":83,"check_in":"2026-08-01","check_out":"2026-08-04","adults":2,"children":0,"rooms":1}},"activity":{"summary":"Activity — needs activity_id + a single date (no check_out) + participants","value":{"product_type":"activity","activity_id":20,"date":"2026-08-01","adults":2,"children":1,"infants":0}},"rental":{"summary":"Rental — needs rental_id + space_id, check_in/check_out, guests","value":{"product_type":"rental","rental_id":1,"space_id":1,"check_in":"2026-09-01","check_out":"2026-09-04","guests":2}}}}}},"responses":{"200":{"description":"Prebook token + locked price (15-minute TTL)","content":{"application/json":{"examples":{"hotel":{"value":{"success":true,"data":{"prebook_token":"pbk_2a01...","expires_at":"2026-08-01T06:08:29Z","product_type":"hotel","total_price":1050.0,"currency":"AED","instant_confirmation":true,"cancellation_policy":"refundable"}}},"activity":{"value":{"success":true,"data":{"prebook_token":"pbk_7b42...","expires_at":"2026-08-01T06:08:29Z","product_type":"activity","total_price":390.0,"currency":"AED","instant_confirmation":true,"cancellation_policy":"see_policy"}}},"rental":{"value":{"success":true,"data":{"prebook_token":"pbk_3921...","expires_at":"2026-09-01T13:04:04Z","product_type":"rental","total_price":1050.0,"currency":"AED","instant_confirmation":true,"cancellation_policy":"moderate"}}}}}}},"422":{"description":"Item unavailable / invalid quote"}}}},"/bookings":{"get":{"tags":["Bookings"],"summary":"List your bookings","x-required-scope":"booking:read","parameters":[{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/PerPage"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Booking"}}}}}}}}},"post":{"tags":["Bookings"],"summary":"Create a booking (idempotent)","description":"Draws down your credit line and creates the booking. Requires an `Idempotency-Key` header; replaying it returns the original booking.","x-required-scope":"booking:write","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string"},"example":"order-2031-attempt-1"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/QuoteRequest"},{"type":"object","properties":{"prebook_token":{"type":"string","description":"Optional; locks the prebooked price"},"partner_reference":{"type":"string"},"guest":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"},"special_requests":{"type":"string"}}}}}]},"examples":{"with_prebook_token":{"summary":"Book a prebooked quote (recommended) — just the token + guest","value":{"prebook_token":"pbk_2a01...","partner_reference":"ORD-2031","guest":{"name":"Jane Doe","email":"jane@example.com","phone":"971501112222"}}},"hotel_direct":{"summary":"Direct hotel booking (no prebook) — pass the full quote; it re-prices then charges","value":{"product_type":"hotel","hotel_id":27,"room_id":83,"check_in":"2026-08-01","check_out":"2026-08-04","adults":2,"rooms":1,"partner_reference":"ORD-2031","guest":{"name":"Jane Doe","email":"jane@example.com","phone":"971501112222"}}},"activity_direct":{"summary":"Direct activity booking — uses a single `date` and participant counts","value":{"product_type":"activity","activity_id":20,"date":"2026-08-01","adults":2,"children":1,"partner_reference":"ORD-2032","guest":{"name":"Jane Doe","email":"jane@example.com","phone":"971501112222"}}},"rental_direct":{"summary":"Direct rental booking — uses space_id + guests","value":{"product_type":"rental","rental_id":1,"space_id":1,"check_in":"2026-09-01","check_out":"2026-09-04","guests":2,"partner_reference":"ORD-2033","guest":{"name":"Jane Doe","email":"jane@example.com","phone":"971501112222"}}}}}}},"responses":{"201":{"description":"Booking created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Booking"}}},"examples":{"hotel":{"value":{"success":true,"message":"Booking created","data":{"reference":"TRV-VILRK1JM","partner_reference":"ORD-2031","product_type":"hotel","status":"confirmed","total_price":1050.0,"currency":"AED","pricing_mode":"net","test":false,"details":{"hotel_id":27,"check_in":"2026-08-01","check_out":"2026-08-04","rooms":1,"guests":2,"guest_name":"Jane Doe"},"created_at":"2026-06-08T05:53:29Z"}}},"activity":{"value":{"success":true,"message":"Booking created","data":{"reference":"ACT-7K2M9XQP","partner_reference":"ORD-2032","product_type":"activity","status":"confirmed","total_price":390.0,"currency":"AED","pricing_mode":"net","test":false,"details":{"activity_id":20,"date":"2026-08-01","adults":2,"children":1,"guest_name":"Jane Doe"},"created_at":"2026-06-08T05:53:29Z"}}},"rental":{"value":{"success":true,"message":"Booking created","data":{"reference":"RNT-J3JWAFCJ","partner_reference":"ORD-2033","product_type":"rental","status":"confirmed","total_price":1050.0,"currency":"AED","pricing_mode":"net","test":false,"details":{"rental_property_id":1,"space_id":1,"check_in":"2026-09-01","check_out":"2026-09-04","nights":3,"guests":2,"guest_name":"Jane Doe"},"created_at":"2026-06-08T05:53:29Z"}}}}}}},"200":{"description":"Idempotent replay — returns the original booking (no second charge)"},"402":{"description":"Insufficient credit / credit blocked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Duplicate partner_reference"},"422":{"description":"Invalid quote / prebook expired"}}}},"/bookings/{reference}":{"get":{"tags":["Bookings"],"summary":"Retrieve a booking","x-required-scope":"booking:read","parameters":[{"name":"reference","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/bookings/{reference}/cancel":{"post":{"tags":["Bookings"],"summary":"Cancel a booking (releases credit)","x-required-scope":"booking:write","parameters":[{"name":"reference","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string"}}}}}},"responses":{"200":{"description":"Cancelled"},"422":{"description":"Not cancellable in current state"}}}},"/webhooks":{"get":{"tags":["Webhooks"],"summary":"List webhook subscriptions","x-required-scope":"webhook:manage","responses":{"200":{"description":"OK"}}},"post":{"tags":["Webhooks"],"summary":"Create a webhook subscription","description":"Returns a signing `secret` once — store it to verify `X-Partner-Signature` on delivered events.","x-required-scope":"webhook:manage","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url","event_types"],"properties":{"url":{"type":"string","format":"uri","description":"Must be https"},"event_types":{"type":"array","items":{"type":"string","enum":["booking.confirmed","booking.cancelled","availability.changed"]}}}},"example":{"url":"https://partner.example.com/webhooks","event_types":["booking.confirmed","booking.cancelled"]}}}},"responses":{"201":{"description":"Created (returns signing secret once)"},"422":{"description":"Invalid url / event types"}}}},"/webhooks/{id}":{"delete":{"tags":["Webhooks"],"summary":"Delete a webhook subscription","x-required-scope":"webhook:manage","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Deleted"},"404":{"$ref":"#/components/responses/NotFound"}}}}},"webhooks":{"booking.confirmed":{"post":{"summary":"Sent when a booking is confirmed","description":"Delivered to your subscribed HTTPS endpoint. Verify the signature:\n`HMAC-SHA256(subscription_secret, \"\u003cX-Partner-Timestamp\u003e.\u003craw_body\u003e\")` == `X-Partner-Signature`.\nRetries with exponential backoff (up to 5 attempts). Use `X-Partner-Event-Id` to dedupe.\n","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"},"example":{"id":"evt_9c54...","type":"booking.confirmed","created_at":"2026-06-08T06:02:59Z","partner":"acme-ota","data":{"reference":"RNT-WAGD3FVW","partner_reference":"ORD-2031","status":"confirmed","total_price":1050.0,"currency":"AED","test":false}}}}},"responses":{"200":{"description":"Acknowledge receipt with any 2xx"}}}},"booking.cancelled":{"post":{"summary":"Sent when a booking is cancelled","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}},"responses":{"200":{"description":"Acknowledge with any 2xx"}}}},"availability.changed":{"post":{"summary":"Sent when an item's availability or price changes","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"},"example":{"id":"evt_abc1...","type":"availability.changed","data":{"product_type":"hotel","item_id":27}}}}},"responses":{"200":{"description":"Acknowledge with any 2xx"}}}}}}