01
Overview
The UTA Partner API lets approved travel partners sell and manage UTA services from their own websites, apps and back-office systems. Every request is authenticated with a partner API key and authorized against the services assigned to that partner.
- Visa: document upload, application submission, status tracking, application listing, fee catalogue and quotes.
- Flights: search, offer & bundles, reprice, book / hold, retrieve and cancel.
- Hotels: search, property details, room availability, book, retrieve and cancel.
- Attractions: activity search, details, availability, book, retrieve and cancel.
- Pricing: every service above also exposes a price-only endpoint for fast customer quoting, documented inside its own service section.
All services share the same authentication, sandbox behaviour and service authorization. There are two response shapes: the core Visa endpoints (visa-upload, visa-apply, visa-status, visa-applications) return a flat body such as { success, reference, … }, while every other endpoint (Flights, Hotels, Attractions and the /visa/… helpers) returns the standard envelope { success, data, errors, meta }.
Architecture
Partner Website
|
| API Request + x-api-key
v
UTA Partner API
|
v
Authentication (is the API key valid and active?)
|
v
Service Authorization (is this service assigned to the partner?)
|
v
UTA Services (visa, flights, hotels, attractions)02
Getting Started
Step 1 — Partner account creation
- Your partner account is created by a UTA administrator.
- The admin assigns the services your account may access — Visa, Flights, Hotels and Attractions.
- A secure API key is generated and shown once. Store it immediately in your secret manager — UTA cannot show it again, only regenerate it.
Step 2 — API authentication
Every request must send your key in the `x-api-key` header.
x-api-key: YOUR_PARTNER_API_KEYcurl https://uta.online/api/public/visa-applications \
-H "x-api-key: uta_live_xxxxxxxxx" \
-H "Content-Type: application/json"Keep keys server-side
03
Base URLs
https://uta.online/api/public/https://sandbox.uta.online/api/public/https://uta.online/api/public/visa-uploadRequires x-api-keyhttps://uta.online/api/public/visa-applyRequires x-api-keyhttps://uta.online/api/public/visa-statusRequires x-api-keyhttps://uta.online/api/public/visa-applicationsRequires x-api-keyhttps://uta.online/api/public/flights/searchRequires x-api-keyhttps://uta.online/api/public/flights/{offerId}Requires x-api-keyhttps://uta.online/api/public/flights/repriceRequires x-api-keyhttps://uta.online/api/public/flights/bookRequires x-api-keyhttps://uta.online/api/public/flights/bookings/{bookingId}Requires x-api-keyhttps://uta.online/api/public/flights/cancelRequires x-api-keyhttps://uta.online/api/public/hotels/searchRequires x-api-keyhttps://uta.online/api/public/hotels/{hotelId}Requires x-api-keyhttps://uta.online/api/public/hotels/availabilityRequires x-api-keyhttps://uta.online/api/public/hotels/bookRequires x-api-keyhttps://uta.online/api/public/hotels/bookings/{reference}Requires x-api-keyhttps://uta.online/api/public/hotels/cancelRequires x-api-keyhttps://uta.online/api/public/attractions/searchRequires x-api-keyhttps://uta.online/api/public/attractions/{activityId}Requires x-api-keyhttps://uta.online/api/public/attractions/availabilityRequires x-api-keyhttps://uta.online/api/public/attractions/bookRequires x-api-keyhttps://uta.online/api/public/attractions/bookings/{bookingId}Requires x-api-keyhttps://uta.online/api/public/attractions/bookings/{bookingId}/cancelRequires x-api-keyhttps://uta.online/api/public/flights/pricingRequires x-api-keyhttps://uta.online/api/public/hotels/pricingRequires x-api-keyhttps://uta.online/api/public/attractions/pricingRequires x-api-keyhttps://uta.online/api/public/visa/pricingRequires x-api-keyhttps://uta.online/api/public/visa/quoteRequires x-api-keyhttps://uta.online/api/public/visa/documentsRequires x-api-keyhttps://uta.online/api/public/visa/passport-scanRequires x-api-keyhttps://uta.online/api/public/visa/address-scanRequires x-api-keyAll endpoints accept and return JSON (`visa-upload` accepts `multipart/form-data`) and support `OPTIONS` pre-flight requests.
04
Authentication
Method: API key authentication via the required `x-api-key` request header. Keys are issued per partner, can be regenerated, and can be revoked at any time.
| Field | Type | Required | Description |
|---|---|---|---|
| x-api-key | header (string) | Required | Your partner API key: uta_live_xxxxxxxxx (production) or uta_test_xxxxxxxxx (sandbox). |
A missing, malformed, revoked or deactivated key returns HTTP 401.
{
"success": false,
"error": "Invalid API key."
}04b
Sandbox Environment
Every partner account belongs to exactly one environment. Sandbox lets you build and test a full integration — visa applications, flight, hotel and attraction bookings — without creating real submissions or supplier reservations.
| Field | Type | Required | Description |
|---|---|---|---|
| Production | uta_live_… | Required | Live traffic on https://uta.online/api/public. Applications are forwarded to UTA operations and receive VSA- references. |
| Sandbox | uta_test_… | Required | Test traffic on https://sandbox.uta.online/api/public. Nothing is forwarded to operations and applications receive TEST-VSA- references. |
Environment isolation: a sandbox key used against the production base URL (or a production key against the sandbox base URL) returns HTTP 403. Request and response shapes, validation, pricing and error codes are identical in both environments, so switching to production only requires swapping the base URL and the API key.
curl -X GET "https://sandbox.uta.online/api/public/visa-applications?page=1&pageSize=10" \
-H "x-api-key: uta_test_xxxxxxxxx"{
"success": true,
"applicationId": "8f1c…",
"reference": "TEST-VSA-000001",
"status": "waiting_verification",
"total_aed": 1350
}{
"success": false,
"error": "Sandbox API keys can only be used against the sandbox base URL."
}06 · Visa API
Upload Visa Document
/visa-uploadRequires x-api-keyUploads a single applicant document (passport copy, photo, Emirates ID, Ejari, hotel booking, etc.) into UTA's private document storage. Send one request per file.
| Field | Type | Required | Description |
|---|---|---|---|
| Content-Type | header | Required | Must be multipart/form-data. |
| file | file | Required | The document image or PDF: JPEG, PNG, WebP, HEIC/HEIF or PDF. Maximum 8 MB per file. |
| document_type | string | Optional | Logical document label used as the stored filename prefix, e.g. passport-copy. |
curl -X POST https://uta.online/api/public/visa-upload \
-H "x-api-key: YOUR_KEY" \
-F "file=@passport.jpg" \
-F "document_type=passport-copy"Chain the storagePath
06 · Visa API
Submit Visa Application
/visa-applyRequires x-api-keyCreates a visa application for one or more applicants using the same payload shape the UTA website submits. Upload documents first, then reference their storage paths here.
Top-level fields
| Field | Type | Required | Description |
|---|---|---|---|
| service_slug | string | Required | Identifies the visa product being purchased, e.g. uae-tourist-visa-30-days. Determines pricing and required fields. |
| service_id | string (uuid) | Optional | Alternative to service_slug — send one or the other. |
| selected_options | object | Optional | Product options chosen for this application, e.g. { "processing": "standard" } for standard vs. express handling. |
| applicants | array<object> | Required | One entry per traveller: 1 to 25 applicants per request. Pricing is calculated per applicant. If you don't send a hotel booking (document_type containing "hotel") or return flight ticket ("flight"/"ticket") for an applicant, UTA prepares it for AED 20 each, added to the total. On /visa/quote, set ownHotelBooking / ownReturnFlight to true per applicant to leave that fee out. |
| documents | array<object> | Optional | Documents uploaded via /visa-upload and attached to this application. |
| files | array<object> | Optional | Alternative to uploading first: inline files as { applicant_index, document_type, file_name, content_type, file_base64 }. |
| billing | object | Optional | Contact and billing details for the booking — used for confirmations and invoicing. |
applicants[]
| Field | Type | Required | Description |
|---|---|---|---|
| first_name | string | Required | Given name exactly as printed in the passport. Missing names delay UTA review. |
| middle_name | string | Optional | Middle name(s) if present in the passport. |
| last_name | string | Required | Surname exactly as printed in the passport. Missing names delay UTA review. |
| passport_number | string | Required | Passport number of the applicant. |
| nationality | string | Optional | Passport nationality (country name or ISO code). |
| date_of_birth | string (YYYY-MM-DD) | Optional | Applicant date of birth. |
| gender | string | Optional | male or female, as shown in the passport. |
| passport_expiry | string (YYYY-MM-DD) | Optional | Passport expiry date; expired passports are rejected. |
| string | Optional | Applicant email for status notifications. | |
| phone | string | Optional | Applicant contact number in international format, e.g. +971501234567. |
UTA reviews every partner application
waiting_verification and checked by UTA staff before they are submitted to the immigration authority. Poll /visa-status to follow progress. In sandbox nothing is ever submitted.documents[]
| Field | Type | Required | Description |
|---|---|---|---|
| storage_path | string | Required | The storagePath returned by POST /visa-upload. |
| document_type | string | Optional | Document label, e.g. passport-copy, photo, emirates-id. |
| applicant_index | number | Optional | Zero-based index of the applicant this document belongs to. Defaults to the first applicant. |
billing
| Field | Type | Required | Description |
|---|---|---|---|
| full_name | string | Optional | Name of the paying customer or partner contact. |
| string | Optional | Email that receives the confirmation and invoice. | |
| phone | string | Optional | Contact number in international format. |
| country | string | Optional | Billing country. |
{
"service_slug": "uae-tourist-visa-30-days",
"selected_options": {
"processing": "standard"
},
"applicants": [
{
"first_name": "John",
"last_name": "Smith",
"passport_number": "P123456"
}
],
"documents": [
{
"storage_path": "guests/path/passport.jpg"
}
]
}Store the reference
06 · Visa API
Check Visa Status
/visa-statusRequires x-api-keyReturns the current processing state of one application owned by your partner account.
| Field | Type | Required | Description |
|---|---|---|---|
| reference | query string | Optional | UTA reference number, e.g. VSA-100001. Provide this or applicationId. |
| applicationId | query string (uuid) | Optional | Application UUID returned by /visa-apply. |
curl "https://uta.online/api/public/visa-status?reference=VSA-100001" \
-H "x-api-key: YOUR_KEY"06 · Visa API
Download eVisa
/visa-download-evisaRequires x-api-keyDownloads the issued eVisa for one of your applications. Use the same reference or applicationId as /visa-status, and call it once /visa-status returns evisaAvailable: true. By default the file (PDF) is returned; add format=json to get it base64-encoded. Sandbox keys receive a sample TEST eVisa for TEST- references.
| Field | Type | Required | Description |
|---|---|---|---|
| reference | query string | Optional | UTA reference, e.g. VSA-100001. Provide this or applicationId. |
| applicationId | query string (uuid) | Optional | Application UUID returned by /visa-apply. |
| format | query string | Optional | Optional. `json` returns base64 content instead of the file. |
curl -o evisa.pdf "https://uta.online/api/public/visa-download-evisa?reference=VSA-100001" \
-H "x-api-key: YOUR_KEY"06 · Visa API
List Visa Applications
/visa-applicationsRequires x-api-keyReturns your partner account's applications, newest first. Only applications created with your API key are visible.
| Field | Type | Required | Description |
|---|---|---|---|
| page | query number | Optional | 1-based page number. Defaults to 1. |
| pageSize | query number | Optional | Records per page (default 20). `page_size` is also accepted. |
curl "https://uta.online/api/public/visa-applications?page=1&pageSize=20" \
-H "x-api-key: YOUR_KEY"06 · Visa API
Visa Fees & Quote
/visa/pricingRequires x-api-keyPublished fee catalogue for every active visa service: base government fee, UTA service charge, VAT and the refundable security deposit per applicant.
curl "https://uta.online/api/public/visa/pricing" -H "x-api-key: YOUR_KEY"/visa/quoteRequires x-api-keyAuthoritative quote for a specific applicant mix and option selection. No application is created. The returned grandTotalAED is what /visa-apply will charge (visa revenue + refundable deposit).
| Field | Type | Required | Description |
|---|---|---|---|
| serviceId / serviceSlug | string | Required | Provide one of the two. |
| applicants[] | array | Required | One entry per applicant: `{ "personType": "adult" | "child" }`. 1–20. |
| selectedOptions | object | Optional | Option selection, e.g. `{ "duration": 30, "entry": "single" }`. |
curl -X POST "https://uta.online/api/public/visa/quote" \
-H "x-api-key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"serviceSlug": "uae-tourist-visa",
"applicants": [{ "personType": "adult" }, { "personType": "child" }],
"selectedOptions": { "duration": 30, "entry": "single" }
}'Deposit is not revenue
06 · Visa API
Documents & Scanning
Helper endpoints that make the application form easier to build. They return the standard envelope { success, data, errors, meta } and need the visa service.
/visa/documents?nationality=INRequires x-api-keyLists the documents UTA requires for one nationality (passport copy, photo, etc.). country is accepted as an alias for nationality. meta.count is the number of documents.
/visa/passport-scanRequires x-api-key| Field | Type | Required | Description |
|---|---|---|---|
| image_base64 | string | Required | Passport photo page as base64. |
| mime_type | string | Required | e.g. image/jpeg, image/png or application/pdf. |
Returns the values read from the passport (names, passport number, dates, nationality) so you can pre-fill the applicant.
/visa/address-scanRequires x-api-key| Field | Type | Required | Description |
|---|---|---|---|
| file_base64 | string | Required | Address document (e.g. Ejari, utility bill) as base64. |
| mime_type | string | Required | File type of the document. |
| doc_type | string | Optional | Optional document type hint. |
| nationality | string | Optional | Optional applicant nationality. |
curl "https://uta.online/api/public/visa/documents?nationality=IN" \
-H "x-api-key: YOUR_KEY"07 · Flights API
Search Flights
/flights/searchRequires x-api-keyReturns live priced offers. One-way, return and multi-city are all expressed through the `legs` array, so the payload shape never changes between trip types.
| Field | Type | Required | Description |
|---|---|---|---|
| tripType | string | Optional | `oneway` (default), `round` or `multi`. |
| cabin | string | Optional | `economy` (default), `premium`, `business` or `first`. |
| legs[] | array | Required | 1–6 legs of `{ from, to, date }`. |
| legs[].from / to | string | Required | 3-letter IATA airport code. |
| legs[].date | string | Required | Departure date, `yyyy-MM-dd`. |
| passengers | object | Optional | `{ adults (1–9), children, infants }`. Defaults to 1 adult. |
| currency | string | Optional | 3-letter currency code. Defaults to AED. |
curl -X POST "https://uta.online/api/public/flights/search" \
-H "x-api-key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"tripType": "round",
"cabin": "economy",
"legs": [
{ "from": "DXB", "to": "LHR", "date": "2026-09-01" },
{ "from": "LHR", "to": "DXB", "date": "2026-09-08" }
],
"passengers": { "adults": 2, "children": 0, "infants": 0 }
}'07 · Flights API
Retrieve Offer & Bundles
/flights/{offerId}Requires x-api-keyReturns the full fare breakdown, baggage rules and any purchasable bundles for one offer. Pass `searchResponseId` from the search response so the offer can be resolved.
| Field | Type | Required | Description |
|---|---|---|---|
| offerId | path string | Required | Offer identifier from search. |
| searchResponseId | query string | Optional | Search context identifier. |
curl "https://uta.online/api/public/flights/ofr_01H...?searchResponseId=srch_01H..." \
-H "x-api-key: YOUR_KEY"07 · Flights API
Reprice / Confirm Fare
/flights/repriceRequires x-api-keyAlways reprice immediately before booking. The response tells you whether the fare is still valid and whether the price moved since search.
| Field | Type | Required | Description |
|---|---|---|---|
| offerId | string | Required | Offer to confirm. |
| searchResponseId | string | Optional | Search context identifier. |
curl -X POST "https://uta.online/api/public/flights/reprice" \
-H "x-api-key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "offerId": "ofr_01H...", "searchResponseId": "srch_01H..." }'07 · Flights API
Book or Hold Flights
/flights/bookRequires x-api-keyCreates the booking. Send `hold: true` to place the fare on hold instead of issuing — the booking then returns with status `on_hold` and must be confirmed before the deadline.
| Field | Type | Required | Description |
|---|---|---|---|
| offerId | string | Required | Repriced offer identifier. |
| selectedBundles[] | array | Optional | `{ journeyKey, bundleCode }` per journey. |
| hold | boolean | Optional | `true` holds the fare instead of issuing. Defaults to `false`. |
| passengers[] | array | Required | 1–9 passengers (see fields below). |
| passengers[].type | string | Optional | `adult` (default), `child` or `infant`. |
| passengers[].firstName / lastName | string | Required | As printed in the passport. |
| passengers[].dateOfBirth | string | Required | `yyyy-MM-dd`. |
| passengers[].gender | string | Optional | `male` (default), `female` or `other`. |
| passengers[].nationality | string | Required | 2–3 letter country code. |
| passengers[].passportNumber | string | Required | 3–20 characters. |
| passengers[].passportExpiry | string | Required | `yyyy-MM-dd`. |
| contact | object | Required | `{ email, phone }` for the booking. |
| passengers[].title | string | Optional | Optional title, e.g. Mr, Mrs, Ms. |
| passengers[].email / phone | string | Optional | Optional per-passenger contact (phone at least 5 characters). |
| bundleId | string | Optional | Optional fare bundle chosen from the offer. |
| ancillaries | object | Optional | Optional extras per passenger index: { "0": { baggage[], meals[], seats[] } }. |
| partnerReference | string | Optional | Your own reference, echoed back on every read. |
curl -X POST "https://uta.online/api/public/flights/book" \
-H "x-api-key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"offerId": "ofr_01H...",
"searchResponseId": "srch_01H...",
"selectedBundles": [{ "journeyKey": "J1", "bundleCode": "FLEX" }],
"hold": false,
"passengers": [
{
"type": "adult",
"title": "MR",
"firstName": "JOHN",
"lastName": "SMITH",
"dateOfBirth": "1990-04-11",
"gender": "male",
"nationality": "GB",
"passportNumber": "P1234567",
"passportExpiry": "2031-06-30"
}
],
"contact": { "email": "john@example.com", "phone": "+971500000000" },
"partnerReference": "AGENCY-8891"
}'07 · Flights API
Retrieve & Cancel Flight Booking
/flights/bookings/{bookingId}Requires x-api-key/flights/cancelRequires x-api-keyRetrieve returns the current status, tickets and price. Cancel voids or refunds the booking according to the fare rules; a held booking is simply released.
| Field | Type | Required | Description |
|---|---|---|---|
| bookingId | path / body string | Required | Booking identifier returned at book time. |
| offerId | body string | Optional | Optional offer ID the booking was made from. |
curl "https://uta.online/api/public/flights/bookings/ORD-889201" -H "x-api-key: YOUR_KEY"07 · Flights API
Flight Pricing (price only)
/flights/pricingRequires x-api-keyFare-confirms an offer returned by /flights/search and returns the money breakdown only. priceChanged: true means the supplier repriced the offer.
| Field | Type | Required | Description |
|---|---|---|---|
| offerId | string | Required | Offer id from /flights/search. |
| searchResponseId | string | Optional | Search session id — recommended for accurate repricing. |
curl -X POST "https://uta.online/api/public/flights/pricing" \
-H "x-api-key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "offerId": "OFR-88213", "searchResponseId": "SRCH-1029" }'Always re-price before booking
08 · Hotels API
Search Hotels
/hotels/searchRequires x-api-keyReturns available properties with a lead nightly price. Results are paginated; stays are capped at 30 nights and check-out must be after check-in.
| Field | Type | Required | Description |
|---|---|---|---|
| destinationId | string | Required | City or destination code, e.g. `DXB`. |
| checkIn / checkOut | string | Required | `yyyy-MM-dd`. 1–30 nights. |
| rooms | number | Optional | Rooms required, 1–8. Defaults to 1. |
| adults | number | Optional | Adults in total, 1–30. Defaults to 2. |
| children | number | Optional | Children in total, 0–20. Defaults to 0. |
| childAges[] | array | Optional | Age (0–17) of each child. Required when `children` > 0 for accurate pricing. |
| nationality | string | Optional | Guest nationality code — affects rates in some markets. |
| page / perPage | number | Optional | Pagination. Defaults to page 1, 25 per page (max 100). |
curl -X POST "https://uta.online/api/public/hotels/search" \
-H "x-api-key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"destinationId": "DXB",
"checkIn": "2026-09-10",
"checkOut": "2026-09-13",
"rooms": 1,
"adults": 2,
"children": 1,
"childAges": [7],
"nationality": "AE",
"page": 1,
"perPage": 25
}'08 · Hotels API
Retrieve Hotel Details
/hotels/{hotelId}Requires x-api-keyStatic content for one property: description, address, facilities and gallery. Only fields the supplier actually provides are returned — missing values come back as `null`.
| Field | Type | Required | Description |
|---|---|---|---|
| hotelId | path string | Required | Property identifier from search. |
curl "https://uta.online/api/public/hotels/htl_10293" -H "x-api-key: YOUR_KEY"08 · Hotels API
Check Room Availability
/hotels/availabilityRequires x-api-keyReturns bookable room rates for one property and stay. Each rate carries a `rateKey` — the only value accepted by the booking endpoint. Rate keys are short-lived, so book promptly.
| Field | Type | Required | Description |
|---|---|---|---|
| hotelId | string | Required | Property identifier. |
| destinationId | string | Required | Same destination used at search. |
| checkIn / checkOut | string | Required | `yyyy-MM-dd`. |
| rooms / adults / children / childAges | mixed | Optional | Occupancy, same rules as search. |
curl -X POST "https://uta.online/api/public/hotels/availability" \
-H "x-api-key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"hotelId": "htl_10293",
"destinationId": "DXB",
"checkIn": "2026-09-10",
"checkOut": "2026-09-13",
"rooms": 1,
"adults": 2
}'08 · Hotels API
Book a Room
/hotels/bookRequires x-api-keyConfirms the reservation against the selected `rateKey`.
| Field | Type | Required | Description |
|---|---|---|---|
| rateKey | string | Required | Rate key from the availability response. |
| holder | object | Required | `{ firstName, lastName }` of the booking holder. |
| guests[] | array | Required | 1–40 guests. |
| guests[].roomNumber | number | Optional | Room the guest occupies, 1–8. Defaults to 1. |
| guests[].type | string | Optional | `adult` (default) or `child`. |
| guests[].firstName / lastName | string | Required | Guest name. |
| guests[].age | number | Optional | Age of the guest (0–120). Send it for every child. |
| partnerReference | string | Optional | Your own reference. |
| remarks | string | Optional | Free-text request passed to the property. |
curl -X POST "https://uta.online/api/public/hotels/book" \
-H "x-api-key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"rateKey": "rk_9f2c...",
"holder": { "firstName": "JOHN", "lastName": "SMITH" },
"guests": [
{ "roomNumber": 1, "type": "adult", "firstName": "JOHN", "lastName": "SMITH" },
{ "roomNumber": 1, "type": "child", "firstName": "EMMA", "lastName": "SMITH", "age": 7 }
],
"partnerReference": "AGENCY-4410",
"remarks": "High floor if possible"
}'08 · Hotels API
Retrieve & Cancel Hotel Booking
/hotels/bookings/{reference}Requires x-api-key/hotels/cancelRequires x-api-keyCancellation follows the rate's policy — a rate past its `cancellationDeadline` may incur a charge, which is reflected in the returned price.
| Field | Type | Required | Description |
|---|---|---|---|
| reference | body string | Required | Hotel booking reference. |
| reason | body string | Optional | Optional cancellation reason. |
curl "https://uta.online/api/public/hotels/bookings/HTL-77120" -H "x-api-key: YOUR_KEY"08 · Hotels API
Hotel Pricing (price only)
/hotels/pricingRequires x-api-keyReturns every bookable rate for one property with the per-night price, the number of nights, and the full-stay total for the requested room count. Same body as/hotels/availability.
| Field | Type | Required | Description |
|---|---|---|---|
| hotelId | string | Required | Hotel id from /hotels/search. |
| destinationId | string | Required | Destination code used in the original search. |
| checkIn / checkOut | string | Required | `yyyy-MM-dd`. 1–30 nights. |
| rooms / adults / children | number | Optional | Occupancy. Defaults 1 room, 2 adults, 0 children. |
| childAges[] | array | Optional | Age of each child — required for accurate child pricing. |
| nationality | string | Optional | Guest nationality code — affects rates in some markets. |
| currency | string | Optional | 3-letter code. Defaults to AED. |
curl -X POST "https://uta.online/api/public/hotels/pricing" \
-H "x-api-key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"hotelId": "htl_10293",
"destinationId": "DXB",
"checkIn": "2026-09-10",
"checkOut": "2026-09-13",
"rooms": 1,
"adults": 2
}'Rate keys are session-scoped
09 · Attractions API
Search Activities
/attractions/searchRequires x-api-keyReturns bookable activities and tickets for a city. Keep the `countryId` and `cityId` from the response — the detail endpoint needs both.
| Field | Type | Required | Description |
|---|---|---|---|
| countryId | number | Required | Destination country identifier. |
| cityId | number | Required | Destination city identifier. |
| query | string | Optional | Free-text filter on activity name, up to 120 characters. |
| page / perPage | number | Optional | Pagination. Defaults to page 1, 25 per page (max 100). |
curl -X POST "https://uta.online/api/public/attractions/search" \
-H "x-api-key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "countryId": 1, "cityId": 2, "query": "burj", "page": 1, "perPage": 25 }'09 · Attractions API
Retrieve Activity Details
/attractions/{activityId}Requires x-api-keyFull activity content plus its ticket options. `countryId` and `cityId` are required query parameters because activity ids are scoped to a destination.
| Field | Type | Required | Description |
|---|---|---|---|
| activityId | path number | Required | Activity identifier from search. |
| countryId | query number | Required | Destination country identifier. |
| cityId | query number | Required | Destination city identifier. |
| travelDate | query string | Optional | `yyyy-MM-dd` — returns pricing for that date. |
curl "https://uta.online/api/public/attractions/4021?countryId=1&cityId=2&travelDate=2026-09-10" \
-H "x-api-key: YOUR_KEY"09 · Attractions API
Check Availability & Pricing
/attractions/availabilityRequires x-api-keyConfirms live pricing and remaining capacity for a travel date. For slot-based activities the response returns the `timeSlotId` values accepted at booking.
| Field | Type | Required | Description |
|---|---|---|---|
| activityId | number | Required | Activity identifier. |
| optionId | number | Optional | Restrict to one ticket option. |
| contractId | number | Optional | Supplier contract id. Defaults to 0. |
| travelDate | string | Required | `yyyy-MM-dd`. |
| adults / children / infants | number | Optional | Pax counts: adults 1–30, children and infants 0–30. Defaults to 1 adult. |
| transferId | number | Optional | Transfer option, when the activity offers pickup. |
curl -X POST "https://uta.online/api/public/attractions/availability" \
-H "x-api-key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "activityId": 4021, "travelDate": "2026-09-10", "adults": 2, "children": 1 }'09 · Attractions API
Book an Activity
/attractions/bookRequires x-api-keyConfirms the booking and returns the supplier reference. Slot-based activities require `timeSlotId`; transfer-inclusive options require `transferId` and a `pickupLocation`.
| Field | Type | Required | Description |
|---|---|---|---|
| activityId | number | Required | Activity identifier. |
| optionId | number | Optional | Ticket option to book. |
| travelDate | string | Required | `yyyy-MM-dd`. |
| adults / children / infants | number | Optional | Pax counts: adults 1–30, children and infants 0–30. Defaults to 1 adult. |
| timeSlotId | number | Optional | Required when `requiresTimeSlot` is `true`. |
| transferId / startTime / pickupLocation | mixed | Optional | Transfer details when applicable. |
| leadGuest | object | Required | `{ firstName, lastName, email, phone, nationality? }`. |
| partnerReference | string | Optional | Your own reference. |
| specialRequest | string | Optional | Free-text note passed to the supplier. |
curl -X POST "https://uta.online/api/public/attractions/book" \
-H "x-api-key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"activityId": 4021,
"optionId": 8801,
"travelDate": "2026-09-10",
"adults": 2,
"children": 1,
"timeSlotId": 1,
"leadGuest": {
"firstName": "JOHN",
"lastName": "SMITH",
"email": "john@example.com",
"phone": "+971500000000",
"nationality": "GB"
},
"partnerReference": "AGENCY-2210"
}'09 · Attractions API
Retrieve & Cancel Activity Booking
/attractions/bookings/{bookingId}Requires x-api-key/attractions/bookings/{bookingId}/cancelRequires x-api-keyRetrieve returns the ticket, validity and download URL once issued. Cancellation is only possible while the activity's cancellation policy still allows it.
| Field | Type | Required | Description |
|---|---|---|---|
| bookingId | path string | Required | Booking reference returned at book time. |
| supplierBookingId / serviceUniqueId / uniqueNo | query string | Optional | Supplier identifiers from the booking response — pass them through when available. |
| supplierBookingId (cancel body) | body string | Required | Supplier booking ID returned at book time (or send bookingId in the body). |
| reason | body string | Optional | Cancellation reason. Defaults to `Partner cancellation`. |
curl "https://uta.online/api/public/attractions/bookings/RY-100482?supplierBookingId=B-1932" \
-H "x-api-key: YOUR_KEY"09 · Attractions API
Attraction Pricing (price only)
/attractions/pricingRequires x-api-keyReturns adult / child / infant unit prices for every option (and transfer variant) of an activity, together with the computed totals for the requested pax mix.
| Field | Type | Required | Description |
|---|---|---|---|
| activityId | number | Required | Activity id from /attractions/search. |
| travelDate | string | Required | `yyyy-MM-dd` visit date. |
| contractId | number | Optional | Contract id from search. Defaults to 0. |
| optionId | number | Optional | Restrict pricing to one option. |
| adults / children / infants | number | Optional | Pax mix. Defaults 1 / 0 / 0. |
| transferId | number | Optional | Transfer variant (0 = ticket only). |
curl -X POST "https://uta.online/api/public/attractions/pricing" \
-H "x-api-key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"activityId": 33,
"contractId": 300,
"travelDate": "2026-09-12",
"adults": 2,
"children": 1
}'10
Error Handling
Errors always return success: false. Core Visa endpoints return a human-readable error message with optional details; all other endpoints return an errors[] array of { code, message, field }.
| Status | Meaning | What to do |
|---|---|---|
| 400 | Invalid request — malformed JSON or wrong Content-Type | Fix the request format and retry. |
| 401 | Authentication failed — missing, invalid or revoked key | Check the x-api-key header; request a new key if revoked. |
| 403 | Service not assigned to your partner account | Ask UTA to enable the service. |
| 404 | Resource not found — unknown reference or applicationId | Verify the identifier belongs to your account. |
| 409 | Conflict — e.g. the booking is already cancelled or the fare changed | Re-read the resource and retry with fresh data. |
| 422 | Validation error — required fields missing or invalid | Read details / errors and correct the payload. |
| 429 | Too many requests | Slow down and retry with backoff. |
| 500 | Internal server error | Retry with backoff; contact UTA support if it persists. |
| 502 / 503 / 504 | Supplier unavailable — the airline, hotel or activity provider did not respond | Retry shortly; nothing was booked. |
{
"success": false,
"error": "Invalid JSON body."
}11
Rate Limits
- Do not send unnecessary repeated requests; batch work where you can.
- Cache responses on your side — poll `/visa-status` on a sensible interval (for example every 15–30 minutes) rather than continuously.
- Apply exponential backoff when you receive `429`, `500` or `502–504` responses.
- Contact UTA before launching high-volume or bulk integrations.
12
Security Guidelines
- Never expose API keys publicly — no frontend code, no public repositories.
- Use backend-to-backend communication for every UTA API call.
- Rotate your key immediately if you suspect it was compromised.
- Do not store passport documents outside approved storage — upload them to UTA and keep only the returned `storagePath`.
- Do not log sensitive customer information, API keys or document contents.
Compromised key?
13
API Response Standards
All endpoints follow one predictable envelope.
| Field | Type | Required | Description |
|---|---|---|---|
| success | boolean | Required | true for 2xx responses, false for every error. |
| error | string | null | Optional | Human-readable error message. Present only on failures. |
| details | object | null | Optional | Field-level validation or diagnostic detail when available. |
| applicationId | uuid | Optional | Application identifier returned by /visa-apply and /visa-status. |
| reference | string | Optional | Human-friendly UTA reference, e.g. VSA-100001. |
| status | string | Optional | GDRFAD status on /visa-status and /visa-applications: In Process, Approved or Rejected. |
14
Integration Checklist
- ☐Receive your sandbox key (uta_test_) and store it in your secret manager
- ☐Test authentication against the sandbox base URL with a simple GET
- ☐Visa: upload documents, submit an application, poll GET /visa-status
- ☐Flights: search, reprice the chosen offer, then book or hold
- ☐Hotels: search, check room availability, then book with a fresh rateKey
- ☐Attractions: search, check availability for the travel date, then book
- ☐Quote customers with the /pricing endpoints and re-price before payment
- ☐Store every returned reference / bookingId against your own order
- ☐Handle 400 / 401 / 403 / 404 / 409 / 422 / 429 / 5xx responses gracefully
- ☐Swap to the production base URL and your uta_live_ key to go live
15
Code Examples
End-to-end visa flow: upload a document, submit the application, then poll for status. Flights, Hotels and Attractions use the same headers, envelope and error handling — only the paths and bodies differ (see each service section above).
# 1. Upload the passport copy
curl -X POST https://uta.online/api/public/visa-upload \
-H "x-api-key: $UTA_API_KEY" \
-F "file=@passport.jpg" \
-F "document_type=passport-copy"
# 2. Submit the application (use storagePath from step 1)
curl -X POST https://uta.online/api/public/visa-apply \
-H "x-api-key: $UTA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"service_slug": "uae-tourist-visa-30-days",
"selected_options": { "processing": "standard" },
"applicants": [
{ "first_name": "John", "last_name": "Smith", "passport_number": "P123456" }
],
"documents": [ { "storage_path": "guests/path/passport.jpg" } ]
}'
# 3. Poll the status
curl "https://uta.online/api/public/visa-status?reference=VSA-100001" \
-H "x-api-key: $UTA_API_KEY"