PHPackages                             iabduul7/laravel-themepark-booking-adapters - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. iabduul7/laravel-themepark-booking-adapters

ActiveLibrary[API Development](/categories/api)

iabduul7/laravel-themepark-booking-adapters
===========================================

Self-contained, drop-in Laravel booking adapters for Walt Disney World &amp; SeaWorld/United Parks (Redeam) and Universal Orlando (SmartOrder): catalog, pricing, availability, holds/bookings, orders and voucher data.

v4.0.0(1w ago)04MITPHPPHP ^8.2CI passing

Since Dec 2Pushed 1w agoCompare

[ Source](https://github.com/iabduul7/laravel-themepark-booking-adapters)[ Packagist](https://packagist.org/packages/iabduul7/laravel-themepark-booking-adapters)[ Docs](https://github.com/iabduul7/laravel-themepark-booking-adapters)[ GitHub Sponsors](https://github.com/iabduul7)[ RSS](/packages/iabduul7-laravel-themepark-booking-adapters/feed)WikiDiscussions main Synced today

READMEChangelog (2)Dependencies (31)Versions (12)Used By (0)

Laravel Theme Park Booking Adapters
===================================

[](#laravel-theme-park-booking-adapters)

[![Latest Version on Packagist](https://camo.githubusercontent.com/64600adbca64d0cec30cf88c66cf2084e31c116f92fce10620e9e684c1315d64/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6961626475756c372f6c61726176656c2d7468656d657061726b2d626f6f6b696e672d61646170746572732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/iabduul7/laravel-themepark-booking-adapters)[![GitHub Tests Action Status](https://camo.githubusercontent.com/7a376bb7f1c9d851e7e79a89ee3e91db50f842760a0747a6a82b4239617334a5/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6961626475756c372f6c61726176656c2d7468656d657061726b2d626f6f6b696e672d61646170746572732f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/iabduul7/laravel-themepark-booking-adapters/actions?query=workflow%3Arun-tests+branch%3Amain)[![GitHub PHPStan Action Status](https://camo.githubusercontent.com/02520f0d40e3234382b0888b2abb48f0b76960a1543c53408835924b80392155/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6961626475756c372f6c61726176656c2d7468656d657061726b2d626f6f6b696e672d61646170746572732f7068707374616e2e796d6c3f6272616e63683d646576266c6162656c3d7068707374616e267374796c653d666c61742d737175617265)](https://github.com/iabduul7/laravel-themepark-booking-adapters/actions?query=workflow%3Aphpstan+branch%3Adev)[![Total Downloads](https://camo.githubusercontent.com/54e9bdeb798b70856823c16b63eb86807654abe6659b5a80c9f34143e4bd36d0/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6961626475756c372f6c61726176656c2d7468656d657061726b2d626f6f6b696e672d61646170746572732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/iabduul7/laravel-themepark-booking-adapters)

A Laravel package providing self-contained, drop-in booking adapters for major theme park distribution APIs:

ParkProviderAdapterWalt Disney WorldRedeam`DisneyRedeamAdapter`SeaWorld / United ParksRedeam`SeaWorldRedeamAdapter`Universal OrlandoSmartOrder ("SmartOrder2")`UniversalSmartOrder2Adapter`Each adapter exposes the provider's real API surface (catalog, rates, availability, pricing schedules, holds/bookings for Redeam; events/orders for SmartOrder) and returns lightweight DTOs over the raw responses. Auth, retries and OAuth token management are handled for you.

> **What's working today:** all three adapters are contract-tested with `Http::fake` and analysed with PHPStan (level 3). Read paths (catalog, rates, pricing, availability) are additionally verified against the live provider sandboxes, and the full write lifecycle is proven **live** for **Disney** (Redeam hold → book → cancel) and **Universal** (SmartOrder place → cancel). **SeaWorld / United Parks** is contract-tested only — its sandbox (Discovery Cove) exposes no bookable availability.

Features
--------

[](#features)

- 🎢 **Three production parks supported**: Disney (Redeam), SeaWorld/United Parks (Redeam), Universal (SmartOrder)
- 🧩 **Driver-based resolution** via a Laravel `Manager` + `ThemePark` facade
- 🔐 **Auth handled**: Redeam `X-API-Key`/`X-API-Secret`; SmartOrder OAuth2 client-credentials with token caching and 401 self-heal
- ♻️ **Resilient transport**: idempotent reads retried on connection drops / 5xx; writes never retried (no double-booking)
- 📦 **Typed result objects**: `Supplier`, `Product`, `Rate`, `PriceSchedule`, `RatePriceSchedule`, `Availability`, `Hold`, `Booking`, …
- 🎫 **Voucher data exposed**: `tickets()` normalises each booking/order response into typed `TicketArtifact`s (redeemable identifier + format + validity); barcode/PDF rendering stays in your app
- 🧩 **Capability interfaces**: `SupportsHolds`, `SupportsEvents`, `ProvidesTicketArtifacts` — type-hint a capability instead of a concrete park
- 🧱 **No app coupling**: pure API integration; persistence, jobs, commission/margins and voucher *rendering* stay in your app
- 🧪 **Contract-tested** with `Http::fake()`, analysed with PHPStan, and exercised live against the provider sandboxes

Requirements
------------

[](#requirements)

- **PHP** 8.2, 8.3 or 8.4
- **Laravel** 12.x or 13.x (`illuminate/contracts ^12.0|^13.0`)

> Earlier releases targeted PHP 8.1 / Laravel 10–11. Support for those was dropped in 3.0.0 to stay on the security-patched Laravel line (≥ 12.60 / ≥ 13.10); see the [changelog](CHANGELOG.md).

Installation
------------

[](#installation)

```
composer require iabduul7/laravel-themepark-booking-adapters
```

Publish the config file:

```
php artisan vendor:publish --tag="themepark-adapters-config"
```

Add credentials to your `.env` (see [`.env.example`](.env.example) for the full list):

```
THEMEPARK_DEFAULT_PROVIDER=disney

# Disney (Redeam)
REDEAM_DISNEY_SUPPLIER_ID=your_disney_supplier_id
REDEAM_DISNEY_API_KEY=your_disney_api_key
REDEAM_DISNEY_API_SECRET=your_disney_api_secret

# SeaWorld / United Parks (Redeam) — supplier is passed per call
REDEAM_UNITED_PARKS_API_KEY=your_seaworld_api_key
REDEAM_UNITED_PARKS_API_SECRET=your_seaworld_api_secret

# Universal (SmartOrder)
SMARTORDER_CUSTOMER_ID=134853
SMARTORDER_APPROVED_SUFFIX=-2KNOW
SMARTORDER_CLIENT_USERNAME=your_client_username
SMARTORDER_CLIENT_SECRET=your_client_secret
```

Usage
-----

[](#usage)

### Resolving an adapter

[](#resolving-an-adapter)

```
use Iabduul7\ThemeParkAdapters\Facades\ThemePark;

$disney    = ThemePark::provider('disney');     // DisneyRedeamAdapter
$seaworld  = ThemePark::provider('seaworld');   // SeaWorldRedeamAdapter
$universal = ThemePark::provider('universal');  // UniversalSmartOrder2Adapter
```

You can also resolve via the container (`app('themepark')` / `ThemeParkManager`) or construct an adapter directly with a config array:

```
use Iabduul7\ThemeParkAdapters\Providers\Disney\DisneyRedeamAdapter;

$disney = new DisneyRedeamAdapter(config('themepark-adapters.providers.disney'));
```

### Disney (Redeam) — supplier fixed from config

[](#disney-redeam--supplier-fixed-from-config)

```
$products = $disney->getAllProducts();                                  // Product[]
$product  = $disney->getProduct('PRODUCT_ID');                          // Product
$rates    = $disney->getProductRates('PRODUCT_ID');                     // Rate[]
$schedule = $disney->getProductPricingSchedule('PRODUCT_ID', '2026-06-01', '2026-06-30'); // PriceSchedule
$rateSched = $disney->getProductRatePricingSchedule('PRODUCT_ID', '2026-06-01', '2026-06-30', 'RATE_ID');
$avail    = $disney->checkAvailabilities('PRODUCT_ID', '2026-06-01', '2026-06-30');

// Hold → book → cancel
$hold    = $disney->createNewHold(['hold' => ['items' => [/* … */]]]);
$booking = $disney->createNewBooking(['booking' => [/* … */]]);
$disney->deleteBooking('BOOKING_ID');

echo $product->getName();
echo $product->getId();
```

### SeaWorld / United Parks (Redeam) — supplier passed per call

[](#seaworld--united-parks-redeam--supplier-passed-per-call)

```
$products = $seaworld->getAllProducts('SUPPLIER_ID');
$product  = $seaworld->getProduct('SUPPLIER_ID', 'PRODUCT_ID');
$rates    = $seaworld->getProductRates('SUPPLIER_ID', 'PRODUCT_ID');
$schedule = $seaworld->getProductPricingSchedule('SUPPLIER_ID', 'PRODUCT_ID', '2026-06-01', '2026-06-30');
```

### Universal (SmartOrder)

[](#universal-smartorder)

```
$catalog = $universal->getAllProducts();                 // GET smartorder/MyProductCatalog
$months  = $universal->getAvailableMonths();             // next 12 months
$events  = $universal->findEvents([/* plu, dates, … */]); // POST smartorder/FindEvents
$order   = $universal->placeOrder([/* order lines, … */]);// POST smartorder/PlaceOrder

if ($universal->canCancelOrder(['ExternalOrderId' => 'E1'])) {
    $universal->cancelOrder(['ExternalOrderId' => 'E1']);
}
```

> The adapters mirror the method names and signatures of the production `LaravelRedeamForWaltDisney`, `LaravelRedeamForUnitedParks` and `SmartOrderClient` clients so they can serve as a drop-in replacement. A normalised, provider-agnostic interface is proposed for a future major version.

Capability interfaces
---------------------

[](#capability-interfaces)

- `Contracts\Capabilities\SupportsHolds` — `createNewHold`, `getHold`, `deleteHold`, `createNewBooking`, `getBooking`, `deleteBooking` (Redeam adapters)
- `Contracts\Capabilities\SupportsEvents` — `findEvents`, `placeOrder`, `getExistingOrder`, `canCancelOrder`, `cancelOrder` (SmartOrder adapter)

Type-hint these when you only need a capability rather than a specific park.

Optional building blocks
------------------------

[](#optional-building-blocks)

Business logic that is specific to a deployment is kept out of the core adapters and shipped as opt-in helpers under `Support/`:

- `Support\Redeam\OptionCodeResolver` — maps a Walt Disney World ticket name to its Redeam option code (also exposed on the Redeam adapters as `getOptionCode()` for drop-in parity).

Persistence (Eloquent models, migrations), queue/sync jobs, commission/operator margins and voucher *rendering* (barcode images, templates, PDF, delivery) are intentionally left to the consuming application. The package does expose the provider-native voucher **data** — `tickets()` normalises each booking/order response into typed `TicketArtifact`s (the redeemable identifier + format + validity).

Authentication
--------------

[](#authentication)

- **Redeam** — `X-API-Key` / `X-API-Secret` headers; GET is form-encoded, writes are JSON.
- **SmartOrder** — OAuth2 client-credentials (`/connect/token`, `scope=SmartOrder`); bearer token cached via a `TokenRepository` (set `SMARTORDER_TOKEN_CACHE=false` to always refresh, matching upstream); `customerId` injected into every request; transparent refresh-and-retry on `401`.

Error handling
--------------

[](#error-handling)

Any non-2xx provider response is raised as a `ThemeParkApiException` — reads and writes alike (a failure is never silently returned as an empty array). The exception carries the HTTP status via `getCode()` and the decoded provider error body via `getResponseData()`. Single-entity lookups raise a dedicated 404: `getProduct()` throws `productNotFound()`, `getExistingOrder()` throws `orderNotFound()`.

```
use Iabduul7\ThemeParkAdapters\Exceptions\ThemeParkApiException;

try {
    $product = ThemePark::provider('disney')->getProduct('PRODUCT_ID');
} catch (ThemeParkApiException $e) {
    $status = $e->getCode();          // e.g. 404, 422, 503
    $body   = $e->getResponseData();  // decoded provider error payload (nullable)
    report($e);
}
```

Idempotent reads are retried on connection drops / 5xx before the failure surfaces; writes are never retried (no double-booking).

Development
-----------

[](#development)

```
composer install
```

Testing
-------

[](#testing)

```
# Adapter contract tests (Http::fake)
composer test:adapters

# Static analysis
composer analyse

# Code style
composer format        # fix
composer format:check  # check only
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](.github/CONTRIBUTING.md) for details.

Credits
-------

[](#credits)

- [Abdullah](https://github.com/iabduul7)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

44

—

FairBetter than 90% of packages

Maintenance98

Actively maintained with recent releases

Popularity5

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity54

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 68% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~52 days

Total

5

Last Release

7d ago

Major Versions

v1.1.0 → v2.0.02026-06-21

v2.0.0 → v3.0.02026-06-21

v3.0.0 → v4.0.02026-06-28

PHP version history (2 changes)v1.0.0PHP ^8.1

v3.0.0PHP ^8.2

### Community

Maintainers

![](https://www.gravatar.com/avatar/dc056cb14243e9c095935dd51acd334fb0a7bdbec31472295930ea0489dc7527?d=identicon)[iabduul.7](/maintainers/iabduul.7)

---

Top Contributors

[![iabduul7](https://avatars.githubusercontent.com/u/24309704?v=4)](https://github.com/iabduul7 "iabduul7 (68 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (17 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (12 commits)")[![claude](https://avatars.githubusercontent.com/u/81847?v=4)](https://github.com/claude "claude (3 commits)")

---

Tags

laraveladaptersticketsbookingiabduul7theme-parkredeamsmartorder

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/iabduul7-laravel-themepark-booking-adapters/health.svg)

```
[![Health](https://phpackages.com/badges/iabduul7-laravel-themepark-booking-adapters/health.svg)](https://phpackages.com/packages/iabduul7-laravel-themepark-booking-adapters)
```

###  Alternatives

[dedoc/scramble

Automatic generation of API documentation for Laravel applications.

2.1k11.2M101](/packages/dedoc-scramble)[simplestats-io/laravel-client

Server-side analytics for Laravel that follows the full funnel from visit to registration to payment, attributed to the channel that drove it. Revenue, MRR, churn and ad-spend profit (ROAS/CAC) per channel. GDPR compliant, ad-blocker proof.

5022.0k](/packages/simplestats-io-laravel-client)[spatie/laravel-health

Monitor the health of a Laravel application

87512.0M167](/packages/spatie-laravel-health)[spatie/laravel-pdf

Create PDFs in Laravel apps

1.0k4.8M47](/packages/spatie-laravel-pdf)[defstudio/telegraph

A laravel facade to interact with Telegram Bots

816333.9k3](/packages/defstudio-telegraph)[codebar-ag/laravel-docuware

DocuWare integration with Laravel

1123.7k](/packages/codebar-ag-laravel-docuware)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
