Developer Portal · v1

UTA Partner API Documentation

Secure APIs for travel partners to integrate UTA services directly into their own platforms. Documentation is organised by service — Visa, Flights, Hotels and Attractions are all live, each with its own pricing endpoint.

Visa — LiveFlights — LiveHotels — LiveAttractions — Live

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

request flow
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.

headers
x-api-key: YOUR_PARTNER_API_KEY
cURL
curl https://uta.online/api/public/visa-applications \
  -H "x-api-key: uta_live_xxxxxxxxx" \
  -H "Content-Type: application/json"

Keep keys server-side

API keys are private credentials. Never embed a key in frontend code, mobile apps, public repositories or browser requests. Call the UTA API only from your backend.

03

Base URLs

production
https://uta.online/api/public/
sandbox
https://sandbox.uta.online/api/public/
POSThttps://uta.online/api/public/visa-uploadRequires x-api-key
POSThttps://uta.online/api/public/visa-applyRequires x-api-key
GEThttps://uta.online/api/public/visa-statusRequires x-api-key
GEThttps://uta.online/api/public/visa-applicationsRequires x-api-key
POSThttps://uta.online/api/public/flights/searchRequires x-api-key
GEThttps://uta.online/api/public/flights/{offerId}Requires x-api-key
POSThttps://uta.online/api/public/flights/repriceRequires x-api-key
POSThttps://uta.online/api/public/flights/bookRequires x-api-key
GEThttps://uta.online/api/public/flights/bookings/{bookingId}Requires x-api-key
POSThttps://uta.online/api/public/flights/cancelRequires x-api-key
POSThttps://uta.online/api/public/hotels/searchRequires x-api-key
GEThttps://uta.online/api/public/hotels/{hotelId}Requires x-api-key
POSThttps://uta.online/api/public/hotels/availabilityRequires x-api-key
POSThttps://uta.online/api/public/hotels/bookRequires x-api-key
GEThttps://uta.online/api/public/hotels/bookings/{reference}Requires x-api-key
POSThttps://uta.online/api/public/hotels/cancelRequires x-api-key
POSThttps://uta.online/api/public/attractions/searchRequires x-api-key
GEThttps://uta.online/api/public/attractions/{activityId}Requires x-api-key
POSThttps://uta.online/api/public/attractions/availabilityRequires x-api-key
POSThttps://uta.online/api/public/attractions/bookRequires x-api-key
GEThttps://uta.online/api/public/attractions/bookings/{bookingId}Requires x-api-key
POSThttps://uta.online/api/public/attractions/bookings/{bookingId}/cancelRequires x-api-key
POSThttps://uta.online/api/public/flights/pricingRequires x-api-key
POSThttps://uta.online/api/public/hotels/pricingRequires x-api-key
POSThttps://uta.online/api/public/attractions/pricingRequires x-api-key
GEThttps://uta.online/api/public/visa/pricingRequires x-api-key
POSThttps://uta.online/api/public/visa/quoteRequires x-api-key
GEThttps://uta.online/api/public/visa/documentsRequires x-api-key
POSThttps://uta.online/api/public/visa/passport-scanRequires x-api-key
POSThttps://uta.online/api/public/visa/address-scanRequires x-api-key

All 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.

FieldTypeRequiredDescription
x-api-keyheader (string)RequiredYour partner API key: uta_live_xxxxxxxxx (production) or uta_test_xxxxxxxxx (sandbox).

A missing, malformed, revoked or deactivated key returns HTTP 401.

