Every state change dispatches a plain event in RoundlyConsulting\Teams\Events, so you can send notifications, write audit logs or sync other systems without forking:
| Event | Properties | Fired when |
|---|---|---|
TeamMemberAdded | $member | A new membership is created. |
TeamMemberRoleChanged | $member, $previousRole | A member’s role changes. |
TeamMemberDeleted | $member | A membership is removed (soft-deleted). |
InviteCreated | $invite | An invite is created. |
InviteAccepted | $invite, $member | An invite is accepted. |
InviteResent | $invite | An invite’s code and expiry are rotated. |
InviteRevoked | $invite | An invite is revoked. |
TeamOwnershipTransferred | $team, $previousOwner, $newOwner | Ownership is transferred. |
JoinRequestCreated | $joinRequest | A user requests to join. |
JoinRequestApproved | $joinRequest | A request is approved (also on auto-approval). |
JoinRequestDenied | $joinRequest | A request is denied. |
JoinRequestExpired | $request | A pending request auto-declines on expiry. |
MembershipExpiringSoon | $member | A membership lapses within the report window (--notify). |
MembershipExpired | $member | An expired membership is pruned — by teams:members:prune, Teams::members()->prune() or model:prune. |
Note the property name: JoinRequestExpired carries $request, the other join-request events carry $joinRequest.
use Illuminate\Support\Facades\Event;
use RoundlyConsulting\Teams\Events\InviteAccepted;
use RoundlyConsulting\Teams\Events\TeamMemberRoleChanged;
Event::listen(function (InviteAccepted $event): void {
logger()->info('Invite accepted', [
'invite' => $event->invite->id,
'member' => $event->member->id,
]);
});
Event::listen(function (TeamMemberRoleChanged $event): void {
// $event->member->role is the new role; $event->previousRole the old one
});Notification bridge
Publish teams-stubs to get App\Listeners\TeamEventSubscriber — a queued subscriber with handlers for TeamMemberAdded, TeamMemberRoleChanged and InviteCreated. Drop your own Notification classes into its handlers; it runs on notifications.queue_connection, falling back to queue.default. Register it:
// app/Providers/AppServiceProvider.php → boot()
use App\Listeners\TeamEventSubscriber;
use Illuminate\Support\Facades\Event;
Event::subscribe(TeamEventSubscriber::class);Extend its subscribe() map to react to any other event. The package ships the wiring; your app owns the content.
Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.