Skip to content

AerTicket Integration

Interface to AerTicket API for flight search, verification, booking, ticket issuance, void, ancillaries, retrieval, and cancellation. Supports both UAT and Production environments with automatic authentication, retry logic, and comprehensive error handling.

Environment Variables (.env)

Terminal window
AERTICKET_UAT_CABINET_URL=https://uat-cabinet.aerticket.com
AERTICKET_UAT_API_BASE_URL=https://uat-api.aerticket.com
AERTICKET_UAT_USERNAME=your_uat_username
AERTICKET_UAT_PASSWORD=your_uat_password
AERTICKET_DEFAULT_ENVIRONMENT=uat
AERTICKET_TIMEOUT=30

Test Connection

Terminal window
./vendor/bin/sail artisan aerticket:test-connection
use App\Services\AerticketCabinetService;
use App\Services\Flights\Aerticket\AerticketSearchService;
$cabinet = app(AerticketCabinetService::class);
$search = new AerticketSearchService($cabinet);
$results = $search->search([
'origin' => 'BCN',
'destination' => 'MAD',
'departure_date' => '2025-12-15',
'return_date' => '2025-12-20',
'adults' => 2,
'cabin_class' => 'economy',
]);
foreach ($results->getFares() as $fare) {
echo "Price: {$fare->getTotalPrice()} {$fare->getCurrency()}\n";
}
use App\Services\Flights\Aerticket\AerticketSearchService;
use App\Services\Flights\Aerticket\DTOs\Request\PassengerType;
use App\Services\Flights\Aerticket\DTOs\Request\SearchOptions;
use App\Services\Flights\Aerticket\DTOs\Request\SearchRequest;
// Define multi-city segments (2-6 segments allowed)
$segments = [
['departure' => 'BCN', 'destination' => 'BKK', 'date' => '2025-12-20'],
['departure' => 'BKK', 'destination' => 'CNX', 'date' => '2025-12-25'],
['departure' => 'CNX', 'destination' => 'BCN', 'date' => '2026-01-05'],
];
// Build passenger types
$passengers = [
PassengerType::adult(2),
PassengerType::child(1),
];
// Create multi-city search request
$searchRequest = SearchRequest::multiCity(
segments: $segments,
passengerTypeList: $passengers,
searchOptions: new SearchOptions(cabinClassList: ['ECONOMY'])
);
// Execute search
$searchService = new AerticketSearchService();
$response = $searchService->search($searchRequest);
ServicePurpose
AerticketCabinetServiceHTTP client, authentication, environment switching
AerticketSearchServiceFlight search
AerticketSearchUpsellServiceFare upgrade search
AerticketVerifyServiceFare verification
AerticketBookServiceBooking creation
AerticketTicketIssueServiceTicket issuance
AerticketFastlaneTicketingServiceFast-track ticket issuance
AerticketRePriceServiceBooking re-pricing
AerticketVoidServiceBooking void
AerticketAncillaryServiceAncillary services (baggage, meals)
AerticketFareRulesServiceFare rules and restrictions
AerticketRetrieveServicePNR retrieval
AerticketCancelServiceBooking cancellation
Terminal window
# UAT (default)
AERTICKET_UAT_CABINET_URL=https://uat-cabinet.aerticket.com
AERTICKET_UAT_API_BASE_URL=https://uat-api.aerticket.com
AERTICKET_UAT_USERNAME=your_username
AERTICKET_UAT_PASSWORD=your_password
# Production
AERTICKET_PRODUCTION_CABINET_URL=https://cabinet.aerticket.com
AERTICKET_PRODUCTION_API_BASE_URL=https://api.aerticket.com
AERTICKET_PRODUCTION_USERNAME=your_username
AERTICKET_PRODUCTION_PASSWORD=your_password
# Environment Selection
AERTICKET_ENVIRONMENT=uat # Values: "uat" or "production"
# Timeouts and Retries
AERTICKET_TIMEOUT=30
AERTICKET_RETRY_ATTEMPTS=3
AERTICKET_FASTLANE_TIMEOUT=300

To prevent accidental low-cost carrier bookings in staging/UAT:

  • Flydubai flights (airline code: FZ) are blocked
  • Flights requiring instant purchase are blocked

Controlled by AERTICKET_ENVIRONMENT variable - active when set to "uat".

