whilesmart / eloquent-conversations
Polymorphic conversations (chatrooms) with messages and participants for Laravel applications.
Package info
github.com/whilesmartphp/eloquent-conversations
pkg:composer/whilesmart/eloquent-conversations
Requires
- php: ^8.2
- laravel/framework: ^11.0|^12.0
- whilesmart/eloquent-owner-access: ^1.0
Requires (Dev)
- fakerphp/faker: ^1.24
- laravel/pint: ^1.22
- orchestra/testbench: ^9.0|^10.0
This package is auto-updated.
Last update: 2026-08-18 21:28:44 UTC
README
Polymorphic conversations (chatrooms) with messages and participants for Laravel applications.
A conversation is a room. Any party can join as a participant (a customer Contact, a User/agent, a bot, the system) and any party can post a message. A conversation can optionally be about something (a support request, an order, a deal) through a polymorphic conversable link, and every conversation is scoped to a polymorphic owner (your tenant) via whilesmart/eloquent-owner-access.
The package is channel-agnostic. It stores and serves conversations, messages, and participants and emits domain events. Delivering a message over WhatsApp, email, or SMS is the host application's job: listen for MessageCreated and dispatch through your own driver.
Install
composer require whilesmart/eloquent-conversations php artisan migrate
Concepts
| Model | What it is |
|---|---|
Conversation |
The room. Has an owner (tenant), an optional conversable (what it is about), a channel, a status, and last_message_at. |
Message |
A single message in a room. Has a polymorphic author (any party), a direction (inbound/outbound), a type (text/note/event), body, attachments, and an external_id for provider dedupe. |
ConversationParticipant |
A member of the room. Polymorphic participant, a role, and last_read_at for read receipts. |
API
All routes are registered under the configured prefix (default api) and middleware (default ['api','auth:sanctum']). Set conversations.register_routes to false to supply your own controllers.
| Method | Path | Action |
|---|---|---|
| GET | /conversations |
List (owner-scoped; filter by status, channel, conversable_*) |
| POST | /conversations |
Create a room |
| GET | /conversations/{conversation} |
Show with messages + participants |
| PUT | /conversations/{conversation} |
Update (status, subject, ...) |
| DELETE | /conversations/{conversation} |
Soft delete |
| GET | /conversations/{conversation}/messages |
List the thread |
| POST | /conversations/{conversation}/messages |
Post a message |
| GET | /conversations/{conversation}/participants |
List participants |
| POST | /conversations/{conversation}/participants |
Add a participant (idempotent) |
| POST | /conversations/{conversation}/read |
Mark read for the calling user |
Traits
use Whilesmart\Conversations\Traits\HasConversations; // on a Request, Order, Deal... use Whilesmart\Conversations\Traits\ParticipatesInConversations; // on a User, Contact...
Events
ConversationCreated, MessageCreated, ParticipantJoined. These are plain events (not broadcast). Bridge them in your app to broadcast over websockets or trigger channel delivery.
Configuration
Publish the config to override models, table names, UUID mode, and route registration:
php artisan vendor:publish --tag=conversations-config
Testing
composer test
composer pint:test