flairuk / laravel-aviationstack
The aviationstack API for Laravel: real-time and historical flights, airport timetables, future schedules, routes, airports, airlines and aircraft, with typed errors and lazy paging.
Requires
- php: ^8.2
- illuminate/contracts: ^12.0|^13.0
- illuminate/http: ^12.0|^13.0
- illuminate/support: ^12.0|^13.0
Requires (Dev)
- laravel/pint: ^1.18
- orchestra/testbench: ^10.0|^11.0
- phpunit/phpunit: ^11.5|^12.0|^13.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Aviationstack for Laravel — A fluent client for the aviationstack API: real-time and historical flights, airport timetables, future schedules, routes, and the reference data (airports, airlines, airplanes, aircraft types, taxes, cities, countries).
use FLAIRUK\Aviationstack\Facades\Aviationstack; Aviationstack::flights()->from('LHR')->to('JFK')->status('active')->get(); Aviationstack::flights()->flight('BA117')->on('2026-09-30')->first(); Aviationstack::timetable('JFK')->arrivals()->status('landed')->get(); Aviationstack::futureFlights('BER', '2026-12-01')->airline('AF')->get(); Aviationstack::airports()->search('heathrow')->first(); Aviationstack::airlines()->lazy()->each(fn (array $airline) => /* … */);
Install
composer require flairuk/laravel-aviationstack
The service provider and the Aviationstack facade are discovered automatically.
AVIATIONSTACK_KEY=… AVIATIONSTACK_HTTPS=true # false on the free plan, which refuses HTTPS (error 105) AVIATIONSTACK_MAX_LIMIT=100 # 1000 on Professional and above
php artisan vendor:publish --tag=aviationstack-config
| Key | Default | |
|---|---|---|
AVIATIONSTACK_KEY |
— | Required. Sent as access_key. |
AVIATIONSTACK_HTTPS |
true |
Free plans must set false. |
AVIATIONSTACK_MAX_LIMIT |
100 |
limit() is clamped to this. |
AVIATIONSTACK_TIMEOUT / _CONNECT_TIMEOUT |
20 / 5 |
Seconds. |
AVIATIONSTACK_RETRIES / _RETRY_DELAY |
1 / 500 |
Retries on connection failures and 5xx only. |
Endpoints
| Method | API path | Named filters |
|---|---|---|
flights() |
/v1/flights |
status(), on($date), from(), to(), airline(), airlineName(), flight(), departureDelay($min, $max), arrivalDelay($min, $max), scheduledToDepartOn(), scheduledToArriveOn() |
timetable($iata, $type) |
/v1/timetable |
departures(), arrivals(), status(), airline(), airlineName(), flight() |
futureFlights($iata, $date, $type) |
/v1/flightsFuture |
departures(), arrivals(), on(), airline(), flight() |
routes() |
/v1/routes |
from(), to(), airline(), flight() |
airports(), airlines(), airplanes(), aircraftTypes(), taxes(), cities(), countries() |
/v1/… |
search() (Basic plan and up) |
endpoint($path) |
anything else | — |
The code-based filters pick the parameter from the code's shape:
from('LHR')sendsdep_iata;from('EGLL')sendsdep_icao.to()works the same way.airline('BA')sendsairline_iata;airline('BAW')sendsairline_icao.flight('BA117')sendsflight_iata;flight('BAW117')sendsflight_icao;flight(117)sendsflight_number.
Codes are upper-cased before they are sent.
Use where('param', $value) or wheres([...]) to pass any parameter under the
API's own name. Dates can be strings or DateTimeInterface.
Every call on the facade returns a new builder, so filters never carry over from one query to the next.
Results and paging
get() returns a FLAIRUK\Aviationstack\Page:
$page = Aviationstack::flights()->from('LHR')->page(2, perPage: 50)->get(); $page->data; // array of rows, exactly as the API returned them $page->total; // size of the whole result set $page->offset; // where this page starts $page->hasMore(); $page->first(); $page->collect(); // Illuminate\Support\Collection count($page); foreach ($page as $row) { … }
Rows are left as the API's own arrays. Their field names differ between
endpoints: flights uses snake case and timetable uses camel case.
lazy() returns a LazyCollection that fetches page after page as you walk
it. Each page is a billed request, so set a limit on large result sets:
Aviationstack::airports()->lazy(maxPages: 5)->take(300)->all();
Errors
Failures throw. They are not turned into empty results, because on a paid API "your quota is spent" must not look the same as "there are no flights".
| Exception | apilayer types |
|---|---|
InvalidAccessKeyException |
missing_access_key, invalid_access_key, inactive_user, account_on_hold |
AccessRestrictedException |
https_access_restricted, function_access_restricted, api_access_blocked |
UsageLimitException |
usage_limit_reached, daily_usage_limit_reached, fair_use_limit_reached, rate_limit_reached |
ConnectionException |
The API could not be reached. |
AviationstackException |
The base class, and the type for everything else (invalid_api_function, internal_error, maintenance_mode, …). |
getCode() returns the apilayer error code (101, 104, 106…), $e->type the
error type, and $e->status the HTTP status. An error body is treated as an
error even when it arrives with a 200 status.
A missing key throws before any request is sent. So does a missing required
parameter on timetable or futureFlights (an InvalidArgumentException).
Rate limits to know about
timetableandflightsFutureallow one request every 10 seconds on paid plans, and one every 60 seconds on the free plan.- Historical
flightsgo back 12 months. - The page size is at most 100 below the Professional plan, and 1000 on it and above.
Testing
composer test
composer format
The tests use Http::fake() and never call the real API.
License
MIT. See LICENSE.md.