Developer documentation · v1

Flight & Hotel Search API

Live airline schedules and hotel availability for your own website or booking portal, plus TicketDrafts-format itineraries and hotel vouchers. JSON responses, one API key.

Base URLhttps://ticketdrafts.xyz/api/v1 Request an API key

Overview

The API returns the same live flight results that power TicketDrafts. You send a route and a date; you get back up to 15 flight options, cheapest first, each with its legs, layovers and an indicative fare. How you display them, and what your website does next, is entirely up to you.

  • One-way search per call, economy, one adult. Return and multi-city trips: one call per leg.
  • Airports are 3-letter IATA codes (DAC, DXB, LHR…).
  • Times are local to each airport. Fares are in USD and indicative.
  • Searching never books or holds a seat.

Authentication

Send your key in a header on every request:

X-API-Key: tdk_live_xxxxxxxxxxxxxxxx

Authorization: Bearer <key> is also accepted.

Call the API from your server, never from the browser. A key placed in website JavaScript can be copied by anyone and used to spend your monthly searches. Your page calls your own backend; your backend calls this API. Browser (CORS) requests are not supported.

Response fields

FieldMeaning
departure / arrivalLocal date and time at each airport. Arrival can be the next day.
stopsNumber of connections. 0 = nonstop.
segmentsOne entry per flight leg, with airline, flight number, airports, times, duration and aircraft.
layoversConnection airport and waiting time in minutes, between consecutive segments.
price.amountLowest economy fare seen for one adult, USD. Indicative — show it as a guide price.
price.estimatedtrue when the source gave no fare and the figure is our estimate.
cachedtrue when the result came from a search made in the last 24 hours.
usageYour searches used this month, limit, remaining, and reset date.

Hotel search

GET/hotels?city=Dubai&country=United Arab Emirates&check_in=2026-11-15&check_out=2026-11-20
ParameterRequiredDescription
cityYesCity name in English, e.g. Dubai
countryRecommendedCountry name, so the right city is found
check_in / check_outYesYYYY-MM-DD; check-out after check-in

Returns up to about 15 real hotels, cheapest first, with stars, guest rating, photos, amenities and the lowest nightly rate in USD. Searching never books a room.

{
  "ok": true,
  "search": { "city": "Dubai", "country": "United Arab Emirates", "check_in": "2026-11-15", "check_out": "2026-11-20" },
  "nights": 5,
  "count": 12,
  "hotels": [
    {
      "id": "ChkI7Z6...",
      "name": "Rove Downtown",
      "stars": 3,
      "rating": 4.4, "reviews": 9120,
      "room_type": "Standard Room",
      "price": { "per_night": 95, "currency": "USD" },
      "images": ["https://..."],
      "amenities": ["Free Wi-Fi", "Pool"],
      "address": "312 Al Sa'ada Street, Dubai",
      "location": { "lat": 25.1972, "lon": 55.2744 },
      "check_in_time": "3:00 PM", "check_out_time": "12:00 PM"
    }
  ],
  "usage": { "used": 13, "limit": 1000, "remaining": 987, "resets_on": "2026-11-01" }
}

Details of the hotel your client picked

GET/hotel?id=ChkI7Z6...&check_in=2026-11-15&check_out=2026-11-20Free, not counted

Adds the hotel's address, phone number, check-in and check-out times and photos stored on TicketDrafts (Google's own photo links expire). Use id values from /hotels. It returns only what it adds, so merge it into the hotel object from /hotels (which keeps the amenities, rating and the nightly price for your dates).

{ "ok": true, "hotel": { "id": "ChkI7Z6...", "name": "Rove Downtown", "address": "...", "phone": "+971 4 561 9000", "images": ["https://ticketdrafts.xyz/uploads/hotels/..."], ... } }

Check usage

GET/usageFree, not counted
{
  "ok": true,
  "client": "Your Agency",
  "plan": "Business",
  "subscription_ends": "2026-11-29",
  "rate_limit_per_minute": 30,
  "usage": { "used": 12, "limit": 1000, "remaining": 988, "resets_on": "2026-11-01" }
}

What counts as a search

  • A /search call that returns flights, or a /hotels call that returns hotels = 1 search from your monthly quota.
  • /hotel (details of one hotel) and /usage are free.
  • Not counted: errors, invalid input, "no flights found" answers, and the same route and date repeated within 15 minutes.
  • The quota resets on the 1st of every month. Unused searches do not carry over.

Errors

Errors return "ok": false with a code and a readable message:

{ "ok": false, "error": { "code": "quota_exceeded", "message": "This month's 1000 searches are used up..." } }
HTTPCodeWhat to do
400bad_airport, bad_date, past_dateFix the parameters.
401missing_key, invalid_keyHeader missing or key wrong.
402quota_exceededMonthly searches used up — upgrade, or wait for the reset.
402subscription_expiredRenew your subscription.
403key_disabled, ip_not_allowedContact us.
429rate_limitedToo many calls per minute — retry after 60 seconds.
503unavailableFlight data source busy — retry in a few minutes. Not counted.

No flights on a route and date returns 200 with "count": 0 and an empty flights list — show "no flights for this date" to your user.

Code examples

PHP

