PHPackages                             escalated-dev/escalated-laravel - 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. [Utility &amp; Helpers](/categories/utility)
4. /
5. escalated-dev/escalated-laravel

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

escalated-dev/escalated-laravel
===============================

An embeddable support ticket system for Laravel applications

0.6.0(1mo ago)19345—10%3MITPHPPHP ^8.2CI passing

Since Feb 8Pushed yesterday3 watchersCompare

[ Source](https://github.com/escalated-dev/escalated-laravel)[ Packagist](https://packagist.org/packages/escalated-dev/escalated-laravel)[ RSS](/packages/escalated-dev-escalated-laravel/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (11)Versions (23)Used By (0)

Escalated for Laravel
=====================

[](#escalated-for-laravel)

A full-featured, embeddable support ticket system for Laravel. Drop it into any app — get a complete helpdesk with SLA tracking, escalation rules, agent workflows, and a customer portal. No external services required.

**Three hosting modes.** Run entirely self-hosted, sync to a central cloud for multi-app visibility, or proxy everything to the cloud. Switch modes with a single config change.

Features
--------

[](#features)

- **Ticket lifecycle** — Create, assign, reply, resolve, close, reopen with configurable status transitions
- **SLA engine** — Per-priority response and resolution targets, business hours calculation, automatic breach detection
- **Escalation rules** — Condition-based rules that auto-escalate, reprioritize, reassign, or notify
- **Agent dashboard** — Ticket queue with filters, bulk actions, internal notes, canned responses
- **Customer portal** — Self-service ticket creation, replies, and status tracking
- **Admin panel** — Manage departments, SLA policies, escalation rules, tags, and view reports
- **File attachments** — Drag-and-drop uploads with configurable storage and size limits
- **Activity timeline** — Full audit log of every action on every ticket
- **Email notifications** — Configurable per-event notifications with webhook support
- **Department routing** — Organize agents into departments with auto-assignment (round-robin)
- **Tagging system** — Categorize tickets with colored tags
- **Guest tickets** — Anonymous ticket submission with magic-link access via guest token
- **Inbound email** — Create and reply to tickets via email (Mailgun, Postmark, AWS SES, IMAP)
- **Inertia.js + Vue 3 UI** — Shared frontend via [`@escalated-dev/escalated`](https://github.com/escalated-dev/escalated)

### v0.4.0 — Advanced Features

[](#v040--advanced-features)

- **Bulk actions** — Assign, change status/priority, add tags, close, or delete multiple tickets at once
- **Macros** — Reusable multi-step automations (set status + assign + add note in one click)
- **Ticket followers** — Agents follow tickets and receive the same notifications as the assignee
- **Satisfaction ratings** — 1-5 star CSAT ratings with optional comments after resolution
- **Pinned notes** — Pin important internal notes to the top of the ticket thread
- **Keyboard shortcuts** — Full keyboard navigation for power users
- **Quick filters** — One-click filter chips (My Tickets, Unassigned, Urgent, SLA Breaching)
- **Presence indicators** — See who else is viewing a ticket in real-time
- **Enhanced dashboard** — CSAT metrics, resolution times, SLA breach tracking

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

[](#requirements)

- PHP 8.2+
- Laravel 11.x or 12.x
- Node.js 18+ (for frontend assets)

Quick Start
-----------

[](#quick-start)

```
composer require escalated-dev/escalated-laravel
npm install @escalated-dev/escalated
php artisan escalated:install
php artisan migrate
```

The install command will offer to automatically configure your User model with the `Ticketable` interface and `HasTickets` trait. If you prefer to do this manually, or if you use a custom user model, add the following:

```
use Escalated\Laravel\Contracts\HasTickets;
use Escalated\Laravel\Contracts\Ticketable;

class User extends Authenticatable implements Ticketable
{
    use HasTickets;
}
```

Define authorization gates in a service provider:

```
use Illuminate\Support\Facades\Gate;

Gate::define('escalated-admin', fn ($user) => $user->is_admin);
Gate::define('escalated-agent', fn ($user) => $user->is_agent || $user->is_admin);
```

Visit `/support` — you're live.

Frontend Integration
--------------------

[](#frontend-integration)

Escalated ships a Vue component library and default pages via the [`@escalated-dev/escalated`](https://github.com/escalated-dev/escalated) npm package.

### 1. Tailwind Content

[](#1-tailwind-content)

Add the Escalated package to your Tailwind `content` config so its classes aren't purged:

```
// tailwind.config.js
content: [
    // ... your existing paths
    './node_modules/@escalated-dev/escalated/src/**/*.vue',
],
```

### 2. Page Resolver

[](#2-page-resolver)

Add the Escalated page resolver to your `app.ts`:

```
import { createInertiaApp } from '@inertiajs/vue3';
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';

const escalatedPages = import.meta.glob(
    '../../node_modules/@escalated-dev/escalated/src/pages/**/*.vue',
);

createInertiaApp({
    resolve: (name) => {
        if (name.startsWith('Escalated/')) {
            const path = name.replace('Escalated/', '');
            return resolvePageComponent(
                `../../node_modules/@escalated-dev/escalated/src/pages/${path}.vue`,
                escalatedPages,
            );
        }
        return resolvePageComponent(`./Pages/${name}.vue`,
            import.meta.glob('./Pages/**/*.vue'));
    },
    // ...
});
```

### 3. Theming (Optional)

[](#3-theming-optional)

Register the `EscalatedPlugin` to render Escalated pages inside your app's layout — no page duplication needed:

```
import { EscalatedPlugin } from '@escalated-dev/escalated';
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue';

createInertiaApp({
    setup({ el, App, props, plugin }) {
        createApp({ render: () => h(App, props) })
            .use(plugin)
            .use(EscalatedPlugin, {
                layout: AuthenticatedLayout,
            })
            .mount(el);
    },
});
```

Your layout component must accept a `#header` slot and a default slot. Escalated will render its sub-navigation in the header and page content in the default slot.

Without the plugin, Escalated uses its own standalone layout with a simple nav bar.

### CSS Custom Properties

[](#css-custom-properties)

Pass a `theme` option to customize colors and radii:

```
app.use(EscalatedPlugin, {
    layout: AuthenticatedLayout,
    theme: {
        primary: '#3b82f6',
        radius: '0.75rem',
    }
})
```

PropertyDefaultDescription`--esc-primary``#4f46e5`Primary action color`--esc-primary-hover`auto-darkenedPrimary hover color`--esc-radius``0.5rem`Border radius for inputs and buttons`--esc-radius-lg`auto-scaledBorder radius for cards and panels`--esc-font-family`inheritFont family override### Available Components

[](#available-components)

ComponentDescription`ActivityTimeline`Full audit log of ticket events`AssigneeSelect`Agent assignment dropdown`AttachmentList`File attachment display`FileDropzone`Drag-and-drop file upload`PriorityBadge`Priority level indicator`ReplyComposer`Rich text reply editor`ReplyThread`Chronological message thread`SlaTimer`SLA countdown display`StatsCard`Metric card for dashboards`StatusBadge`Ticket status indicator`TagSelect`Tag picker with colors`TicketFilters`Search and filter controls`TicketList`Paginated ticket table`TicketSidebar`Ticket metadata sidebar### Shared Inertia Props

[](#shared-inertia-props)

Escalated automatically shares data to all Inertia pages via `page.props.escalated`:

```
page.props.escalated = {
    prefix: 'support',     // Route prefix from config
    is_agent: true,        // Current user can access agent views
    is_admin: false,       // Current user can access admin views
}
```

Use these to conditionally show nav links or restrict UI elements.

Hosting Modes
-------------

[](#hosting-modes)

### Self-Hosted (default)

[](#self-hosted-default)

Everything stays in your database. No external calls. Full autonomy.

```
// config/escalated.php
'mode' => 'self-hosted',
```

### Synced

[](#synced)

Local database + automatic sync to `cloud.escalated.dev` for unified inbox across multiple apps. If the cloud is unreachable, your app keeps working — events queue and retry.

```
'mode' => 'synced',
'hosted' => [
    'api_url' => 'https://cloud.escalated.dev/api/v1',
    'api_key' => env('ESCALATED_API_KEY'),
],
```

### Cloud

[](#cloud)

All ticket data proxied to the cloud API. Your app handles auth and renders UI, but storage lives in the cloud. Supports multiple domains per API key.

```
'mode' => 'cloud',
```

All three modes share the same controllers, UI, and business logic. The driver pattern handles the rest.

Publishing Assets
-----------------

[](#publishing-assets)

```
# Email templates
php artisan vendor:publish --tag=escalated-views

# Config file
php artisan vendor:publish --tag=escalated-config

# Database migrations
php artisan vendor:publish --tag=escalated-migrations
```

Scheduling
----------

[](#scheduling)

Add these to your scheduler for SLA and escalation automation:

```
// app/Console/Kernel.php or routes/console.php
Schedule::command('escalated:check-sla')->everyMinute();
Schedule::command('escalated:evaluate-escalations')->everyFiveMinutes();
Schedule::command('escalated:close-resolved')->daily();
Schedule::command('escalated:purge-activities')->weekly();
Schedule::command('escalated:poll-imap')->everyMinute(); // Only if using IMAP adapter
```

Configuration
-------------

[](#configuration)

All config lives in `config/escalated.php`. Key options:

```
'mode' => 'self-hosted',              // self-hosted | synced | cloud
'user_model' => App\Models\User::class,
'table_prefix' => 'escalated_',
'default_priority' => 'medium',

'routes' => [
    'prefix' => 'support',
    'middleware' => ['web', 'auth'],
],

'tickets' => [
    'allow_customer_close' => true,
    'auto_close_resolved_after_days' => 7,
],

'sla' => [
    'enabled' => true,
    'business_hours_only' => false,
    'business_hours' => [
        'start' => '09:00',
        'end' => '17:00',
        'timezone' => 'UTC',
        'days' => [1, 2, 3, 4, 5],
    ],
],
```

See the [full configuration reference](docs/configuration.md).

Events
------

[](#events)

Every ticket action dispatches an event you can listen to:

EventWhen`TicketCreated`New ticket`TicketStatusChanged`Status transition`TicketAssigned`Agent assigned`ReplyCreated`Public reply added`InternalNoteAdded`Agent note added`SlaBreached`SLA deadline missed`TicketEscalated`Ticket escalated`TicketResolved`Ticket resolved`TicketClosed`Ticket closed```
use Escalated\Laravel\Events\TicketCreated;

Event::listen(TicketCreated::class, function ($event) {
    // $event->ticket
});
```

[Full events documentation →](docs/events.md)

Inbound Email
-------------

[](#inbound-email)

Escalated can create and reply to tickets from incoming emails. Supports **Mailgun**, **Postmark**, **AWS SES** webhooks, and **IMAP** polling as a fallback.

### How It Works

[](#how-it-works)

1. An external email service receives an email at your support address (e.g., `support@yourapp.com`)
2. The service forwards the email to your application via webhook (or IMAP polling fetches it)
3. Escalated normalizes the payload into an `InboundMessage` DTO via the adapter
4. The `InboundEmailService` processes the message:
    - **Thread matching**: checks the subject for a ticket reference (e.g., `[ESC-00001]`), then checks `In-Reply-To` / `References` headers against stored message IDs
    - **Match found**: adds a reply to the existing ticket; reopens the ticket if it was resolved or closed
    - **No match**: creates a new ticket — if the sender is a registered user they become the requester, otherwise a guest ticket is created
5. Every inbound email is logged to `escalated_inbound_emails` for audit

### Enable Inbound Email

[](#enable-inbound-email)

```
ESCALATED_INBOUND_EMAIL=true
ESCALATED_INBOUND_ADDRESS=support@yourapp.com
```

### Adapter Setup

[](#adapter-setup)

#### Mailgun

[](#mailgun)

```
ESCALATED_INBOUND_ADAPTER=mailgun
ESCALATED_MAILGUN_SIGNING_KEY=your-mailgun-signing-key
```

Configure a Mailgun Route to forward inbound emails to:

```
POST https://yourapp.com/support/inbound/mailgun

```

The signing key is in your Mailgun dashboard under **Settings &gt; API Keys &gt; HTTP Webhook Signing Key**. Requests are verified via HMAC-SHA256 signature.

#### Postmark

[](#postmark)

```
ESCALATED_INBOUND_ADAPTER=postmark
ESCALATED_POSTMARK_INBOUND_TOKEN=your-postmark-inbound-token
```

Configure an Inbound Webhook in your Postmark server settings pointing to:

```
POST https://yourapp.com/support/inbound/postmark

```

The token is sent in the `X-Postmark-Token` header and verified on each request.

#### AWS SES

[](#aws-ses)

```
ESCALATED_INBOUND_ADAPTER=ses
ESCALATED_SES_REGION=us-east-1
ESCALATED_SES_TOPIC_ARN=arn:aws:sns:us-east-1:123456789:your-topic
```

1. Configure SES to receive emails and publish to an SNS topic
2. Create an HTTPS subscription on the SNS topic pointing to: ```
    POST https://yourapp.com/support/inbound/ses

    ```
3. Escalated auto-confirms the SNS subscription and verifies message signatures using Amazon's certificate

#### IMAP (Fallback)

[](#imap-fallback)

For providers without webhook support, poll via IMAP:

```
ESCALATED_INBOUND_ADAPTER=imap
ESCALATED_IMAP_HOST=imap.gmail.com
ESCALATED_IMAP_PORT=993
ESCALATED_IMAP_ENCRYPTION=ssl
ESCALATED_IMAP_USERNAME=support@yourapp.com
ESCALATED_IMAP_PASSWORD=your-app-password
ESCALATED_IMAP_MAILBOX=INBOX
```

Schedule the poll command:

```
Schedule::command('escalated:poll-imap')->everyMinute();
```

### Webhook URL

[](#webhook-url)

```
POST /{prefix}/inbound/{adapter}

```

Where `{prefix}` is your configured route prefix (default: `support`) and `{adapter}` is `mailgun`, `postmark`, or `ses`. These routes use the `api` middleware (no CSRF, no auth).

### Processing Features

[](#processing-features)

- **Thread detection** via subject reference pattern (`[ESC-00001]`) and `In-Reply-To` / `References` headers
- **Guest tickets** for unknown senders — display name derived from email (e.g., `john.doe@example.com` → `John Doe`)
- **Subject sanitization** — strips `RE:`, `FW:`, `FWD:` prefixes (including stacked)
- **HTML fallback** — uses stripped HTML body when plain text is empty
- **Duplicate detection** — skips messages with duplicate `Message-ID` headers
- **Attachment handling** — stores attachments respecting `max_attachment_size_kb` and `max_attachments_per_reply`
- **Auto-reopen** — reopens resolved/closed tickets when a reply arrives via email
- **Audit logging** — every inbound email recorded in `escalated_inbound_emails` with status tracking

### Custom Adapter

[](#custom-adapter)

Implement the `InboundAdapter` interface:

```
use Escalated\Laravel\Mail\Adapters\InboundAdapter;
use Escalated\Laravel\Mail\InboundMessage;
use Illuminate\Http\Request;

class MyAdapter implements InboundAdapter
{
    public function parseRequest(Request $request): InboundMessage
    {
        return new InboundMessage(
            fromEmail: $request->input('from'),
            fromName: $request->input('name'),
            toEmail: $request->input('to'),
            subject: $request->input('subject'),
            bodyText: $request->input('text'),
            bodyHtml: $request->input('html'),
            messageId: $request->input('message_id'),
            inReplyTo: $request->input('in_reply_to'),
        );
    }

    public function verifyRequest(Request $request): bool
    {
        return $request->header('X-Secret') === config('services.my_adapter.secret');
    }
}
```

### Inbound Email Environment Variables

[](#inbound-email-environment-variables)

VariableDefaultDescription`ESCALATED_INBOUND_EMAIL``false`Enable inbound email`ESCALATED_INBOUND_ADAPTER``mailgun`Default adapter`ESCALATED_INBOUND_ADDRESS``support@example.com`Support email address`ESCALATED_MAILGUN_SIGNING_KEY`—Mailgun webhook signing key`ESCALATED_POSTMARK_INBOUND_TOKEN`—Postmark inbound token`ESCALATED_SES_REGION``us-east-1`AWS SES region`ESCALATED_SES_TOPIC_ARN`—AWS SNS topic ARN`ESCALATED_IMAP_HOST`—IMAP server hostname`ESCALATED_IMAP_PORT``993`IMAP server port`ESCALATED_IMAP_ENCRYPTION``ssl`IMAP encryption`ESCALATED_IMAP_USERNAME`—IMAP username`ESCALATED_IMAP_PASSWORD`—IMAP password`ESCALATED_IMAP_MAILBOX``INBOX`IMAP mailbox to pollRoutes
------

[](#routes)

RouteMethodDescription`/support`GETCustomer ticket list`/support/create`GETNew ticket form`/support/{ticket}`GETTicket detail`/support/guest/create`GETGuest ticket form`/support/guest/{token}`GETGuest ticket view (magic link)`/support/agent`GETAgent dashboard`/support/agent/tickets`GETAgent ticket queue`/support/agent/tickets/{ticket}`GETAgent ticket view`/support/admin/reports`GETAdmin reports`/support/admin/departments`GETDepartment management`/support/admin/sla-policies`GETSLA policy management`/support/admin/escalation-rules`GETEscalation rule management`/support/admin/tags`GETTag management`/support/admin/canned-responses`GETCanned response management`/support/inbound/mailgun`POSTMailgun inbound webhook`/support/inbound/postmark`POSTPostmark inbound webhook`/support/inbound/ses`POSTSES/SNS inbound webhook`/support/agent/tickets/bulk`POSTBulk actions on multiple tickets`/support/agent/tickets/{ticket}/follow`POSTFollow/unfollow a ticket`/support/agent/tickets/{ticket}/macro`POSTApply a macro to a ticket`/support/agent/tickets/{ticket}/presence`POSTUpdate presence on a ticket`/support/agent/tickets/{ticket}/pin/{reply}`POSTPin/unpin an internal note`/support/{ticket}/rate`POSTSubmit satisfaction ratingAll routes use the configurable prefix (default: `support`). Inbound webhook routes use the `api` middleware (no auth, no CSRF).

Plugin SDK
----------

[](#plugin-sdk)

Escalated supports framework-agnostic plugins built with the [Plugin SDK](https://github.com/escalated-dev/escalated-plugin-sdk). Plugins are written once in TypeScript and work across all Escalated backends.

### Installing Plugins

[](#installing-plugins)

The plugin bridge is built into `escalated-laravel` — no additional PHP package required. Install plugins and the runtime via npm:

```
npm install @escalated-dev/plugin-runtime
npm install @escalated-dev/plugin-slack
npm install @escalated-dev/plugin-jira
```

### Enabling SDK Plugins

[](#enabling-sdk-plugins)

```
// config/escalated.php
'plugins' => [
    'enabled'     => true,
    'sdk_enabled' => true,  // Enable the Node.js bridge
],
```

### How It Works

[](#how-it-works-1)

SDK plugins run as a Node.js subprocess managed by `@escalated-dev/plugin-runtime`, communicating with Laravel over JSON-RPC 2.0 via stdio. The `escalated_do_action()` and `escalated_apply_filters()` helpers dual-dispatch to both legacy PHP plugins and new SDK plugins simultaneously — no changes to existing hook call sites.

### Building Your Own Plugin

[](#building-your-own-plugin)

```
import { definePlugin } from '@escalated-dev/plugin-sdk'

export default definePlugin({
  name: 'my-plugin',
  version: '1.0.0',
  actions: {
    'ticket.created': async (event, ctx) => {
      ctx.log.info('New ticket!', event)
    },
  },
})
```

### Resources

[](#resources)

- [Plugin SDK](https://github.com/escalated-dev/escalated-plugin-sdk) — TypeScript SDK for building plugins
- [Plugin Runtime](https://github.com/escalated-dev/escalated-plugin-runtime) — Runtime host for plugins
- [Plugin Development Guide](https://github.com/escalated-dev/escalated-docs) — Full documentation

See the detailed [Plugin Bridge](#plugin-bridge-sdk-plugins) section below for the full architecture, auto-generated routes, dual dispatch, and store documentation.

Plugin Bridge (SDK Plugins)
---------------------------

[](#plugin-bridge-sdk-plugins)

Escalated supports a second generation of plugins written in TypeScript using the `@escalated-dev/plugin-sdk`. These plugins run as a Node.js subprocess managed by `@escalated-dev/plugin-runtime` and communicate with Laravel over JSON-RPC 2.0 via stdio.

### How It Works

[](#how-it-works-2)

```
Laravel (PHP)                     Plugin Runtime (Node.js)
┌──────────────────────┐  stdio   ┌──────────────────────┐
│ PluginBridge         │◄────────►│ @escalated-dev/       │
│  - spawns subprocess │  JSON-   │   plugin-runtime      │
│  - dispatches hooks  │  RPC 2.0 │  ┌────────────────┐   │
│  - handles ctx.*     │          │  │ Slack Plugin    │   │
│  - mounts routes     │          │  │ Jira Plugin     │   │
└──────────────────────┘          │  │ ...             │   │
                                  │  └────────────────┘   │
                                  └──────────────────────┘

```

The bridge spawns the runtime **lazily** on the first hook dispatch and keeps the process alive across requests (one long-lived subprocess per PHP-FPM worker). If the process crashes it is automatically restarted with exponential backoff.

### Requirements

[](#requirements-1)

- Node.js 18+
- `@escalated-dev/plugin-runtime` installed in your project:

```
npm install @escalated-dev/plugin-runtime
```

Install any SDK plugins the same way:

```
npm install @escalated-dev/plugin-slack @escalated-dev/plugin-jira
```

### Startup Sequence

[](#startup-sequence)

1. `EscalatedServiceProvider::boot()` calls `$bridge->boot()`
2. Bridge spawns `node node_modules/@escalated-dev/plugin-runtime/dist/index.js`
3. Protocol handshake confirms version compatibility
4. Bridge fetches the plugin manifest (pages, hooks, endpoints, webhooks)
5. Routes are registered in Laravel for plugin pages, API endpoints, and webhooks
6. Runtime is ready to receive hook dispatches

### Auto-generated Routes

[](#auto-generated-routes)

For each installed SDK plugin the bridge automatically registers:

CategoryURL PatternAuthAdmin pages`{prefix}/admin/plugins/{plugin}/{route}`AdminData endpoints`{prefix}/api/plugins/{plugin}/{path}`AdminWebhook endpoints`{prefix}/webhooks/plugins/{plugin}/{path}`None### Dual Dispatch (Backward Compatibility)

[](#dual-dispatch-backward-compatibility)

The existing `escalated_do_action()` and `escalated_apply_filters()` helper functions dispatch hooks to **both** old PHP plugins and new SDK plugins simultaneously. No changes are required to existing hook call sites.

```
// This automatically dispatches to PHP plugins AND SDK plugins:
escalated_do_action('ticket.created', $ticket->toArray());

// Same for filters:
$channels = escalated_apply_filters('notification.channels', []);
```

### Plugin Store

[](#plugin-store)

SDK plugins can persist data using `ctx.store`. This is backed by the `escalated_plugin_store` table:

```
php artisan vendor:publish --tag=escalated-migrations
php artisan migrate
```

### Configuration

[](#configuration-1)

```
// config/escalated.php
'plugins' => [
    'enabled'         => true,
    'sdk_enabled'     => true,      // Enable the Node.js bridge
    'runtime_command' => 'node node_modules/@escalated-dev/plugin-runtime/dist/index.js',
    'runtime_cwd'     => base_path(), // Working directory for the subprocess
],
```

### Writing SDK Plugins

[](#writing-sdk-plugins)

See the [`@escalated-dev/plugin-sdk`](https://github.com/escalated-dev/plugin-sdk) package for the full TypeScript authoring API. A minimal plugin looks like:

```
import { definePlugin } from '@escalated-dev/plugin-sdk'

export default definePlugin({
  name: 'my-plugin',
  version: '1.0.0',

  actions: {
    'ticket.created': async (event, ctx) => {
      const config = await ctx.config.all()
      // ... do something
    },
  },

  endpoints: {
    'GET /settings': { capability: 'manage_settings', handler: async (ctx) => {
      return await ctx.config.all()
    }},
  },
})
```

Documentation
-------------

[](#documentation)

- [Installation](docs/installation.md)
- [Configuration](docs/configuration.md)
- [Customization](docs/customization.md)
- [Events](docs/events.md)
- [SLA Policies](docs/sla-policies.md)
- [Escalation Rules](docs/escalation-rules.md)
- [Hosting Modes](docs/hosting-modes.md)

Testing
-------

[](#testing)

```
composer install
vendor/bin/pest
```

Also Available For
------------------

[](#also-available-for)

- **[Escalated for Laravel](https://github.com/escalated-dev/escalated-laravel)** — Laravel Composer package (you are here)
- **[Escalated for Rails](https://github.com/escalated-dev/escalated-rails)** — Ruby on Rails engine
- **[Escalated for Django](https://github.com/escalated-dev/escalated-django)** — Django reusable app
- **[Escalated for AdonisJS](https://github.com/escalated-dev/escalated-adonis)** — AdonisJS v6 package
- **[Escalated for Filament](https://github.com/escalated-dev/escalated-filament)** — Filament v3 admin panel plugin
- **[Shared Frontend](https://github.com/escalated-dev/escalated)** — Vue 3 + Inertia.js UI components

Same architecture, same Vue UI, same three hosting modes — for every major backend framework.

License
-------

[](#license)

MIT

###  Health Score

47

—

FairBetter than 94% of packages

Maintenance97

Actively maintained with recent releases

Popularity26

Limited adoption so far

Community12

Small or concentrated contributor base

Maturity45

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 96.2% 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 ~1 days

Total

13

Last Release

32d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/1f1e8418623e51236a1fd63d1da722d2b15a8a8b067b10d520580fd3e9a6e509?d=identicon)[MatthewGross](/maintainers/MatthewGross)

---

Top Contributors

[![mpge](https://avatars.githubusercontent.com/u/3311227?v=4)](https://github.com/mpge "mpge (102 commits)")[![marufmax](https://avatars.githubusercontent.com/u/7222229?v=4)](https://github.com/marufmax "marufmax (4 commits)")

---

Tags

laravellaravelsupportticketshelpdeskcustomer-support

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/escalated-dev-escalated-laravel/health.svg)

```
[![Health](https://phpackages.com/badges/escalated-dev-escalated-laravel/health.svg)](https://phpackages.com/packages/escalated-dev-escalated-laravel)
```

###  Alternatives

[binshops/laravel-ticket

A simple ticketing system for Laravel 5.1 – 5.8 and 6.\* - 7.\* - 8.\* - 9.\* - 10.\* -which integrates smoothly with Laravel default users and auth system

261.0k](/packages/binshops-laravel-ticket)

PHPackages © 2026

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