TripMaker API Specification¶
Overview¶
The TripMaker API provides endpoints for managing trip projects, itineraries, flights, accommodations, activities, other services, exclusions, costs, and PDF generation.
Base Path: /tripmaker
Content Types:
- Request: application/json
- Response: application/json (or application/pdf for downloads)
Response Format¶
All endpoints return a TlinqApiResponse object:
Date Format: All dates are returned in ISO 8601 format (yyyy-MM-dd'T'HH:mm:ss)
Project Endpoints¶
POST /tripmaker/project/create¶
Creates a new trip project.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | Yes | User session token | | projectName | string | Yes | Project name | | customerId | integer | No | Customer ID | | startDate | string | No | Start date (yyyy-MM-dd) | | endDate | string | No | End date (yyyy-MM-dd) | | adults | integer | No | Number of adults | | children | integer | No | Number of children | | infants | integer | No | Number of infants |
Request Example:
{
"session": "user-session-token",
"projectName": "Smith Family Vacation",
"customerId": 1001,
"startDate": "2025-08-15",
"endDate": "2025-08-25",
"adults": 2,
"children": 2,
"infants": 0
}
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"projectId": 5001,
"projectName": "Smith Family Vacation",
"customerId": 1001,
"customerName": "John Smith",
"startDate": "2025-08-15",
"endDate": "2025-08-25",
"adults": 2,
"children": 2,
"infants": 0,
"status": "DRAFT",
"createdBy": 101,
"createdAt": "2025-06-15T10:30:00",
"itineraries": []
}
}
POST /tripmaker/project/list¶
Lists projects with optional filters.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | customerId | integer | No | Filter by customer | | status | string | No | Filter by status | | fromDate | string | No | Filter from date | | toDate | string | No | Filter to date |
Request Example:
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": [
{
"projectId": 5001,
"projectName": "Smith Family Vacation",
"customerId": 1001,
"customerName": "John Smith",
"startDate": "2025-08-15",
"endDate": "2025-08-25",
"adults": 2,
"children": 2,
"infants": 0,
"status": "DRAFT",
"createdAt": "2025-06-15T10:30:00"
},
{
"projectId": 5002,
"projectName": "Corporate Retreat 2025",
"customerId": 2001,
"customerName": "Acme Corp",
"startDate": "2025-09-01",
"endDate": "2025-09-05",
"adults": 20,
"children": 0,
"infants": 0,
"status": "DRAFT",
"createdAt": "2025-06-16T14:00:00"
}
]
}
POST /tripmaker/project/get¶
Gets project details by ID.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | projectId | integer | Yes | Project ID |
Request Example:
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"projectId": 5001,
"projectName": "Smith Family Vacation",
"customerId": 1001,
"customerName": "John Smith",
"customerEmail": "john.smith@example.com",
"startDate": "2025-08-15",
"endDate": "2025-08-25",
"adults": 2,
"children": 2,
"infants": 0,
"status": "DRAFT",
"createdBy": 101,
"createdByName": "Agent Jane",
"createdAt": "2025-06-15T10:30:00",
"updatedAt": "2025-06-18T09:00:00",
"itineraries": [
{
"itineraryId": 6001,
"itineraryName": "Option A - Beach Focus",
"description": "Focus on beach resorts and water activities",
"totalCost": 5500.00,
"totalSelling": 7150.00
},
{
"itineraryId": 6002,
"itineraryName": "Option B - Adventure Focus",
"description": "Focus on adventure activities and cultural tours",
"totalCost": 4800.00,
"totalSelling": 6240.00
}
]
}
}
POST /tripmaker/project/update¶
Updates project details.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | projectId | integer | Yes | Project ID | | projectName | string | No | Project name | | startDate | string | No | Start date | | endDate | string | No | End date | | adults | integer | No | Number of adults | | children | integer | No | Number of children | | infants | integer | No | Number of infants | | status | string | No | Project status |
Request Example:
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"projectId": 5001,
"projectName": "Smith Family Vacation",
"endDate": "2025-08-28",
"status": "QUOTED",
"updatedAt": "2025-06-18T15:30:00"
}
}
POST /tripmaker/project/delete¶
Deletes a project.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | projectId | integer | Yes | Project ID |
Request Example:
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"message": "Project deleted successfully"
}
}
Itinerary Endpoints¶
POST /tripmaker/itinerary/create¶
Creates a new itinerary for a project.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | projectId | integer | Yes | Parent project ID | | itineraryName | string | Yes | Itinerary name | | description | string | No | Description |
Request Example:
{
"session": "user-session-token",
"projectId": 5001,
"itineraryName": "Option A - Beach Focus",
"description": "Focus on beach resorts and water activities"
}
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"itineraryId": 6001,
"projectId": 5001,
"itineraryName": "Option A - Beach Focus",
"description": "Focus on beach resorts and water activities",
"totalCost": 0.00,
"totalSelling": 0.00,
"createdAt": "2025-06-15T11:00:00"
}
}
POST /tripmaker/itinerary/get¶
Gets itinerary details by ID.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | itineraryId | integer | Yes | Itinerary ID |
Request Example:
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"itineraryId": 6001,
"projectId": 5001,
"itineraryName": "Option A - Beach Focus",
"description": "Focus on beach resorts and water activities",
"totalCost": 5500.00,
"totalSelling": 7150.00,
"totalMargin": 1650.00,
"marginPercentage": 30.0,
"createdAt": "2025-06-15T11:00:00",
"updatedAt": "2025-06-18T14:00:00",
"components": [
{
"componentId": 7001,
"componentType": "FLIGHT",
"dayNumber": 1,
"description": "DXB → MLE - Emirates EK652",
"costPrice": 1200.00,
"sellingPrice": 1560.00
},
{
"componentId": 7002,
"componentType": "HOTEL",
"dayNumber": 1,
"nights": 10,
"description": "Maldives Beach Resort - Deluxe Villa",
"costPrice": 3800.00,
"sellingPrice": 4940.00
}
]
}
}
POST /tripmaker/itinerary/list¶
Lists itineraries for a project.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | projectId | integer | Yes | Project ID |
Request Example:
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": [
{
"itineraryId": 6001,
"projectId": 5001,
"itineraryName": "Option A - Beach Focus",
"description": "Focus on beach resorts and water activities",
"totalCost": 5500.00,
"totalSelling": 7150.00
},
{
"itineraryId": 6002,
"projectId": 5001,
"itineraryName": "Option B - Adventure Focus",
"description": "Focus on adventure activities",
"totalCost": 4800.00,
"totalSelling": 6240.00
}
]
}
POST /tripmaker/itinerary/update¶
Updates itinerary details.
Request Example:
{
"session": "user-session-token",
"itineraryId": 6001,
"itineraryName": "Option A - Beach & Spa Focus",
"description": "Focus on beach resorts, water activities and spa treatments"
}
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"itineraryId": 6001,
"itineraryName": "Option A - Beach & Spa Focus",
"description": "Focus on beach resorts, water activities and spa treatments",
"updatedAt": "2025-06-18T16:00:00"
}
}
POST /tripmaker/itinerary/delete¶
Deletes an itinerary.
Request Example:
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"message": "Itinerary deleted successfully"
}
}
Flight Management Endpoints¶
POST /tripmaker/itinerary/add-flight¶
Adds a flight to an itinerary.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | itineraryId | integer | Yes | Itinerary ID | | flightOffer | object | Yes | Flight offer object from search | | dayNumber | integer | No | Day in itinerary |
Request Example:
{
"session": "user-session-token",
"itineraryId": 6001,
"flightOffer": {
"offerId": "FL-12345",
"airline": "Emirates",
"flightNumber": "EK652",
"origin": "DXB",
"destination": "MLE",
"departureDate": "2025-08-15",
"departureTime": "08:00",
"arrivalTime": "12:30",
"cabinClass": "ECONOMY",
"price": 1200.00
},
"dayNumber": 1
}
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"componentId": 7001,
"itineraryId": 6001,
"componentType": "FLIGHT",
"dayNumber": 1,
"airline": "Emirates",
"flightNumber": "EK652",
"origin": "DXB",
"originName": "Dubai International",
"destination": "MLE",
"destinationName": "Velana International",
"departureDate": "2025-08-15",
"departureTime": "08:00",
"arrivalTime": "12:30",
"cabinClass": "ECONOMY",
"costPrice": 1200.00,
"sellingPrice": 1560.00,
"marginType": "PERCENTAGE",
"marginValue": 30.0
}
}
POST /tripmaker/itinerary/get-flights¶
Gets all flights in an itinerary.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | itineraryId | integer | Yes | Itinerary ID |
Request Example:
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": [
{
"componentId": 7001,
"componentType": "FLIGHT",
"dayNumber": 1,
"airline": "Emirates",
"flightNumber": "EK652",
"origin": "DXB",
"destination": "MLE",
"departureDate": "2025-08-15",
"departureTime": "08:00",
"arrivalTime": "12:30",
"cabinClass": "ECONOMY",
"costPrice": 1200.00,
"sellingPrice": 1560.00
},
{
"componentId": 7005,
"componentType": "FLIGHT",
"dayNumber": 11,
"airline": "Emirates",
"flightNumber": "EK653",
"origin": "MLE",
"destination": "DXB",
"departureDate": "2025-08-25",
"departureTime": "14:00",
"arrivalTime": "18:30",
"cabinClass": "ECONOMY",
"costPrice": 1200.00,
"sellingPrice": 1560.00
}
]
}
POST /tripmaker/itinerary/remove-flight¶
Removes a flight from an itinerary.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | flightId | integer | Yes | Flight component ID |
Request Example:
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"message": "Flight removed successfully"
}
}
Accommodation Management Endpoints¶
POST /tripmaker/accommodation/search¶
Searches for accommodations via Amadeus.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | cityCode | string | Yes | City IATA code | | checkInDate | string | Yes | Check-in date (yyyy-MM-dd) | | checkOutDate | string | Yes | Check-out date (yyyy-MM-dd) | | adults | integer | Yes | Number of adults | | roomQuantity | integer | No | Number of rooms |
Request Example:
{
"session": "user-session-token",
"cityCode": "MLE",
"checkInDate": "2025-08-15",
"checkOutDate": "2025-08-25",
"adults": 2,
"roomQuantity": 1
}
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": [
{
"offerId": "HO-98765",
"hotelId": "MLEBEACH",
"hotelName": "Maldives Beach Resort",
"chainCode": "XX",
"starRating": 5,
"address": "North Male Atoll, Maldives",
"latitude": 4.1755,
"longitude": 73.5093,
"roomType": "Deluxe Villa",
"boardType": "ALL_INCLUSIVE",
"price": {
"total": 3800.00,
"currency": "USD",
"perNight": 380.00
},
"amenities": ["Pool", "Spa", "Restaurant", "Beach Access", "Water Sports"]
},
{
"offerId": "HO-98766",
"hotelId": "MLEPALM",
"hotelName": "Palm Paradise Resort",
"starRating": 4,
"address": "South Male Atoll, Maldives",
"roomType": "Beach Bungalow",
"boardType": "HALF_BOARD",
"price": {
"total": 2500.00,
"currency": "USD",
"perNight": 250.00
}
}
]
}
POST /tripmaker/itinerary/add-accommodation¶
Adds accommodation to an itinerary.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | itineraryId | integer | Yes | Itinerary ID | | hotelOffer | object | Yes | Hotel offer from search | | dayNumber | integer | No | Day in itinerary | | nights | integer | No | Number of nights |
Request Example:
{
"session": "user-session-token",
"itineraryId": 6001,
"hotelOffer": {
"offerId": "HO-98765",
"hotelId": "MLEBEACH",
"hotelName": "Maldives Beach Resort",
"roomType": "Deluxe Villa",
"boardType": "ALL_INCLUSIVE",
"price": 3800.00
},
"dayNumber": 1,
"nights": 10
}
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"componentId": 7002,
"itineraryId": 6001,
"componentType": "HOTEL",
"dayNumber": 1,
"nights": 10,
"hotelName": "Maldives Beach Resort",
"roomType": "Deluxe Villa",
"boardType": "ALL_INCLUSIVE",
"checkIn": "2025-08-15",
"checkOut": "2025-08-25",
"costPrice": 3800.00,
"sellingPrice": 4940.00,
"marginType": "PERCENTAGE",
"marginValue": 30.0
}
}
POST /tripmaker/itinerary/get-accommodations¶
Gets all accommodations in an itinerary.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | Yes | User session token | | itineraryId | integer | Yes | Itinerary ID |
Request Example:
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"accommodations": [
{
"componentId": 7002,
"componentType": "HOTEL",
"dayNumber": 1,
"nights": 10,
"hotelName": "Maldives Beach Resort",
"roomType": "Deluxe Villa",
"boardType": "ALL_INCLUSIVE",
"checkIn": "2025-08-15",
"checkOut": "2025-08-25",
"costPrice": 3800.00,
"sellingPrice": 4940.00
}
]
}
}
POST /tripmaker/itinerary/remove-accommodation¶
Removes accommodation from an itinerary.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | Yes | User session token | | accommodationId | integer | Yes | Accommodation ID to remove |
Request Example:
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"message": "Accommodation removed successfully"
}
}
Activity Management Endpoints¶
POST /tripmaker/activity/search¶
Searches for activities via Amadeus.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | latitude | number | Yes | Location latitude | | longitude | number | Yes | Location longitude | | radius | integer | No | Search radius (km) |
Request Example:
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": [
{
"activityId": "ACT-001",
"amadeusOfferId": "TOUR-12345",
"activityName": "Sunset Dolphin Cruise",
"description": "Experience the magical sunset while watching playful dolphins",
"durationMinutes": 180,
"price": {
"amount": 85.00,
"currency": "USD"
},
"category": "WATER_ACTIVITIES",
"rating": 4.8,
"reviewCount": 245,
"images": ["https://example.com/dolphin1.jpg"]
},
{
"activityId": "ACT-002",
"amadeusOfferId": "TOUR-12346",
"activityName": "Snorkeling Safari",
"description": "Explore vibrant coral reefs and marine life",
"durationMinutes": 240,
"price": {
"amount": 120.00,
"currency": "USD"
},
"category": "WATER_ACTIVITIES",
"rating": 4.9,
"reviewCount": 380
}
]
}
POST /tripmaker/itinerary/add-activity¶
Adds activity to an itinerary.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | itineraryId | integer | Yes | Itinerary ID | | activity | object | Yes | Activity data | | dayNumber | integer | No | Day in itinerary | | time | string | No | Time of activity |
Request Example:
{
"session": "user-session-token",
"itineraryId": 6001,
"activity": {
"activityName": "Sunset Dolphin Cruise",
"description": "Experience the magical sunset while watching dolphins",
"durationMinutes": 180,
"price": 85.00,
"source": "AMADEUS",
"amadeusOfferId": "TOUR-12345"
},
"dayNumber": 3,
"time": "16:00"
}
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"activityId": 8001,
"itineraryId": 6001,
"activityDate": "2025-08-17",
"timePeriod": "Afternoon",
"activityName": "Sunset Dolphin Cruise",
"description": "Experience the magical sunset while watching dolphins",
"durationMinutes": 180,
"transportIncluded": false,
"guideIncluded": true,
"baseCostTotal": 85.00,
"sellingPrice": 110.50,
"source": "AMADEUS",
"amadeusOfferId": "TOUR-12345",
"displayOrder": 1,
"createdAt": "2025-06-15T14:00:00"
}
}
POST /tripmaker/itinerary/get-activities¶
Gets all activities in an itinerary.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | itineraryId | integer | Yes | Itinerary ID |
Request Example:
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": [
{
"activityId": 8001,
"itineraryId": 6001,
"activityDate": "2025-08-17",
"timePeriod": "Afternoon",
"activityName": "Sunset Dolphin Cruise",
"description": "Experience the magical sunset while watching dolphins",
"durationMinutes": 180,
"transportIncluded": false,
"guideIncluded": true,
"baseCostTotal": 85.00,
"sellingPrice": 110.50,
"source": "AMADEUS",
"displayOrder": 1
},
{
"activityId": 8002,
"itineraryId": 6001,
"activityDate": "2025-08-19",
"timePeriod": "Morning",
"activityName": "Snorkeling Safari",
"description": "Explore vibrant coral reefs",
"durationMinutes": 240,
"transportIncluded": true,
"guideIncluded": true,
"baseCostTotal": 120.00,
"sellingPrice": 156.00,
"source": "AMADEUS",
"displayOrder": 2
}
]
}
POST /tripmaker/itinerary/update-activity¶
Updates activity details.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | Yes | User session token | | activityId | integer | Yes | Activity ID to update | | itineraryId | integer | Yes | Itinerary ID containing the activity | | activityDate | string | No | Activity date (yyyy-MM-dd) | | timePeriod | string | No | Time period (e.g., "Morning", "Afternoon") | | activityName | string | No | Activity name | | description | string | No | Activity description | | durationMinutes | integer | No | Duration in minutes |
Request Example:
{
"session": "user-session-token",
"activityId": 8001,
"itineraryId": 6001,
"activityDate": "2025-08-18",
"timePeriod": "Evening",
"description": "Experience the magical sunset while watching playful dolphins - includes refreshments"
}
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"activityId": 8001,
"message": "Activity updated successfully"
}
}
Error Codes:
- NOTFOUND - Activity not found in the itinerary
POST /tripmaker/itinerary/remove-activity¶
Removes activity from an itinerary.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | Yes | User session token | | activityId | integer | Yes | Activity ID to remove |
Request Example:
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"message": "Activity removed successfully"
}
}
Exclusion Management Endpoints¶
POST /tripmaker/itinerary/add-exclusion¶
Adds an exclusion to an itinerary.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | itineraryId | integer | Yes | Itinerary ID | | exclusionText | string | Yes | Exclusion description |
Request Example:
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"exclusionId": 9001,
"itineraryId": 6001,
"exclusionText": "Travel insurance",
"displayOrder": 1,
"createdAt": "2025-06-15T15:00:00"
}
}
POST /tripmaker/itinerary/get-exclusions¶
Gets all exclusions for an itinerary.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | itineraryId | integer | Yes | Itinerary ID |
Request Example:
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": [
{
"exclusionId": 9001,
"itineraryId": 6001,
"exclusionText": "Travel insurance",
"displayOrder": 1,
"createdAt": "2025-06-15T15:00:00"
},
{
"exclusionId": 9002,
"itineraryId": 6001,
"exclusionText": "Visa fees",
"displayOrder": 2,
"createdAt": "2025-06-15T15:01:00"
},
{
"exclusionId": 9003,
"itineraryId": 6001,
"exclusionText": "Personal expenses and tips",
"displayOrder": 3,
"createdAt": "2025-06-15T15:02:00"
}
]
}
POST /tripmaker/itinerary/update-exclusion¶
Updates an exclusion.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | Yes | User session token | | exclusionId | integer | Yes | Exclusion ID to update | | exclusionText | string | Yes | Updated exclusion text |
Request Example:
{
"session": "user-session-token",
"exclusionId": 9001,
"exclusionText": "Travel and medical insurance"
}
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"exclusionId": 9001,
"message": "Exclusion updated successfully"
}
}
POST /tripmaker/itinerary/delete-exclusion¶
Deletes an exclusion.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | Yes | User session token | | exclusionId | integer | Yes | Exclusion ID to delete |
Request Example:
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"message": "Exclusion deleted successfully"
}
}
Other Service Management Endpoints¶
POST /tripmaker/itinerary/add-other-service¶
Adds an other service to an itinerary. Supports miscellaneous services such as transport, visa processing, meet & greet, etc. Currency conversion is applied automatically if the service currency differs from the local currency.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | itineraryId | integer | Yes | Itinerary ID | | category | string | Yes | Service category (TRANSPORT, VISA, MEET & GREET, OTHERS) | | description | string | Yes | Service description | | serviceDate | string | No | Service date (yyyy-MM-dd) | | serviceTime | string | No | Service time (HH:mm) | | quantity | integer | No | Quantity (default: 1) | | supplierName | string | No | Supplier name | | baseCostTotal | decimal | No | Base cost total (default: 0.00) | | basePriceTotal | decimal | No | Base price total (default: 0.00) | | currency | string | No | Currency code (e.g. USD, AED, EUR) |
Request Example:
{
"session": "user-session-token",
"itineraryId": 6001,
"category": "TRANSPORT",
"description": "Airport transfer DXB to hotel",
"serviceDate": "2025-08-15",
"serviceTime": "14:00",
"quantity": 1,
"supplierName": "ABC Transport LLC",
"baseCostTotal": 45.00,
"basePriceTotal": 60.00,
"currency": "AED"
}
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"otherServiceId": 10001,
"baseCostTotal": 45.00,
"basePriceTotal": 60.00,
"currency": "AED",
"originalCostTotal": null
}
}
POST /tripmaker/itinerary/get-other-services¶
Gets all other services in an itinerary.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | itineraryId | integer | Yes | Itinerary ID |
Request Example:
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"otherServices": [
{
"otherServiceId": 10001,
"itineraryId": 6001,
"category": "TRANSPORT",
"description": "Airport transfer DXB to hotel",
"serviceDate": "2025-08-15",
"serviceTime": "14:00",
"quantity": 1,
"supplierName": "ABC Transport LLC",
"baseCostTotal": 45.00,
"basePriceTotal": 60.00,
"currency": "AED",
"originalCostTotal": null,
"createdAt": "2025-06-15T15:00:00"
},
{
"otherServiceId": 10002,
"itineraryId": 6001,
"category": "VISA",
"description": "Tourist visa processing",
"serviceDate": null,
"serviceTime": null,
"quantity": 2,
"supplierName": null,
"baseCostTotal": 150.00,
"basePriceTotal": 200.00,
"currency": "AED",
"originalCostTotal": null,
"createdAt": "2025-06-15T15:05:00"
}
]
}
}
POST /tripmaker/itinerary/update-other-service¶
Updates an other service. Uses read-modify-write pattern — only provided fields are updated.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | otherServiceId | integer | Yes | Other service ID to update | | itineraryId | integer | Yes | Itinerary ID | | category | string | No | Service category | | description | string | No | Service description | | serviceDate | string | No | Service date (yyyy-MM-dd) | | serviceTime | string | No | Service time (HH:mm) | | quantity | integer | No | Quantity | | supplierName | string | No | Supplier name | | baseCostTotal | decimal | No | Base cost total | | basePriceTotal | decimal | No | Base price total | | currency | string | No | Currency code |
Request Example:
{
"session": "user-session-token",
"otherServiceId": 10001,
"itineraryId": 6001,
"baseCostTotal": 50.00,
"basePriceTotal": 65.00
}
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"otherServiceId": 10001,
"message": "Other service updated successfully"
}
}
POST /tripmaker/itinerary/remove-other-service¶
Removes an other service from an itinerary.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | otherServiceId | integer | Yes | Other service ID to remove |
Request Example:
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"message": "Other service removed successfully"
}
}
Cost Management Endpoints¶
POST /tripmaker/cost/get-breakdown¶
Gets cost breakdown for an itinerary.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | itineraryId | integer | Yes | Itinerary ID |
Request Example:
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"itineraryId": 6001,
"components": [
{
"componentId": 7001,
"componentType": "FLIGHT",
"description": "DXB → MLE - Emirates EK652",
"costPrice": 1200.00,
"marginType": "PERCENTAGE",
"marginValue": 30.0,
"marginAmount": 360.00,
"sellingPrice": 1560.00
},
{
"componentId": 7002,
"componentType": "HOTEL",
"description": "Maldives Beach Resort - 10 nights",
"costPrice": 3800.00,
"marginType": "PERCENTAGE",
"marginValue": 30.0,
"marginAmount": 1140.00,
"sellingPrice": 4940.00
},
{
"componentId": 8001,
"componentType": "ACTIVITY",
"description": "Sunset Dolphin Cruise",
"costPrice": 85.00,
"marginType": "PERCENTAGE",
"marginValue": 30.0,
"marginAmount": 25.50,
"sellingPrice": 110.50
}
],
"totalCost": 5085.00,
"totalMargin": 1525.50,
"totalSelling": 6610.50,
"overallMarginPercentage": 30.0,
"currency": "USD"
}
}
POST /tripmaker/cost/update-margin¶
Updates margin for a component.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | componentId | integer | Yes | Component ID | | marginType | string | Yes | "PERCENTAGE" or "FIXED" | | marginValue | number | Yes | Margin value |
Request Example:
{
"session": "user-session-token",
"componentId": 7001,
"marginType": "PERCENTAGE",
"marginValue": 25.0
}
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"componentId": 7001,
"costPrice": 1200.00,
"marginType": "PERCENTAGE",
"marginValue": 25.0,
"marginAmount": 300.00,
"sellingPrice": 1500.00,
"message": "Margin updated successfully"
}
}
POST /tripmaker/cost/override-price¶
Overrides price for a component.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | componentId | integer | Yes | Component ID | | overridePrice | number | Yes | New selling price |
Request Example:
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"componentId": 7002,
"costPrice": 3800.00,
"sellingPrice": 5000.00,
"effectiveMargin": 31.58,
"priceOverridden": true,
"message": "Price override applied successfully"
}
}
POST /tripmaker/cost/apply-global-margin¶
Applies global margin to all components.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | itineraryId | integer | Yes | Itinerary ID | | marginType | string | Yes | "PERCENTAGE" or "FIXED" | | marginValue | number | Yes | Margin value |
Request Example:
{
"session": "user-session-token",
"itineraryId": 6001,
"marginType": "PERCENTAGE",
"marginValue": 25.0
}
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"itineraryId": 6001,
"componentsUpdated": 5,
"totalCost": 5085.00,
"totalMargin": 1271.25,
"totalSelling": 6356.25,
"marginType": "PERCENTAGE",
"marginValue": 25.0,
"message": "Global margin applied to all components"
}
}
PDF Generation Endpoints¶
Both PDF types (quotation and brochure) use externalized HTML templates loaded from TLINQ_HOME/templates/tripmaker/. If no external template is found, the system falls back to classpath-bundled defaults. This allows layout customization without rebuilding.
| Template | File | Purpose |
|---|---|---|
| Quotation | pdf-quotation-template.html |
Client-facing pricing document |
| Brochure | pdf-brochure-template.html |
AI-generated travel brief (no prices) |
POST /tripmaker/pdf/generate¶
Generates PDF quotation. Includes flights, accommodations, activities, other services, a chronological trip schedule, exclusions, and a cost summary.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | itineraryId | integer | Yes | Itinerary ID | | templateId | integer | No | PDF template ID | | includeBreakdown | boolean | No | Include cost breakdown |
Request Example:
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"pdfId": "PDF-2025-12345",
"itineraryId": 6001,
"fileName": "SmithFamilyVacation_OptionA.pdf",
"fileSize": 245678,
"generatedAt": "2025-06-18T16:30:00",
"expiresAt": "2025-06-25T16:30:00",
"downloadUrl": "/tripmaker/pdf/download/PDF-2025-12345"
}
}
POST /tripmaker/pdf/download¶
Downloads PDF quotation.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | pdfId | string | Yes | PDF document ID |
Response:
Returns PDF file as binary stream with Content-Disposition header.
POST /tripmaker/pdf/email¶
Emails PDF quotation.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | pdfId | string | Yes | PDF document ID | | recipientEmail | string | Yes | Recipient email | | subject | string | No | Email subject | | message | string | No | Email message |
Request Example:
{
"session": "user-session-token",
"pdfId": "PDF-2025-12345",
"recipientEmail": "john.smith@example.com",
"subject": "Your Maldives Vacation Quote",
"message": "Dear Mr. Smith,\n\nPlease find attached our proposed itinerary for your family vacation to the Maldives.\n\nBest regards,\nTravel Team"
}
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"emailSent": true,
"recipientEmail": "john.smith@example.com",
"sentAt": "2025-06-18T16:45:00",
"message": "Quote emailed successfully"
}
}
POST /tripmaker/pdf/get-status¶
Gets PDF generation status.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | pdfId | string | Yes | PDF document ID |
Request Example:
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"pdfId": "PDF-2025-12345",
"status": "READY",
"fileName": "SmithFamilyVacation_OptionA.pdf",
"fileSize": 245678,
"generatedAt": "2025-06-18T16:30:00",
"expiresAt": "2025-06-25T16:30:00",
"downloadCount": 2,
"emailedTo": ["john.smith@example.com"]
}
}
POST /tripmaker/pdf/generate-brochure¶
Generates a travel brochure PDF combining the AI-generated travel brief with the trip schedule. The brochure is strictly a "travel story" document — no prices or cost information are included.
Request Body: | Field | Type | Required | Description | |-------|------|----------|-------------| | session | string | No | User session token | | itineraryId | integer | Yes | Itinerary ID | | aiBrief | object | Yes | AI brief data (headline, narrative, areas, sights, practical info) |
Request Example:
{
"session": "user-session-token",
"itineraryId": 6001,
"aiBrief": {
"headline": "Bali: Island of Gods",
"timing_score": 4,
"timing_explanation": "Great weather for beach and culture",
"narrative": "Bali offers a rich tapestry of experiences...",
"areas": [
{ "name": "Ubud", "description": "Cultural heart of Bali", "highlights": ["Rice terraces", "Monkey Forest"] }
],
"sights": [
{ "name": "Tanah Lot Temple", "description": "Iconic sea temple", "duration": "2 hours", "best_time": "Sunset" }
],
"activities": [
{ "name": "Surfing in Kuta", "description": "Beginner-friendly waves", "duration": "3 hours" }
],
"practical": {
"visa": "Visa on arrival for most nationalities",
"currency": "Indonesian Rupiah (IDR)",
"transport": "Scooter rental or private driver",
"safety": "Generally safe for tourists",
"etiquette": "Dress modestly at temples",
"connectivity": "Good WiFi in tourist areas",
"health": "Drink bottled water only"
}
}
}
Response Structure:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"pdfId": "PDF-2025-12346",
"itineraryId": 6001,
"fileName": "SmithFamilyVacation_Brochure.pdf",
"fileSize": 198432,
"generatedAt": "2025-06-18T17:00:00",
"downloadUrl": "/tripmaker/pdf/download/PDF-2025-12346"
}
}
Brochure Content: - Cover header with destination, dates, traveler details - Timing badge (score and explanation) - Narrative section (AI-generated destination overview) - Recommended areas (cards with highlights) - Sights and activities grid - Chronological trip schedule (same as quotation) - Practical information table
Data Models¶
CTripProject¶
| Field | Type | Description |
|---|---|---|
| projectId | integer | Project ID |
| projectName | string | Project name |
| customerId | integer | Customer ID |
| customerName | string | Customer name |
| startDate | date | Trip start date |
| endDate | date | Trip end date |
| adults | integer | Number of adults |
| children | integer | Number of children |
| infants | integer | Number of infants |
| status | string | Project status (DRAFT, QUOTED, ACCEPTED, BOOKED, COMPLETED, CANCELLED) |
| createdBy | integer | Creator user ID |
| createdAt | datetime | Creation timestamp |
| updatedAt | datetime | Last update timestamp |
| itineraries | array | List of itineraries |
CTripItinerary¶
| Field | Type | Description |
|---|---|---|
| itineraryId | integer | Itinerary ID |
| projectId | integer | Parent project ID |
| itineraryName | string | Itinerary name |
| description | string | Description |
| totalCost | decimal | Total cost |
| totalSelling | decimal | Total selling price |
| totalMargin | decimal | Total margin amount |
| marginPercentage | decimal | Overall margin percentage |
| createdAt | datetime | Creation timestamp |
| updatedAt | datetime | Last update timestamp |
| components | array | List of trip components |
CTripComponent¶
| Field | Type | Description |
|---|---|---|
| componentId | integer | Component ID |
| itineraryId | integer | Parent itinerary ID |
| componentType | string | Type (FLIGHT, HOTEL, ACTIVITY, OTHER_SERVICE) |
| dayNumber | integer | Day in itinerary |
| description | string | Component description |
| costPrice | decimal | Cost price |
| sellingPrice | decimal | Selling price |
| marginType | string | Margin type (PERCENTAGE, FIXED) |
| marginValue | decimal | Margin value |
| marginAmount | decimal | Calculated margin amount |
| priceOverridden | boolean | Whether price is manually overridden |
CCostBreakdown¶
| Field | Type | Description |
|---|---|---|
| itineraryId | integer | Itinerary ID |
| components | array | Component costs array |
| totalCost | decimal | Total cost |
| totalMargin | decimal | Total margin |
| totalSelling | decimal | Total selling price |
| overallMarginPercentage | decimal | Overall margin as percentage |
| currency | string | Currency code |
CActivity¶
| Field | Type | Description |
|---|---|---|
| activityId | integer | Activity ID |
| itineraryId | integer | Parent itinerary ID |
| activityDate | date | Activity date |
| timePeriod | string | Time period (MORNING, AFTERNOON, EVENING, FULL_DAY) |
| activityName | string | Activity name |
| description | string | Activity description |
| durationMinutes | integer | Duration in minutes |
| transportIncluded | boolean | Whether transport is included |
| guideIncluded | boolean | Whether guide is included |
| baseCostTotal | decimal | Base cost total |
| sellingPrice | decimal | Selling price |
| source | string | Source (AMADEUS, MANUAL) |
| amadeusOfferId | string | Amadeus offer ID if sourced from Amadeus |
| displayOrder | integer | Display order |
| createdAt | datetime | Creation timestamp |
COtherService¶
| Field | Type | Description |
|---|---|---|
| otherServiceId | integer | Other service ID |
| itineraryId | integer | Parent itinerary ID |
| category | string | Service category (TRANSPORT, VISA, MEET & GREET, OTHERS) |
| description | string | Service description |
| serviceDate | date | Service date |
| serviceTime | string | Service time (HH:mm format) |
| quantity | integer | Quantity (default: 1) |
| supplierName | string | Supplier name |
| baseCostTotal | decimal | Base cost total |
| basePriceTotal | decimal | Base price total (selling price) |
| currency | string | Currency code |
| originalCostTotal | decimal | Original cost before currency conversion |
| createdAt | datetime | Creation timestamp |
CExclusion¶
| Field | Type | Description |
|---|---|---|
| exclusionId | integer | Exclusion ID |
| itineraryId | integer | Parent itinerary ID |
| exclusionText | string | Exclusion description text |
| displayOrder | integer | Display order |
| createdAt | datetime | Creation timestamp |
Booking Integration¶
POST /tripmaker/project/convertToBooking¶
Converts a TripMaker project in QUOTED status into a BLM booking. The project is set to CLOSED after successful conversion.
Request Body:
| Parameter | Type | Required | Description |
|---|---|---|---|
| projectId | Integer | Yes | The TripMaker project ID |
| itineraryId | Integer | Yes | The itinerary whose cost breakdown defines the service lines |
Response: CBooking object with all fields populated, including bookingId, bookingRef, status (ENQUIRY), sourceType (TRIPMAKER), sourceRef (projectId).
Example Request:
Example Response:
{
"apiStatus": { "errorCode": "OK", "errorMessage": "Success" },
"apiData": {
"bookingId": 101,
"bookingRef": "TQ-2026-00042",
"status": "ENQUIRY",
"customerName": "John Smith",
"sourceType": "TRIPMAKER",
"sourceRef": "15",
"travelStartDate": "2026-05-01",
"travelEndDate": "2026-05-08"
}
}
Error Responses:
- Project not found → ERR00012
- Project not in QUOTED status → ERR00014
- Itinerary doesn't belong to project → ERR00012
Roles: agent, admin