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.
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.
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{
"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:
flightLegs[0] = outbound (Flying From → Flying To, Departing date)flightLegs[1] = inbound (Flying To → Flying From, Returning date)from/to can be auto-swapped from the outbound by the frontend.startDate (top-level) = flightLegs[0].date, endDate = flightLegs[1].date.{
"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:
travelDateMode: "FLEXIBLE" — the departure date lives inside flightLegs[0].date, not startDate/endDate.startDate and endDate must be omitted (they are only validated when travelDateMode = "FIXED").{
"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:
from and to are free-text (city or airport name).startDate = first leg date; endDate = last leg date.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 |
|
PHONE |
Phone |
WHATSAPP |
bestTimeToCall| Value | Label |
|---|---|
MORNING |
Morning |
AFTERNOON |
Afternoon |
EVENING |
Evening |
ANY |
Any |
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
}'
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
}'
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
}'
{
"message": "SUC_LEAD_GENERATED",
"data": {
"id": "uuid-...",
"referenceNumber": "HSH-2026-XXXXXXXX",
"requestFor": "FLIGHT",
"customerFirstName": "Jane",
...
}
}
{
"message": "data.flightJourneyType must be one of the following values: RETURN, ONE_WAY, MULTI_CITY",
"developer_errors": [
{
"error_type": "ui",
"actual_error": "...",
"display_error": "..."
}
]
}
| 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 |
customerEmail |
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.
| 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 |