Developers
B2B API documentation
The B2B API behind nwp.ae: price and book for your clients at net, issue vouchers, and run a hotel desk, corporate transport and DMC programmes, with your rates, statements and invoices alongside. Early access: sandbox keys answer with labelled test data, and live keys are issued on approval.
StatusEarly access · sandbox only
The sandbox checks real requests against the real schema and answers with test data. Nothing is booked, no vehicle is held and no price is returned. The sandbox carries no service-level commitment, and production keys are issued to approved partners when the API opens.
Request early accessOverview
JSON over HTTPS. Send Content-Type: application/json. Every response is JSON and carries an x-request-id header to quote to the trade desk; sandbox responses also carry x-nwp-environment: sandbox.
| Base URL | — |
|---|---|
| Sandbox | https://nwp.ae/api/b2b/sandbox |
| Production | https://nwp.ae/api/b2b/v1Not open yet · Requires a live key — issued on approval |
B2B API v1
One API for everything an account does: ground transport and tours & activities priced on your commercial terms (net rate, commission or tariff), bookings for your clients, vouchers and name boards, the hotel desk, corporate transport, DMC programmes, the booking widget, users, notices, statements and invoices. Sandbox keys (nwp_test_…) are open to applicants: they answer every endpoint with test data flagged sandbox: true and never book or change your account. Live keys (nwp_live_…) are issued on approval and work once NWP has switched live access on for your account. Every POST takes an Idempotency-Key, every answer carries x-request-id, and each key has its own per-minute limit.
The OpenAPI 3.1 document: /api/b2b/v1/openapi.json
Ground transport
POST/api/b2b/v1/transport/quotePrice under your terms
Scope:
transport:readPOST/api/b2b/v1/transport/bookingsBook
Scope:
transport:writeRequires a live key — issued on approvalGET/api/b2b/v1/transport/bookings/{id}Booking status and cancellation terms
Scope:
transport:readPOST/api/b2b/v1/transport/bookings/{id}/cancelCancel under the policy
Scope:
transport:writeRequires a live key — issued on approvalGET/api/b2b/v1/transport/bookings/{id}/voucherVoucher in your brand (HTML or PDF)
Scope:
transport:read
Tours & activities
GET/api/b2b/v1/activities/productsProducts on sale, per person or per vehicle
Scope:
activities:readGET/api/b2b/v1/activities/products/{id}/availabilityAvailability by day
Scope:
activities:readPOST/api/b2b/v1/activities/quotePrice under your terms
Scope:
activities:readPOST/api/b2b/v1/activities/bookingsBook
Scope:
activities:writeRequires a live key — issued on approvalGET/api/b2b/v1/activities/bookings/{id}Booking status and cancellation terms
Scope:
activities:readPOST/api/b2b/v1/activities/bookings/{id}/cancelCancel under the policy
Scope:
activities:writeRequires a live key — issued on approvalGET/api/b2b/v1/activities/bookings/{id}/voucherVoucher in your brand (HTML or PDF)
Scope:
activities:read
Cruise
GET/api/b2b/v1/cruise/sailingsSailings
Scope:
cruise:readNot yet available: answers 501 until a cruise supplier is connectedPOST/api/b2b/v1/cruise/quotePrice under your terms
Scope:
cruise:readNot yet available: answers 501 until a cruise supplier is connectedPOST/api/b2b/v1/cruise/bookingsBook
Scope:
cruise:writeNot yet available: answers 501 until a cruise supplier is connectedGET/api/b2b/v1/cruise/bookings/{id}Booking status and cancellation terms
Scope:
cruise:readNot yet available: answers 501 until a cruise supplier is connectedPOST/api/b2b/v1/cruise/bookings/{id}/cancelCancel under the policy
Scope:
cruise:writeNot yet available: answers 501 until a cruise supplier is connected
Welcome guides
GET/api/b2b/v1/guides/propertiesYour properties
Scope:
guides:readPOST/api/b2b/v1/guides/propertiesAdd a property
Scope:
guides:writeGET/api/b2b/v1/guides/properties/{id}A property's guide, link and files
Scope:
guides:readPATCH/api/b2b/v1/guides/properties/{id}Edit a property
Scope:
guides:writePOST/api/b2b/v1/guides/properties/{id}/statusPause or resume a guide
Scope:
guides:writePOST/api/b2b/v1/guides/properties/{id}/linkReplace the guest link
Scope:
guides:writeGET/api/b2b/v1/guides/properties/{id}/wifiRead the Wi-Fi back
Scope:
guides_wifi:readPOST/api/b2b/v1/guides/properties/{id}/wifiSet the Wi-Fi
Scope:
guides_wifi:writeGET/api/b2b/v1/guides/properties/{id}/qrQR code (PNG or SVG)
Scope:
guides:readGET/api/b2b/v1/guides/properties/{id}/cardPrintable card (PDF or HTML)
Scope:
guides:readGET/api/b2b/v1/guides/statsScans, views, bookings and your split
Scope:
guides:read
Account
GET/api/b2b/v1/whoamiCheck a key
Scope:
account:readGET/api/b2b/v1/openapi.jsonThis API as OpenAPI 3.1
Affiliates
GET/api/b2b/v1/affiliate/statsStatistics for a period: clicks, bookings, conversion, earnings
Scope:
affiliate:readGET/api/b2b/v1/affiliate/linksYour tracking links, with QR codes
Scope:
affiliate:readPOST/api/b2b/v1/affiliate/linksBuild a tracking link with UTM
Scope:
affiliate:writeRequires a live key — issued on approvalGET/api/b2b/v1/affiliate/links/{code}/qrA link's QR code (SVG or PNG)
Scope:
affiliate:readGET/api/b2b/v1/affiliate/performanceClicks, bookings and earnings by link
Scope:
affiliate:readGET/api/b2b/v1/affiliate/payoutsPayout balance and requests
Scope:
affiliate:readPOST/api/b2b/v1/affiliate/payoutsRequest a payout, sent by bank transfer
Scope:
affiliate:writeRequires a live key — issued on approvalPOST/api/b2b/v1/affiliate/payouts/{reference}/cancelWithdraw a payout request
Scope:
affiliate:writeRequires a live key — issued on approvalPOST/api/b2b/v1/affiliate/bank-detailsSave bank details (write-only)
Scope:
affiliate:writeRequires a live key — issued on approvalGET/api/b2b/v1/affiliate/widgetWidget settings and snippet
Scope:
affiliate:readPOST/api/b2b/v1/affiliate/widgetSet up the booking widget
Scope:
affiliate:writeRequires a live key — issued on approval
Bookings for your clients
POST/api/b2b/v1/bookings/quotePrice under your terms
Scope:
bookings:createPOST/api/b2b/v1/bookingsBook
Scope:
bookings:createRequires a live key — issued on approvalGET/api/b2b/v1/bookingsList
Scope:
bookings:viewGET/api/b2b/v1/bookings/creditedBookings credited to your account
Scope:
bookings:viewGET/api/b2b/v1/bookings/{ref}Details
Scope:
bookings:viewPOST/api/b2b/v1/bookings/{ref}/cancelCancel under the policy
Scope:
bookings:manageRequires a live key — issued on approvalPOST/api/b2b/v1/bookings/{ref}/amendmentsAsk the trade desk for a change
Scope:
bookings:manageRequires a live key — issued on approvalPOST/api/b2b/v1/bookings/{ref}/brandYour brand, or none, on its documents
Scope:
bookings:manageRequires a live key — issued on approvalGET/api/b2b/v1/bookings/{ref}/voucherVoucher in your brand (HTML or PDF)
Scope:
bookings:viewGET/api/b2b/v1/bookings/{ref}/name-boardDriver's name board (HTML)
Scope:
bookings:viewGET/api/b2b/v1/requestsChange and service requests, with the desk's answers
Scope:
bookings:viewPOST/api/b2b/v1/requests/{id}/withdrawWithdraw an open request
Scope:
bookings:manageRequires a live key — issued on approval
Hotel desk
POST/api/b2b/v1/desk/salesQuick sale at the desk
Scope:
bookings:createRequires a live key — issued on approvalGET/api/b2b/v1/desk/days/{date}A day's sales, or its settlement as CSV or PDF
Scope:
statements:readPOST/api/b2b/v1/desk/days/{date}/closeClose the day and freeze its settlement
Scope:
statements:readRequires a live key — issued on approval
Corporate transport
GET/api/b2b/v1/corporate/cost-centresList
Scope:
bookings:viewPOST/api/b2b/v1/corporate/cost-centresCreate or change
Scope:
settings:manageRequires a live key — issued on approvalPOST/api/b2b/v1/corporate/cost-centres/{id}/approversCreate or change
Scope:
settings:manageRequires a live key — issued on approvalGET/api/b2b/v1/corporate/requestsList
Scope:
bookings:viewPOST/api/b2b/v1/corporate/requestsBook
Scope:
bookings:createRequires a live key — issued on approvalPOST/api/b2b/v1/corporate/requests/{id}/decisionApprove or decline
Scope:
bookings:createRequires a live key — issued on approvalGET/api/b2b/v1/corporate/shuttlesList
Scope:
bookings:viewPOST/api/b2b/v1/corporate/shuttlesCreate or change
Scope:
bookings:createRequires a live key — issued on approvalPOST/api/b2b/v1/corporate/shuttles/{id}/statusChange its status
Scope:
bookings:createRequires a live key — issued on approvalPOST/api/b2b/v1/corporate/shuttles/{id}/scheduleSchedule a month of runs
Scope:
bookings:createRequires a live key — issued on approvalPOST/api/b2b/v1/corporate/shuttles/{id}/repricePick up a newly agreed rate
Scope:
bookings:createRequires a live key — issued on approvalGET/api/b2b/v1/corporate/usageUsage by cost centre (JSON or CSV)
Scope:
statements:read
DMC programmes
GET/api/b2b/v1/dmc/programmesList
Scope:
bookings:viewPOST/api/b2b/v1/dmc/programmesCreate or change
Scope:
bookings:createRequires a live key — issued on approvalGET/api/b2b/v1/dmc/programmes/{id}Details
Scope:
bookings:viewPOST/api/b2b/v1/dmc/programmes/{id}/versionsSave a priced version
Scope:
bookings:createRequires a live key — issued on approvalPOST/api/b2b/v1/dmc/programmes/{id}/statusChange its status
Scope:
bookings:createRequires a live key — issued on approvalPOST/api/b2b/v1/dmc/programmes/{id}/brandYour brand, or none, on its documents
Scope:
bookings:createRequires a live key — issued on approvalPOST/api/b2b/v1/dmc/programmes/{id}/acceptAccept a version and book it
Scope:
bookings:createRequires a live key — issued on approvalGET/api/b2b/v1/dmc/programmes/{id}/proposalClient proposal (HTML)
Scope:
bookings:viewPOST/api/b2b/v1/dmc/programmes/{id}/linksIssue an expiring client link
Scope:
bookings:createRequires a live key — issued on approvalGET/api/b2b/v1/dmc/programmes/{id}/linksClient links and who accepted
Scope:
bookings:viewPOST/api/b2b/v1/dmc/programmes/{id}/links/{link}/revokeRevoke a client link
Scope:
bookings:createRequires a live key — issued on approval
Rates and quote requests
GET/api/b2b/v1/rates/catalogueCatalogue at your rates (JSON, CSV or PDF)
Scope:
rates:viewGET/api/b2b/v1/rates/sheetService rate sheet
Scope:
rates:viewPOST/api/b2b/v1/quote-requestsSend a quote request
Scope:
bookings:createRequires a live key — issued on approvalPOST/api/b2b/v1/wholesale-requestsRequest vehicle capacity
Scope:
bookings:createRequires a live key — issued on approval
Booking widget
GET/api/b2b/v1/widgetWidget settings and snippet
Scope:
tracking:viewPOST/api/b2b/v1/widgetChange the widget
Scope:
tracking:manageRequires a live key — issued on approval
Users
GET/api/b2b/v1/usersList
Scope:
users:viewPOST/api/b2b/v1/usersInvite a person
Scope:
users:manageRequires a live key — issued on approvalPOST/api/b2b/v1/users/{id}/roleChange a person's role
Scope:
users:manageRequires a live key — issued on approvalPOST/api/b2b/v1/users/{id}/deactivateRemove a person's access
Scope:
users:manageRequires a live key — issued on approvalPOST/api/b2b/v1/users/{id}/reactivateRestore a person's access
Scope:
users:manageRequires a live key — issued on approval
Notices
GET/api/b2b/v1/inboxNotices about your account
Scope:
inbox:view
Statements and invoices
GET/api/b2b/v1/statementsStatements, balance and open invoices
Scope:
statements:readGET/api/b2b/v1/statements/{period}One month's statement (JSON or PDF)
Scope:
statements:readGET/api/b2b/v1/invoices/{id}One invoice (JSON or PDF)
Scope:
statements:read
Account settings
GET/api/b2b/v1/settingsAccount particulars, contacts and billing email
Scope:
settings:viewPOST/api/b2b/v1/settings/billing-emailSet the billing email
Scope:
settings:manageRequires a live key — issued on approvalPOST/api/b2b/v1/settings/contactsAdd or change a contact
Scope:
settings:manageRequires a live key — issued on approvalPOST/api/b2b/v1/settings/contacts/{id}/removeRemove a contact
Scope:
settings:manageRequires a live key — issued on approvalPOST/api/b2b/v1/settings/brandYour brand, or none, on its documents
Scope:
settings:manageRequires a live key — issued on approval
curl -X POST 'https://nwp.ae/api/b2b/v1/transport/quote' \
-H 'Authorization: Bearer nwp_test_…' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: 7f1c2b0e-quote-1' \
-d '{"airport":"dxb","terminal":"t3","direction":"from_airport","place":"downtown","vehicle":"vclass","pickup_date":"2026-11-02","pickup_time":"14:30","passengers":3,"bags":3}'Authentication
Every sandbox call takes a bearer token. The developer handshake issues one: a JWT-shaped token that starts nwp_sandbox_, lasts 30 days and opens test data and nothing else.
1Request a sandbox token
curl -X POST https://nwp.ae/api/b2b/orchestration \
-H 'Content-Type: application/json' \
-d '{
"action": "developer_handshake",
"platform_name": "Example Travel App",
"contact_email": "developers@example.com",
"use_case": "transfers"
}'{
"environment": "sandbox",
"status": "early-access",
"test_data": true,
"token_type": "Bearer",
"token": "nwp_sandbox_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImVudiI6InNhbmRib3gifQ…",
"expires_at": "2026-10-31T08:00:00.000Z",
"scopes": [
"sandbox:transfers.quote",
"sandbox:availability.read"
],
"endpoints": [
{
"method": "POST",
"url": "https://nwp.ae/api/b2b/sandbox/transfers"
},
{
"method": "GET",
"url": "https://nwp.ae/api/b2b/sandbox/availability"
},
{
"method": "GET",
"url": "https://nwp.ae/api/b2b/sandbox/status"
}
],
"production": {
"status": "not_open",
"request_access": "https://nwp.ae/register?type=institutional"
}
}2Call the sandbox with it
curl -X POST https://nwp.ae/api/b2b/sandbox/transfers \
-H 'Authorization: Bearer nwp_sandbox_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImVudiI6InNhbmRib3gifQ…' \
-H 'Content-Type: application/json' \
-d @transfer.jsonTransfer request
Send the fields below to the sandbox transfers endpoint. Field names belong to the API and stay in English in every language.
pickup_locationRequired{ type: "airport" | "coordinates" | "hotel", … }Where the passenger is collected: an airport terminal (DXB_T1, DXB_T2, DXB_T3, DWC, SHJ), coordinates inside the UAE, or a hotel reference.
dropoff_locationRequired{ type: "hotel" | "coordinates" | "airport", … }Where the passenger is taken: a hotel reference string (your own hotel code or the hotel's name), coordinates, or an airport terminal.
flight_numberConditionalstringThe arriving flight, such as EK202. The pickup is timed to the flight's scheduled landing.
pickup_atConditionalstring (ISO 8601)ISO 8601 with an offset. Required when the pickup is not at an airport, or when an airport pickup has no flight.
buffer_minutes_overrideOptionalintegerFree waiting after landing, in minutes, from 0 to 180. The default is 60: the free waiting the group's transfer site already gives every arrival.
vehicle_classRequiredenumOne of VIP_V_CLASS, EXECUTIVE_SEDAN, or LUXURY_COACH.
passengersOptionalintegerRefused when it is more than the class seats.
client_metadataOptionalobjectWhite-label details for the traveller's voucher: agency_name, logo_url (https only), voucher_branding and agency_reference.
| Field | Type | Required | Description |
|---|---|---|---|
pickup_location | { type: "airport" | "coordinates" | "hotel", … } | Required | Where the passenger is collected: an airport terminal (DXB_T1, DXB_T2, DXB_T3, DWC, SHJ), coordinates inside the UAE, or a hotel reference. |
dropoff_location | { type: "hotel" | "coordinates" | "airport", … } | Required | Where the passenger is taken: a hotel reference string (your own hotel code or the hotel's name), coordinates, or an airport terminal. |
flight_number | string | Conditional | The arriving flight, such as EK202. The pickup is timed to the flight's scheduled landing. |
pickup_at | string (ISO 8601) | Conditional | ISO 8601 with an offset. Required when the pickup is not at an airport, or when an airport pickup has no flight. |
buffer_minutes_override | integer | Optional | Free waiting after landing, in minutes, from 0 to 180. The default is 60: the free waiting the group's transfer site already gives every arrival. |
vehicle_class | enum | Required | One of VIP_V_CLASS, EXECUTIVE_SEDAN, or LUXURY_COACH. |
passengers | integer | Optional | Refused when it is more than the class seats. |
client_metadata | object | Optional | White-label details for the traveller's voucher: agency_name, logo_url (https only), voucher_branding and agency_reference. |
{
"pickup_location": {
"type": "airport",
"terminal": "DXB_T3"
},
"dropoff_location": {
"type": "hotel",
"hotel_ref": "EXAMPLE-HOTEL-DOWNTOWN"
},
"flight_number": "EK202",
"buffer_minutes_override": 60,
"vehicle_class": "VIP_V_CLASS",
"passengers": 4,
"client_metadata": {
"agency_name": "Example Travel",
"logo_url": "https://example.com/logo.png",
"voucher_branding": {
"mode": "white_label",
"accent_hex": "#0A0A0A"
},
"agency_reference": "EX-10442"
}
}Vehicle classes
| Class | Vehicle | Seats |
|---|---|---|
VIP_V_CLASS | Mercedes-Benz V-Class or similar | 7 |
EXECUTIVE_SEDAN | Lexus ES 350 or a similar executive saloon | 3 |
LUXURY_COACH | Toyota Coaster or King Long coach | 30 |
Each vehicle is hired with its licensed chauffeur for the job; the class fixes the type of vehicle and its seats.
Response
A sandbox quote echoes the request and adds how the pickup will be timed and how the voucher will be branded. It never carries a price.
{
"environment": "sandbox",
"test_data": true,
"notice": "Sandbox response: test data only. Nothing is booked, no vehicle is held and no price is quoted. Production is not open yet.",
"quote_id": "SBX-WT5PCXWF",
"status": "sandbox_accepted",
"vehicle": {
"class": "VIP_V_CLASS",
"description": "Mercedes-Benz V-Class or similar",
"max_passengers": 7
},
"passengers": 4,
"pickup": {
"location": {
"type": "airport",
"terminal": "DXB_T3"
},
"timing": {
"mode": "flight_landing",
"flight_number": "EK202",
"driver_ready": "at the scheduled landing time",
"free_waiting_minutes": 60,
"live_arrival_tracking": "planned"
}
},
"dropoff": {
"location": {
"type": "hotel",
"hotel_ref": "EXAMPLE-HOTEL-DOWNTOWN"
}
},
"voucher": {
"branding": "white_label",
"agency_name": "Example Travel",
"logo_url": "https://example.com/logo.png",
"accent_hex": "#0A0A0A",
"footer_text": null,
"agency_reference": "EX-10442",
"shows_nwp_branding": false
},
"price": null,
"price_note": "Sandbox quotes carry no price. Net rates are issued to approved partners in the portal.",
"default_buffer_minutes": 60,
"created_at": "2026-10-01T08:00:00.000Z"
}{
"error": {
"code": "validation_failed",
"message": "One or more fields are invalid.",
"retryable": false,
"fields": [
"flight_number"
],
"issues": [
{
"path": "flight_number",
"message": "flight_number must be an airline flight number such as EK202."
}
]
},
"environment": "sandbox"
}Flight timing
Today the pickup is timed to the landing time on the booking, and the driver waits free for the buffer after it. If a flight moves, tell the trade desk and the pickup moves with it.
Automated live arrival tracking through FlightAware or AeroDataBox is planned. Neither is connected yet, and the sandbox reports live_arrival_tracking as planned.
Signed availability
The handshake returns a signed availability URL. The signature covers the date, the vehicle class and the expiry; change any of them and the call is refused. The statuses are samples to build against.
curl 'https://nwp.ae/api/b2b/sandbox/availability?date=2026-10-15&vehicle_class=VIP_V_CLASS&expires=1760572800&sig=…'{
"environment": "sandbox",
"test_data": true,
"notice": "Sandbox response: test data only. Nothing is booked, no vehicle is held and no price is quoted. Production is not open yet.",
"date": "2026-10-15",
"vehicle_class": "VIP_V_CLASS",
"vehicle": {
"description": "Mercedes-Benz V-Class or similar",
"max_passengers": 7
},
"sample_status": "on_request",
"note": "A sample status for building against. Real availability is confirmed by the trade desk until the API opens."
}Account actions
POST to the orchestration endpoint with an action. An action that asks a person to do something is stored and passed to the trade desk before the response says so.
| Action | What it does |
|---|---|
credit_line_application | Net-15, 30, 45 or 60 terms for a UAE-registered company. The trade licence number and the TRN (15 digits, beginning 100) are required. A person reviews every application, and bookings are prepaid until a line is approved. |
wallet_topup | A prepayment into your account. Card top-ups are not available yet, so the trade desk invoices you by bank transfer, and the response says so. |
account_payload | Your account's currency matrix. AED is the base and the only currency anything is charged or earned in; other currencies are display conversions at the site's daily rate, so a margin never moves in conversion. |
tracking_link | A deterministic partner URL and QR code for the holiday-home and affiliate tiers, with a plain statement of where it is credited today. |
developer_handshake | A sandbox token, the sandbox endpoints and a signed availability URL. |
{
"action": "credit_line_application",
"company_legal_name": "Example Travel L.L.C.",
"trade_licence_number": "1234567",
"licence_authority": "Department of Economy and Tourism, Dubai",
"trn": "100000000000003",
"contact_name": "Finance Desk",
"contact_email": "finance@example.com",
"requested_terms": "NET_30",
"requested_limit_aed": 50000
}{
"action": "wallet_topup",
"company_name": "Example Travel L.L.C.",
"contact_email": "finance@example.com",
"amount_aed": 10000,
"purchase_order": "PO-2291"
}{
"action": "account_payload",
"company_name": "Example Travel L.L.C.",
"tier": "Tier_4_Regional_DMCs",
"display_currencies": [
"USD",
"EUR"
],
"lines": [
{
"label": "Your own city-tour package",
"net_aed": 400,
"sell_aed": 560
}
]
}{
"action": "tracking_link",
"partner_code": "HHO-EXAMPLE",
"tier": "Tier_1_Holiday_Homes",
"property_id": "marina-2104",
"destination": "dubaitransfers.ae"
}Errors
Every error has the same shape: error.code, error.message and error.retryable, with fields and issues on a validation failure.
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_json | The body is not valid JSON. |
| 401 | unauthenticated | No sandbox token, or one that is malformed, expired or wrongly signed. |
| 404 | not_found | The endpoint does not exist on this host. |
| 405 | method_not_allowed | The endpoint takes another method. |
| 413 | payload_too_large | The body is larger than 16 KB. |
| 422 | validation_failed | A field is missing or malformed: see fields and issues. |
| 429 | rate_limited | Too many requests from this address: retry after retry_after_seconds. |
| 500 | internal | Something failed on our side: quote the request id. |
| 502 | upstream_unavailable | A payment provider did not answer. |
| 503 | not_configured | The request could not be stored: email the trade desk. |
Rate limits
Account actions are limited per address, per hour: credit_line_application: 5, wallet_topup: 10, account_payload: 60, tracking_link: 60, and developer_handshake: 10. Sandbox calls are limited to 120 an hour per address.
Booking widget
The booking widget is open to approved partners in early access: one script tag puts nwp.ae's tours and transfers on your site at the public price, in twelve languages, with your name on it and your partner code on every booking. Set it up through the API: the booking widget endpoints read and change its settings and return the snippet to paste.