Flight Enquiry — Frontend Integration Guide

Endpoint: POST /v1/leads/inquiry
Auth: None required (public endpoint)
Rate limit: 10 requests per 5 minutes per IP
reCAPTCHA: Required — pass a valid Google reCAPTCHA v3 token in recaptchaToken.


Overview

The flight enquiry form has three journey modes:

Tab flightJourneyType Legs
RETURN RETURN 2 legs: outbound + inbound
ONE WAY ONE_WAY 1 leg
MULTI-CITY MULTI_CITY 2+ legs (user can add more)

All three modes share the same endpoint and the same top-level fields. Only the data object differs per mode.


Top-Level Payload

These fields are always required regardless of journey type.

{
  // --- Customer details ---
  "customerFirstName": "Jane",           // string, required
  "customerLastName":  "Smith",          // string, required
  "customerEmail":     "jane@example.com", // valid email, required
  "customerPhoneNumber": "+441234567890",  // string, max 15 chars, required
  "customerCountryCode":  "+44",           // string, max 5 chars, required

  // --- Enquiry meta ---
  "requestFor":     "FLIGHT",    // must be exactly "FLIGHT"
  "source":         "WEBSITE",   // "WEBSITE" | "SOCIAL_MEDIA" | "REFERRAL" | ...
  "travelDateMode": "FIXED",     // "FIXED" | "FLEXIBLE"

  // travelDateMode rules per journey type:
  //   RETURN     → "FIXED",    startDate = outbound date, endDate = return date
  //   ONE_WAY    → "FLEXIBLE", no startDate/endDate needed (dates live in flightLegs)
  //   MULTI_CITY → "FIXED",    startDate = first leg date, endDate = last leg date
  "startDate": "2026-08-15",     // YYYY-MM-DD (omit for ONE_WAY)
  "endDate":   "2026-08-22",     // YYYY-MM-DD (omit for ONE_WAY)

  // --- Passengers ---
  "totalAdults":   2,   // integer ≥ 1, required
  "totalChildren": 1,   // integer ≥ 0, optional
  "totalInfants":  0,   // integer ≥ 0, optional

  // --- Budget ---
  "budget":       800,   // number, optional
  "currencyType": "GBP", // "GBP" | "USD" | "EUR" | ...

  "notes": "",           // string, optional

  // --- reCAPTCHA (required) ---
  "recaptchaToken": "<google-recaptcha-v3-token>",

  // --- Flight-specific payload ---
  "data": { ... },       // see per-mode examples below

  "tags":   [],          // string[], optional
  "tagIds": [],          // number[], optional
  "isTenant": false      // boolean, always false for public enquiries
}

data Object — Per Journey Mode

RETURN

{
  "flightJourneyType": "RETURN",
  "cabinClass": "ECONOMY",
  "flightLegs": [
    {
      "from": "London Heathrow (LHR)",
      "to":   "Dubai (DXB)",
      "date": "2026-08-15"
    },
    {
      "from": "Dubai (DXB)",
      "to":   "London Heathrow (LHR)",
      "date": "2026-08-22"
    }
  ],
  "preferredContactMethod": "EMAIL",
  "bestTimeToCall": "MORNING",
  "marketingOptIn": true
}

Notes:


ONE WAY

{
  "flightJourneyType": "ONE_WAY",
  "cabinClass": "BUSINESS",
  "flightLegs": [
    {
      "from": "Manchester (MAN)",
      "to":   "New York JFK (JFK)",
      "date": "2026-09-10"
    }
  ],
  "preferredContactMethod": "PHONE",
  "bestTimeToCall": "AFTERNOON",
  "marketingOptIn": false
}

Notes:


MULTI-CITY