401 response
{
  "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.

FieldTypeRequiredDescription
Productionuta_live_…RequiredLive traffic on https://uta.online/api/public. Applications are forwarded to UTA operations and receive VSA- references.
Sandboxuta_test_…RequiredTest 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.

sandbox request
curl -X GET "https://sandbox.uta.online/api/public/visa-applications?page=1&pageSize=10" \
  -H "x-api-key: uta_test_xxxxxxxxx"
sandbox apply response
{
  "success": true,
  "applicationId": "8f1c…",
  "reference": "TEST-VSA-000001",
  "status": "waiting_verification",
  "total_aed": 1350
}
403 wrong environment
{
  "success": false,
  "error": "Sandbox API keys can only be used against the sandbox base URL."
}

05

Service Authorization

Authentication proves who you are; authorization decides what you may call. Each partner record carries a list of assigned services and endpoints check it on every request.

partner services
[
  "visa",
  "flights",
  "hotels",
  "attractions"
]

If an authenticated partner calls an endpoint for a service that is not assigned, the API returns HTTP 403 and no business logic runs. Pricing endpoints are authorized against the same service — /hotels/pricing requires hotels, /visa/quote requires visa, and so on.

403 response
{
  "success": false,
  "error": "Partner is not authorized for the \"visa\" service."
}

Need another service?

Contact your UTA account manager to have Visa, Flights, Hotels or Attractions added to your partner profile.

06 · Visa API

Upload Visa Document

POST/visa-uploadRequires x-api-key

Uploads a single applicant document (passport copy, photo, Emirates ID, Ejari, hotel booking, etc.) into UTA's private document storage. Send one request per file.

FieldTypeRequiredDescription
Content-TypeheaderRequiredMust be multipart/form-data.
filefileRequiredThe document image or PDF: JPEG, PNG, WebP, HEIC/HEIF or PDF. Maximum 8 MB per file.
document_typestringOptionalLogical document label used as the stored filename prefix, e.g. passport-copy.
cURL
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

Keep the returned `storagePath` — you pass it in the `documents[]` array when you submit the visa application. Files live in private storage and are never publicly readable.

06 · Visa API

Submit Visa Application

POST/visa-applyRequires x-api-key

Creates 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

FieldTypeRequiredDescription
service_slugstringRequiredIdentifies the visa product being purchased, e.g. uae-tourist-visa-30-days. Determines pricing and required fields.
service_idstring (uuid)OptionalAlternative to service_slug — send one or the other.
selected_optionsobjectOptionalProduct options chosen for this application, e.g. { "processing": "standard" } for standard vs. express handling.
applicantsarray<object>RequiredOne 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.
documentsarray<object>OptionalDocuments uploaded via /visa-upload and attached to this application.
filesarray<object>OptionalAlternative to uploading first: inline files as { applicant_index, document_type, file_name, content_type, file_base64 }.
billingobjectOptionalContact and billing details for the booking — used for confirmations and invoicing.

applicants[]

FieldTypeRequiredDescription
first_namestringRequiredGiven name exactly as printed in the passport. Missing names delay UTA review.
middle_namestringOptionalMiddle name(s) if present in the passport.
last_namestringRequiredSurname exactly as printed in the passport. Missing names delay UTA review.
passport_numberstringRequiredPassport number of the applicant.
nationalitystringOptionalPassport nationality (country name or ISO code).
date_of_birthstring (YYYY-MM-DD)OptionalApplicant date of birth.
genderstringOptionalmale or female, as shown in the passport.
passport_expirystring (YYYY-MM-DD)OptionalPassport expiry date; expired passports are rejected.
emailstringOptionalApplicant email for status notifications.
phonestringOptionalApplicant contact number in international format, e.g. +971501234567.

UTA reviews every partner application

Applications sent through the API are created with status 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[]

FieldTypeRequiredDescription
storage_pathstringRequiredThe storagePath returned by POST /visa-upload.
document_typestringOptionalDocument label, e.g. passport-copy, photo, emirates-id.
applicant_indexnumberOptionalZero-based index of the applicant this document belongs to. Defaults to the first applicant.

billing

FieldTypeRequiredDescription
full_namestringOptionalName of the paying customer or partner contact.
emailstringOptionalEmail that receives the confirmation and invoice.
phonestringOptionalContact number in international format.
countrystringOptionalBilling country.
Request
{
  "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

Persist both `applicationId` and `reference` (e.g. `VSA-100001`) against your own order. They are the only identifiers accepted by the status endpoint.

06 · Visa API

Check Visa Status

GET/visa-statusRequires x-api-key

Returns the current processing state of one application owned by your partner account.

FieldTypeRequiredDescription
referencequery stringOptionalUTA reference number, e.g. VSA-100001. Provide this or applicationId.
applicationIdquery string (uuid)OptionalApplication UUID returned by /visa-apply.
Request
curl "https://uta.online/api/public/visa-status?reference=VSA-100001" \
  -H "x-api-key: YOUR_KEY"

06 · Visa API

Download eVisa

GET/visa-download-evisaRequires x-api-key

Downloads 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.

FieldTypeRequiredDescription
referencequery stringOptionalUTA reference, e.g. VSA-100001. Provide this or applicationId.
applicationIdquery string (uuid)OptionalApplication UUID returned by /visa-apply.
formatquery stringOptionalOptional. `json` returns base64 content instead of the file.
Request
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

GET/visa-applicationsRequires x-api-key

Returns your partner account's applications, newest first. Only applications created with your API key are visible.

FieldTypeRequiredDescription
pagequery numberOptional1-based page number. Defaults to 1.
pageSizequery numberOptionalRecords per page (default 20). `page_size` is also accepted.
Request
curl "https://uta.online/api/public/visa-applications?page=1&pageSize=20" \
  -H "x-api-key: YOUR_KEY"

06 · Visa API

Visa Fees & Quote

GET/visa/pricingRequires x-api-key

Published fee catalogue for every active visa service: base government fee, UTA service charge, VAT and the refundable security deposit per applicant.

Request
curl "https://uta.online/api/public/visa/pricing" -H "x-api-key: YOUR_KEY"
POST/visa/quoteRequires x-api-key

Authoritative 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).

FieldTypeRequiredDescription
serviceId / serviceSlugstringRequiredProvide one of the two.
applicants[]arrayRequiredOne entry per applicant: `{ "personType": "adult" | "child" }`. 1–20.
selectedOptionsobjectOptionalOption selection, e.g. `{ "duration": 30, "entry": "single" }`.
Request
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

`totalAED` is the visa fee. `depositTotalAED` is a refundable security deposit collected separately and returned after the applicant exits the UAE. Never merge the two in your customer invoice.

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.

GET/visa/documents?nationality=INRequires x-api-key

Lists 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.

POST/visa/passport-scanRequires x-api-key
FieldTypeRequiredDescription
image_base64stringRequiredPassport photo page as base64.
mime_typestringRequirede.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.

POST/visa/address-scanRequires x-api-key
FieldTypeRequiredDescription
file_base64stringRequiredAddress document (e.g. Ejari, utility bill) as base64.
mime_typestringRequiredFile type of the document.
doc_typestringOptionalOptional document type hint.
nationalitystringOptionalOptional applicant nationality.
cURL
curl "https://uta.online/api/public/visa/documents?nationality=IN" \
  -H "x-api-key: YOUR_KEY"

07 · Flights API

Retrieve Offer & Bundles

GET/flights/{offerId}Requires x-api-key

Returns 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.

FieldTypeRequiredDescription
offerIdpath stringRequiredOffer identifier from search.
searchResponseIdquery stringOptionalSearch context identifier.
Request
curl "https://uta.online/api/public/flights/ofr_01H...?searchResponseId=srch_01H..." \
  -H "x-api-key: YOUR_KEY"

07 · Flights API

Reprice / Confirm Fare

POST/flights/repriceRequires x-api-key

Always reprice immediately before booking. The response tells you whether the fare is still valid and whether the price moved since search.

FieldTypeRequiredDescription
offerIdstringRequiredOffer to confirm.
searchResponseIdstringOptionalSearch context identifier.
Request
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

POST/flights/bookRequires x-api-key

Creates 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.

FieldTypeRequiredDescription
offerIdstringRequiredRepriced offer identifier.
selectedBundles[]arrayOptional`{ journeyKey, bundleCode }` per journey.
holdbooleanOptional`true` holds the fare instead of issuing. Defaults to `false`.
passengers[]arrayRequired1–9 passengers (see fields below).
passengers[].typestringOptional`adult` (default), `child` or `infant`.
passengers[].firstName / lastNamestringRequiredAs printed in the passport.
passengers[].dateOfBirthstringRequired`yyyy-MM-dd`.
passengers[].genderstringOptional`male` (default), `female` or `other`.
passengers[].nationalitystringRequired2–3 letter country code.
passengers[].passportNumberstringRequired3–20 characters.
passengers[].passportExpirystringRequired`yyyy-MM-dd`.
contactobjectRequired`{ email, phone }` for the booking.
passengers[].titlestringOptionalOptional title, e.g. Mr, Mrs, Ms.
passengers[].email / phonestringOptionalOptional per-passenger contact (phone at least 5 characters).
bundleIdstringOptionalOptional fare bundle chosen from the offer.
ancillariesobjectOptionalOptional extras per passenger index: { "0": { baggage[], meals[], seats[] } }.
partnerReferencestringOptionalYour own reference, echoed back on every read.
Request
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

GET/flights/bookings/{bookingId}Requires x-api-key
POST/flights/cancelRequires x-api-key

Retrieve returns the current status, tickets and price. Cancel voids or refunds the booking according to the fare rules; a held booking is simply released.

FieldTypeRequiredDescription
bookingIdpath / body stringRequiredBooking identifier returned at book time.
offerIdbody stringOptionalOptional offer ID the booking was made from.
Retrieve
curl "https://uta.online/api/public/flights/bookings/ORD-889201" -H "x-api-key: YOUR_KEY"

07 · Flights API

Flight Pricing (price only)

POST/flights/pricingRequires x-api-key

Fare-confirms an offer returned by /flights/search and returns the money breakdown only. priceChanged: true means the supplier repriced the offer.

FieldTypeRequiredDescription
offerIdstringRequiredOffer id from /flights/search.
searchResponseIdstringOptionalSearch session id — recommended for accurate repricing.
Request
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

Supplier rates change. Call this endpoint (or `/flights/reprice`) immediately before you take payment, and compare the returned total with the amount you quoted.

08 · Hotels API

Retrieve Hotel Details

GET/hotels/{hotelId}Requires x-api-key

Static content for one property: description, address, facilities and gallery. Only fields the supplier actually provides are returned — missing values come back as `null`.

FieldTypeRequiredDescription
hotelIdpath stringRequiredProperty identifier from search.
Request
curl "https://uta.online/api/public/hotels/htl_10293" -H "x-api-key: YOUR_KEY"

08 · Hotels API

Check Room Availability

POST/hotels/availabilityRequires x-api-key

Returns 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.

FieldTypeRequiredDescription
hotelIdstringRequiredProperty identifier.
destinationIdstringRequiredSame destination used at search.
checkIn / checkOutstringRequired`yyyy-MM-dd`.
rooms / adults / children / childAgesmixedOptionalOccupancy, same rules as search.
Request
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

POST/hotels/bookRequires x-api-key

Confirms the reservation against the selected `rateKey`.

FieldTypeRequiredDescription
rateKeystringRequiredRate key from the availability response.
holderobjectRequired`{ firstName, lastName }` of the booking holder.
guests[]arrayRequired1–40 guests.
guests[].roomNumbernumberOptionalRoom the guest occupies, 1–8. Defaults to 1.
guests[].typestringOptional`adult` (default) or `child`.
guests[].firstName / lastNamestringRequiredGuest name.
guests[].agenumberOptionalAge of the guest (0–120). Send it for every child.
partnerReferencestringOptionalYour own reference.
remarksstringOptionalFree-text request passed to the property.
Request
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

GET/hotels/bookings/{reference}Requires x-api-key
POST/hotels/cancelRequires x-api-key

Cancellation follows the rate's policy — a rate past its `cancellationDeadline` may incur a charge, which is reflected in the returned price.

FieldTypeRequiredDescription
referencebody stringRequiredHotel booking reference.
reasonbody stringOptionalOptional cancellation reason.
Retrieve
curl "https://uta.online/api/public/hotels/bookings/HTL-77120" -H "x-api-key: YOUR_KEY"

08 · Hotels API

Hotel Pricing (price only)

POST/hotels/pricingRequires x-api-key

Returns 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.

FieldTypeRequiredDescription
hotelIdstringRequiredHotel id from /hotels/search.
destinationIdstringRequiredDestination code used in the original search.
checkIn / checkOutstringRequired`yyyy-MM-dd`. 1–30 nights.
rooms / adults / childrennumberOptionalOccupancy. Defaults 1 room, 2 adults, 0 children.
childAges[]arrayOptionalAge of each child — required for accurate child pricing.
nationalitystringOptionalGuest nationality code — affects rates in some markets.
currencystringOptional3-letter code. Defaults to AED.
Request
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

`rateKey` values returned here are valid for booking, but expire with the supplier search session. Re-run pricing if more than ~20 minutes pass before `/hotels/book`.

09 · Attractions API

Retrieve Activity Details

GET/attractions/{activityId}Requires x-api-key

Full activity content plus its ticket options. `countryId` and `cityId` are required query parameters because activity ids are scoped to a destination.

FieldTypeRequiredDescription
activityIdpath numberRequiredActivity identifier from search.
countryIdquery numberRequiredDestination country identifier.
cityIdquery numberRequiredDestination city identifier.
travelDatequery stringOptional`yyyy-MM-dd` — returns pricing for that date.
Request
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

POST/attractions/availabilityRequires x-api-key

Confirms live pricing and remaining capacity for a travel date. For slot-based activities the response returns the `timeSlotId` values accepted at booking.

FieldTypeRequiredDescription
activityIdnumberRequiredActivity identifier.
optionIdnumberOptionalRestrict to one ticket option.
contractIdnumberOptionalSupplier contract id. Defaults to 0.
travelDatestringRequired`yyyy-MM-dd`.
adults / children / infantsnumberOptionalPax counts: adults 1–30, children and infants 0–30. Defaults to 1 adult.
transferIdnumberOptionalTransfer option, when the activity offers pickup.
Request
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

POST/attractions/bookRequires x-api-key

Confirms the booking and returns the supplier reference. Slot-based activities require `timeSlotId`; transfer-inclusive options require `transferId` and a `pickupLocation`.

FieldTypeRequiredDescription
activityIdnumberRequiredActivity identifier.
optionIdnumberOptionalTicket option to book.
travelDatestringRequired`yyyy-MM-dd`.
adults / children / infantsnumberOptionalPax counts: adults 1–30, children and infants 0–30. Defaults to 1 adult.
timeSlotIdnumberOptionalRequired when `requiresTimeSlot` is `true`.
transferId / startTime / pickupLocationmixedOptionalTransfer details when applicable.
leadGuestobjectRequired`{ firstName, lastName, email, phone, nationality? }`.
partnerReferencestringOptionalYour own reference.
specialRequeststringOptionalFree-text note passed to the supplier.
Request
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

GET/attractions/bookings/{bookingId}Requires x-api-key
POST/attractions/bookings/{bookingId}/cancelRequires x-api-key

Retrieve returns the ticket, validity and download URL once issued. Cancellation is only possible while the activity's cancellation policy still allows it.

FieldTypeRequiredDescription
bookingIdpath stringRequiredBooking reference returned at book time.
supplierBookingId / serviceUniqueId / uniqueNoquery stringOptionalSupplier identifiers from the booking response — pass them through when available.
supplierBookingId (cancel body)body stringRequiredSupplier booking ID returned at book time (or send bookingId in the body).
reasonbody stringOptionalCancellation reason. Defaults to `Partner cancellation`.
Retrieve
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)