<?php
$url = 'https://ticketdrafts.xyz/api/v1/search?' . http_build_query([
    'from' => 'DXB', 'to' => 'LHR', 'date' => '2026-11-15',
]);
$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 40,
    CURLOPT_HTTPHEADER     => ['X-API-Key: ' . getenv('TICKETDRAFTS_API_KEY')],
]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);

if (!empty($data['ok'])) {
    foreach ($data['flights'] as $f) {
        echo $f['airline']['name'], ' ', $f['flight_number'], ' ',
             $f['departure']['time'], ' → ', $f['arrival']['time'], ' ',
             $f['price']['amount'], ' USD', PHP_EOL;
    }
} else {
    echo 'Error: ', $data['error']['message'] ?? 'unknown';
}

Node.js (server side)

const params = new URLSearchParams({ from: 'DXB', to: 'LHR', date: '2026-11-15' });
const res = await fetch('https://ticketdrafts.xyz/api/v1/search?' + params, {
  headers: { 'X-API-Key': process.env.TICKETDRAFTS_API_KEY },
});
const data = await res.json();
if (data.ok) console.log(data.count, 'flights', data.flights);
else console.error(data.error.code, data.error.message);

Ticket layout

Partners with the ticket layout get one script file. It turns a flight your client picked into a flight itinerary in the TicketDrafts format, with your agency's logo, name, address and phone, and downloads it as an A4 PDF. Everything happens in your client's browser: no extra API call, nothing is sent to TicketDrafts, and searches are not counted.

Your script tag is sent to you by TicketDrafts. It works only on the website domains registered for your account and while your subscription is active.

1. Add the script

<script src="https://ticketdrafts.xyz/sdk/c/YOUR-FILE-ID.js"></script>

2. Build the booking from the search result

Pass the flight objects exactly as /search returned them: one per direction (outbound, then return).

const booking = {
  flights: [outboundFlight, returnFlight],     // objects from /search, unchanged
  passengers: [
    { title: 'MR', first: 'Rahim', last: 'Uddin', type: 'ADULT',
      passport: 'A01234567', nationality: 'Bangladeshi' }
  ],
  pnr: 'K7QX2M',            // optional: your own reference (5-8 letters/digits)
  cabin: 'Economy',         // optional
  status: 'Confirmed',      // Confirmed | Booked | Reserved | Hold
  agency: {                 // optional: your branding in the ticket header
    name: 'Your Agency Name',
    logo: '/images/logo.png',   // same-site URL or a data: URI
    address: 'Office address',
    phone: '+971 4 000 0000'
  },
  fare: { currency: 'AED', rate: 3.6725 }   // or { currency: 'AED', adult: 2140 }, or false to hide fares
};

3. Show it and download it

// Preview on your page
TDTicket.render('#ticket-preview', booking);

// Download the PDF
document.querySelector('#download').addEventListener('click', () => {
  TDTicket.download(booking).catch(err => alert(err.message));
});

// Or get the PDF as a Blob, e.g. to save it on your server or email it
TDTicket.pdf(booking).then(({ blob, pnr, filename }) => { /* upload blob */ });
FieldNotes
passengersAt least one. type is ADULT, CHILD or INFANT and sets the fare rows.
pnrIf left out, one is generated and kept on the booking object, so the preview and the PDF match.
fareDefault: the API fare in USD. rate converts it to your currency; adult sets the adult total yourself. Base fare and taxes are split the same way as on TicketDrafts.
agency.logoLoad it from your own site (or a data: URI). Images on other sites only work if that site allows cross-origin use.

Hotel voucher

The same script makes a TicketDrafts hotel voucher. Pass the hotel object (from /hotel, with the price from /hotels):

const voucher = {
  hotel: Object.assign({}, hotelFromSearch, hotelDetails.hotel, { price: hotelFromSearch.price }),
  check_in: '2026-11-15', check_out: '2026-11-20',
  rooms: 1, adults: 2, children: 0,
  room_type: 'Deluxe King Room',          // optional
  guests: [{ title: 'MR', first: 'Rahim', last: 'Uddin', passport: 'A01234567', nationality: 'Bangladeshi' }],
  reference: 'HT-K7QX2M',                 // optional: your own voucher reference
  agency: { name: 'Your Agency Name', logo: '/images/logo.png', website: 'youragency.com', email: 'support@youragency.com' },
  fare: { currency: 'AED', rate: 3.6725 }  // or false to hide prices
};

TDTicket.renderHotel('#voucher-preview', voucher);
TDTicket.downloadHotel(voucher);
TDTicket.hotelPdf(voucher).then(({ blob, ref, filename }) => { /* upload blob */ });

The voucher shows the room charge for rooms × nights plus 10% taxes and fees, and your agency's name and contact in the footer.

Good practice

  • Allow up to 40 seconds for a fresh (uncached) search.
  • Save the flight your customer selected in your own database — search results are not stored for later lookup.
  • Keep your key in a server environment variable, not in shared code. If it leaks, ask us for a new one; the old key stops working immediately.
  • Optionally send us your server's IP address and we will lock the key to it.

Ready to connect your website?

Questions or a new key: support@ticketdrafts.xyz

Request an API key
Messenger Telegram