{
  "flightJourneyType": "MULTI_CITY",
  "cabinClass": "PREMIUM_ECONOMY",
  "flightLegs": [
    { "from": "London (LHR)",  "to": "Paris (CDG)",   "date": "2026-10-01" },
    { "from": "Paris (CDG)",   "to": "Rome (FCO)",    "date": "2026-10-05" },
    { "from": "Rome (FCO)",    "to": "London (LHR)",  "date": "2026-10-12" }
  ],
  "preferredContactMethod": "WHATSAPP",
  "bestTimeToCall": "EVENING",
  "marketingOptIn": true
}

Notes:


Enum Reference

flightJourneyType

Value Label
RETURN Return
ONE_WAY One Way
MULTI_CITY Multi-City

cabinClass

Value Label
ECONOMY Economy
PREMIUM_ECONOMY Premium Economy
BUSINESS Business
FIRST First

preferredContactMethod

Value Label
EMAIL Email
PHONE Phone
WHATSAPP WhatsApp

bestTimeToCall

Value Label
MORNING Morning
AFTERNOON Afternoon
EVENING Evening
ANY Any

Complete Example Payloads (curl)

RETURN

curl -X POST 'https://<api-base>/v1/leads/inquiry' \
  -H 'Content-Type: application/json' \
  -H 'tenantid: 1' \
  --data-raw '{
    "customerFirstName": "Jane",
    "customerLastName": "Smith",
    "customerEmail": "jane@example.com",
    "customerPhoneNumber": "+441234567890",
    "customerCountryCode": "+44",
    "requestFor": "FLIGHT",
    "source": "WEBSITE",
    "travelDateMode": "FIXED",
    "startDate": "2026-08-15",
    "endDate": "2026-08-22",
    "totalAdults": 2,
    "totalChildren": 0,
    "totalInfants": 0,
    "budget": 800,
    "currencyType": "GBP",
    "notes": "",
    "recaptchaToken": "<token>",
    "data": {
      "flightJourneyType": "RETURN",
      "cabinClass": "ECONOMY",
      "flightLegs": [
        { "from": "London Heathrow (LHR)", "to": "Dubai (DXB)", "date": "2026-08-15" },
        { "from": "Dubai (DXB)", "to": "London Heathrow (LHR)", "date": "2026-08-22" }
      ],
      "preferredContactMethod": "EMAIL",
      "bestTimeToCall": "MORNING",
      "marketingOptIn": true
    },
    "tags": [],
    "tagIds": [],
    "isTenant": false
  }'

ONE WAY

curl -X POST 'https://<api-base>/v1/leads/inquiry' \
  -H 'Content-Type: application/json' \
  -H 'tenantid: 1' \
  --data-raw '{
    "customerFirstName": "James",
    "customerLastName": "Brown",
    "customerEmail": "james@example.com",
    "customerPhoneNumber": "+441987654321",
    "customerCountryCode": "+44",
    "requestFor": "FLIGHT",
    "source": "WEBSITE",
    "travelDateMode": "FLEXIBLE",
    "totalAdults": 1,
    "totalChildren": 0,
    "totalInfants": 0,
    "budget": 1200,
    "currencyType": "GBP",
    "notes": "",
    "recaptchaToken": "<token>",
    "data": {
      "flightJourneyType": "ONE_WAY",
      "cabinClass": "BUSINESS",
      "flightLegs": [
        { "from": "Manchester (MAN)", "to": "New York JFK (JFK)", "date": "2026-09-10" }
      ],
      "preferredContactMethod": "PHONE",
      "bestTimeToCall": "AFTERNOON",
      "marketingOptIn": false
    },
    "tags": [],
    "tagIds": [],
    "isTenant": false
  }'

MULTI-CITY