POST/attractions/pricingRequires x-api-key

Returns adult / child / infant unit prices for every option (and transfer variant) of an activity, together with the computed totals for the requested pax mix.

FieldTypeRequiredDescription
activityIdnumberRequiredActivity id from /attractions/search.
travelDatestringRequired`yyyy-MM-dd` visit date.
contractIdnumberOptionalContract id from search. Defaults to 0.
optionIdnumberOptionalRestrict pricing to one option.
adults / children / infantsnumberOptionalPax mix. Defaults 1 / 0 / 0.
transferIdnumberOptionalTransfer variant (0 = ticket only).
Request
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 }.

StatusMeaningWhat to do
400Invalid request — malformed JSON or wrong Content-TypeFix the request format and retry.
401Authentication failed — missing, invalid or revoked keyCheck the x-api-key header; request a new key if revoked.
403Service not assigned to your partner accountAsk UTA to enable the service.
404Resource not found — unknown reference or applicationIdVerify the identifier belongs to your account.
409Conflict — e.g. the booking is already cancelled or the fare changedRe-read the resource and retry with fresh data.
422Validation error — required fields missing or invalidRead details / errors and correct the payload.
429Too many requestsSlow down and retry with backoff.
500Internal server errorRetry with backoff; contact UTA support if it persists.
502 / 503 / 504Supplier unavailable — the airline, hotel or activity provider did not respondRetry shortly; nothing was booked.
400
{
  "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?

A UTA admin can regenerate or revoke your key instantly. Revoked keys immediately return `401` on every endpoint.

13

API Response Standards

All endpoints follow one predictable envelope.

FieldTypeRequiredDescription
successbooleanRequiredtrue for 2xx responses, false for every error.
errorstring | nullOptionalHuman-readable error message. Present only on failures.
detailsobject | nullOptionalField-level validation or diagnostic detail when available.
applicationIduuidOptionalApplication identifier returned by /visa-apply and /visa-status.
referencestringOptionalHuman-friendly UTA reference, e.g. VSA-100001.
statusstringOptionalGDRFAD 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).

cURL
# 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"