laravel-notification-channels/intercom
Laravel Notification Channels Intercom adds an Intercom channel to Laravel notifications, letting you send messages and updates to users through Intercom from your existing notification classes. Requires Laravel and an Intercom access token.
This is a thin bridge between Laravel's notification system and Intercom's PHP SDK: it lets an existing Notification class fan out to Intercom (in-app messages, emails, and contact/event updates) using the same via() / toX() contract you already use for mail, SMS, and database notifications.
Version 1.4.0 added Laravel 9 support (PR #14), so you can use the channel on Laravel 9 if your other dependencies allow. There are no new features in this release — just compatibility and style fixes.
Minimal steps:
composer require laravel-notification-channels/intercom
php artisan vendor:publish --provider="NotificationChannels\Intercom\IntercomServiceProvider"
Set the token in .env (usually INTERCOM_TOKEN) and pick the config file that gets published (config/intercom.php). Before wiring anything into a real notification, read three files in the vendor directory, in this order:
src/IntercomChannel.php — shows exactly how the notification is dispatched and what exceptions bubble up.src/IntercomMessage.php — the fluent message builder; this is the API you will actually spend time with.config/intercom.php — token, and (critically) any base-URI/region setting.First use case: a transactional in-app message to a known Intercom contact when something happens in your app (invoice paid, seat assigned, invite accepted).
use Illuminate\Notifications\Notification;
use NotificationChannels\Intercom\IntercomChannel;
use NotificationChannels\Intercom\IntercomMessage;
class InvoicePaid extends Notification
{
public function via($notifiable): array
{
return [IntercomChannel::class];
}
public function toIntercom($notifiable)
{
return IntercomMessage::create()
->to($notifiable->intercom_id) // contact id, not Laravel user id
->withTitle('Invoice paid')
->withBody('Thanks — your receipt is ready.');
}
}
If the fluent method names differ in your pinned version, mirror what IntercomMessage exposes; the pattern is stable even when method names drift.
Resolve the Intercom identity on the notifiable, not in the notification. Add a routeNotificationForIntercom() method (or an intercom_id attribute) so the channel and message builder don't need to guess between email and contact id:
public function routeNotificationForIntercom()
{
return $this->intercom_id;
}
Separate "notify a human" from "update the contact record." The package is a notification channel; contact attributes, tags, and events are better handled in a small service or job that calls the Intercom client directly. Don't try to make a notification do contact sync — it gets messy fast and you lose idempotency.
Queue everything. Add implements ShouldQueue to the notification (or use Notification::route(...)->notify() from a job). Intercom's API is rate-limited and network-bound; a synchronous call inside a web request is a latency and failure liability.
Template vs. inline body. For anything user-facing and recurring, prefer an Intercom-side template (so copy changes don't require a deploy) and pass variables from toIntercom(). Keep the Laravel notification responsible for when and to whom, and Intercom responsible for what it says.
Admin sender. Admin-initiated messages typically require a from admin id. Put it in config (intercom.admin_id) and inject it in the message builder rather than hardcoding it in every notification.
Testing. Use Notification::fake() and assert on the notification class, not the Intercom payload. For the payload shape, unit-test the builder in isolation:
Notification::fake();
$user->notify(new InvoicePaid($invoice));
Notification::assertSentTo($user, InvoicePaid::class);
Compose with other channels. Intercom as an additional channel alongside mail and database is the sweet spot — Intercom for in-app/retention messaging, mail for the legally-required receipt.
composer.json, and keep the Intercom calls behind one or two classes so a swap (or a direct HTTP client) is a localized change.composer.json before adopting — the release notes only mention Laravel 9. Check the constraint (illuminate/*) rather than assuming forward compatibility.api.intercom.io vs api.eu.intercom.io vs api.au.intercom.io). If the config doesn't expose a base URI, you'll need to bind a configured IntercomClient yourself in a service provider. This is the most common "it works locally, 401s in prod" cause.GET /me before debugging the channel.intercom_id is null, decide explicitly: skip the notification, or create the contact first. Silent no-ops are the usual failure mode.retryUntil/backoff, and be aware that a burst of notifications (e.g., a mass announcement) will hit limits fast — chunk it.php artisan config:cache after any .env change to the token; a stale cached config is a classic 15-minute debugging detour.IntercomClient in the container for region/proxy/mocking; macro the message class if you need a house style; and swap the channel's message class if you want a domain-specific builder without forking the package.IntercomChannel and IntercomMessage source before you build on it — it's faster than guessing method names from memory. The 1.4.0 changelog adds nothing to the docs, so the README remains the only reference.How can I help you explore Laravel packages today?