use App\Services\Flights\Aerticket\AerticketVerifyService;
$verify = new AerticketVerifyService($cabinet);
$response = $verify->verify([
'fare_id' => $fare->getId(),
'session_id' => $searchResponse->getSessionId(),
]);
if ($response->isAvailable()) {
$updatedPrice = $response->getPrice();
}
use App\Jobs\AerticketCreateBookingJob;
AerticketCreateBookingJob::dispatch(
fareId: 'fare-123',
instantTicketOrder: true,
userId: auth()->id()
)->onQueue('aerticket-bookings');
use App\Jobs\AerticketIssueTicketJob;
AerticketIssueTicketJob::dispatch(
bookingReference: 'ABC123',
bookingId: $flightBooking->id,
userId: auth()->id()
)->onQueue('aerticket-tickets');

Faster alternative to regular ticket issuance. Booking must be at least 5 minutes old.

use App\Jobs\AerticketFastlaneTicketingJob;
AerticketFastlaneTicketingJob::dispatch(
bookingReference: 'ABC123',
bookingId: $flightBooking->id,
userId: auth()->id()
)->onQueue('aerticket-fastlane');
use App\Services\Flights\Aerticket\AerticketRePriceService;
use App\Services\Flights\Aerticket\DTOs\Request\PriceRange;
$rePriceService = new AerticketRePriceService($cabinet);
// Re-pricing with price tolerance (±5 EUR)
$priceRange = new PriceRange(min: 5.0, max: 5.0);
$response = $rePriceService->rePrice('ABC123', $priceRange);
if ($response->hasNewFares()) {
// Price outside tolerance - requires approval
$subFareToken = $response->getSubFareToken();
}
use App\Services\Flights\Aerticket\AerticketAncillaryService;
$ancillaryService = new AerticketAncillaryService($cabinet);
// For bookings (after booking)
$response = $ancillaryService->availableBookingAncillaries(
pnrLocator: 'ABC123',
ancillaryTypes: ['BAGGAGE', 'MEAL']
);
foreach ($response->getAncillariesByType() as $type => $ancillaries) {
foreach ($ancillaries as $ancillary) {
echo "{$ancillary->name}: {$ancillary->getFormattedPrice()}\n";
}
}
use App\Services\Flights\Aerticket\AerticketCancelService;
$cancel = new AerticketCancelService($cabinet);
// Normal cancellation
$result = $cancel->cancelBooking('ABC123');
// Force cancellation (even if tickets issued)
$result = $cancel->cancelBooking('ABC123', forceCancellation: true);

Per AerTicket API specification:

  • No numbers in firstName or lastName
  • No symbols (only letters and spaces)
  • No ”+” character
  • Combined length: 2-57 characters
  • Valid titles: MR, MRS, MS, CHD, INF, DR MR, etc.
use App\Rules\PassengerValidationRules;
// In Form Requests
public function rules(): array
{
return [
'passengerList.*.firstName' => PassengerValidationRules::firstName(),
'passengerList.*.lastName' => PassengerValidationRules::lastName(),
'passengerList.*.title' => PassengerValidationRules::title(),
];
}
  • Infant (INF): 0-23 months
  • Child (CHD): 2-15 years
  • Adult (ADT): 16+ years
use App\Enums\AgeCategory;
$ageCategory = AgeCategory::fromDateOfBirth($dateOfBirth);
if (!$ageCategory->isValidForDateOfBirth($dateOfBirth)) {
$errorMessage = $ageCategory->getValidationErrorMessage($dateOfBirth);
}
ExceptionDescription
AerticketValidationExceptionInvalid input
AerticketTimeoutExceptionRequest timeout
AerticketSearchExceptionSearch error
AerticketBookingExceptionBooking error
AerticketTicketIssueExceptionTicket issuance error
AerticketRePricingExceptionRe-pricing error
AerticketFareExpiredExceptionFare expired (410)
AerticketPriceChangeExceptionPrice changed
try {
$results = $search->search($data);
} catch (AerticketValidationException $e) {
return response()->json(['error' => $e->getMessage()], 422);
} catch (AerticketTimeoutException $e) {
return response()->json(['error' => 'Request timed out'], 504);
} catch (AerticketSearchException $e) {
Log::error('Search failed', ['error' => $e->getMessage()]);
return response()->json(['error' => 'Search failed'], 500);
}
Terminal window
# All AerTicket tests
./vendor/bin/sail artisan test --filter=Aerticket
# Connection test
./vendor/bin/sail artisan aerticket:test-connection
# Re-pricing tests
./vendor/bin/sail artisan test --filter=RePrice
# Ancillary tests
./vendor/bin/sail artisan test --filter=Ancillary
Terminal window
php artisan tinker
>>> config('aerticket.environments.uat.username')

Increase timeout in .env:

Terminal window
AERTICKET_TIMEOUT=60

Check logs:

Terminal window
./vendor/bin/sail artisan pail --filter="apihubflowid"

The apihubflowid is required when contacting AerTicket support.