curl -X POST 'https://<api-base>/v1/leads/inquiry' \
  -H 'Content-Type: application/json' \
  -H 'tenantid: 1' \
  --data-raw '{
    "customerFirstName": "Sarah",
    "customerLastName": "Connor",
    "customerEmail": "sarah@example.com",
    "customerPhoneNumber": "+441122334455",
    "customerCountryCode": "+44",
    "requestFor": "FLIGHT",
    "source": "WEBSITE",
    "travelDateMode": "FIXED",
    "startDate": "2026-10-01",
    "endDate": "2026-10-12",
    "totalAdults": 2,
    "totalChildren": 1,
    "totalInfants": 0,
    "budget": 3000,
    "currencyType": "GBP",
    "notes": "Prefer aisle seats",
    "recaptchaToken": "<token>",
    "data": {
      "flightJourneyType": "MULTI_CITY",
      "cabinClass": "PREMIUM_ECONOMY",
      "flightLegs": [
        { "from": "London (LHR)",  "to": "Paris (CDG)",  "date": "2026-10-01" },
        { "from": "Paris (CDG)",   "to": "Rome (FCO)",   "date": "2026-10-05" },
        { "from": "Rome (FCO)",    "to": "London (LHR)", "date": "2026-10-12" }
      ],
      "preferredContactMethod": "WHATSAPP",
      "bestTimeToCall": "EVENING",
      "marketingOptIn": true
    },
    "tags": [],
    "tagIds": [],
    "isTenant": false
  }'

Success Response

{
  "message": "SUC_LEAD_GENERATED",
  "data": {
    "id": "uuid-...",
    "referenceNumber": "HSH-2026-XXXXXXXX",
    "requestFor": "FLIGHT",
    "customerFirstName": "Jane",
    ...
  }
}

Validation Error Response (422)

{
  "message": "data.flightJourneyType must be one of the following values: RETURN, ONE_WAY, MULTI_CITY",
  "developer_errors": [
    {
      "error_type": "ui",
      "actual_error": "...",
      "display_error": "..."
    }
  ]
}

Frontend Form Mapping

Form Field API Field Notes
Tab (RETURN / ONE WAY / MULTI-CITY) data.flightJourneyType RETURN | ONE_WAY | MULTI_CITY
Flying From data.flightLegs[0].from Free text, e.g. "London Heathrow (LHR)"
Flying To data.flightLegs[0].to Free text
Departing date data.flightLegs[0].date + startDate (RETURN/MULTI_CITY) YYYY-MM-DD. For ONE_WAY, date lives only in flightLegs[0].date
Returning date (RETURN only) data.flightLegs[1].date + endDate YYYY-MM-DD
travelDateMode travelDateMode "FIXED" for RETURN & MULTI_CITY; "FLEXIBLE" for ONE_WAY
Flight N from (MULTI-CITY) data.flightLegs[N-1].from 0-indexed
Flight N to (MULTI-CITY) data.flightLegs[N-1].to
Flight N date (MULTI-CITY) data.flightLegs[N-1].date
Preferred Cabin data.cabinClass ECONOMY | PREMIUM_ECONOMY | BUSINESS | FIRST
Adults (16+) totalAdults Top-level, integer ≥ 1
Children (0-15) totalChildren Top-level, integer ≥ 0
Full Name customerFirstName + customerLastName Split on first space
Phone customerPhoneNumber + customerCountryCode Strip country code into customerCountryCode
Email customerEmail

Backward Compatibility

Existing TRIP and HOTEL enquiries are unaffected. The legacy data.flightType field (INCLUDE_FLIGHTS | LAND_ONLY | ECONOMY | PREMIUM_ECONOMY | BUSINESS_CLASS | FIRST_CLASS) remains valid for TRIP leads and will continue to work as before.


Changed Files (for reference)

File Change
src/shared/enums/flight-type.enum.ts Added FlightJourneyTypeEnum, CabinClassEnum, and their label maps
src/modules/leads/dto/lead-data.dto.ts Added FlightLegDto class; added flightJourneyType, cabinClass, flightLegs to LeadPlatformDataDto
src/modules/leads/dto/create-lead.dto.ts Updated data ApiProperty description
src/modules/leads/leads.service.ts Added buildFlightSummary() helper; used it in sendEnquiryEmails()
src/modules/cron/cron.service.ts Added buildFlightSummary() helper; used it in customer confirmation email builder