Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Intercom Laravel Package

jeffersongoncalves/laravel-intercom

A Laravel package that integrates Intercom into your application, offering configuration and convenient access to Intercom’s API for managing contacts, conversations, and messaging.

View on GitHub
Deep Wiki
Context7

Getting Started

This is the initial 1.0.0 release, so treat it as a greenfield integration rather than an upgrade — there is no migration surface, but also no battle-testing yet. Pin the exact version in composer.json until you've validated the endpoints you depend on.

Minimal setup

  1. composer require the package, then publish its config (php artisan vendor:publish --tag=intercom-config or similar — check the README for the exact tag).
  2. Add INTERCOM_TOKEN to .env and confirm the config file reads from it rather than hardcoding. Add the token to your deploy secrets before running config:cache.
  3. If your workspace is hosted outside the US, set the regional base URL (api.eu.intercom.io / api.au.intercom.io). Getting this wrong produces confusing 401s that look like a bad token.
  4. Resolve the client from the container (facade or constructor injection) rather than new-ing anything, so you can swap it in tests.

Where to look first

  • The config file — it tells you what's actually configurable (token, region, API version, timeout, retry policy) versus what's hardcoded.
  • The resource classes/enum of supported areas: contacts, conversations, messages, companies, tags, articles, admins, events. That list is your map of what the package does and, by omission, what it doesn't (no webhooks, no data export, no bulk endpoints mentioned).
  • Whether it wraps the official intercom/intercom-php SDK or speaks raw HTTP via Laravel's Http client. This single fact determines your testing and error-handling strategy.

First use case

Identify a user the moment they register or log in: contacts()->create() (or upsert) with a stable external_id (your users.id), plus email, name, and a signed-up timestamp as a custom attribute. Everything else in Intercom — messaging, segmentation, support context — depends on that identity being right, so ship this first and verify it in the Intercom UI before building on top.

Implementation Patterns

Keep the API out of the request cycle. Nearly every meaningful call here is a network hop to a third party. Fire contact sync, event tracking, and tagging from queued listeners on your User model (Registered, Updated, LoggedIn) with ->afterCommit() so you never sync a user that rolled back. Wrap the job in a retry policy and a failed() handler that logs rather than throwing into the queue's dead-letter path permanently.

Wrap the package in a thin domain service. Inject the client into something like App\Services\Intercom\CustomerSync that exposes identify(User $user) and track(User $user, string $event, array $meta). Your application code talks to your service, not to the vendor package. When the package changes method signatures between minor versions — likely, at 1.0.0 — you edit one file instead of forty.

The identify/update pattern is the workhorse. Use external_id as the canonical key and treat email as a mutable attribute. Intercom resolves identity on both, so if you ever set email as the primary key and a user changes it, you'll create duplicates that are painful to merge.

Events drive lifecycle messaging. events()->create() with a name and metadata is how you trigger onboarding sequences and re-engagement without shipping new code. Define a small enum of event names in your codebase and reject free-form strings at the call site — otherwise marketing will invent names your dashboard can't aggregate.

Tags are your segmentation primitive. Attach/detach on state transitions (plan tier, trial status, beta flag). Prefer a fixed tag vocabulary over dynamic strings like plan-{id}; Intercom's tag list becomes unusable fast.

B2B: companies before contacts. Create the company, then attach the contact with a job title and role. Do this in the same queued job as the contact sync, ordered, so a contact never appears unattached in a way support staff will misread.

Conversations and messages are admin-initiated, not user-initiated. messages()->create() outbound from an admin (admin_id required) is the typical path for in-app announcements and email follow-ups; message_type matters (inapp vs email) and the two behave very differently in the UI. Reading conversations is a support-dashboard concern — paginate with the cursor and cache aggressively, because the list endpoints are the slowest thing in the API.

Articles and help center are useful for building a self-serve "was this helpful" surface inside your app, but they're read-mostly and low-risk — a good place to start if you want a low-consequence first integration.

Testing pattern: bind a fake implementation of your own IntercomClient interface in the container for feature tests. If the package uses Laravel's HTTP client under the hood, Http::fake() gives you end-to-end coverage cheaply — assert on the request body for external_id and attributes rather than on the package's return objects.

Gotchas and Tips

  • Pin the API version. Intercom versions its REST API via an Intercom-Version header, and behaviour changes between versions (conversations especially). If the package hardcodes a version, note it; if it's configurable, set it explicitly and don't rely on the default drifting under you.
  • There is no sandbox workspace. You get dev and production. A misconfigured INTERCOM_TOKEN in local .env will happily create real contacts and fire real customer emails. Use a separate dev workspace, and consider a hard guard that throws in non-production unless an explicit opt-in env var is set.
  • Rate limits are real and asymmetric. Standard endpoints allow generous throughput; search and list endpoints are much tighter. Respect X-RateLimit-Remaining and back off on 429 with jitter rather than fixed sleeps. A backfill script over 50k users will hit this — chunk it and make it resumable.
  • Search is eventually consistent. A contact created seconds ago may not appear in contacts()->search(). Never use search to verify a write; fetch by id or external_id instead. This bites people writing "did the sync work?" assertions.
  • Don't let an Intercom outage break signup. Wrap every call in a try/catch at the job or service boundary and fail open. The package will throw on 4xx/5xx; decide per call site whether that's fatal (no — it almost never is).
  • Set aggressive timeouts. Default HTTP timeouts of 30s+ on a queue worker will silently starve your pool during an Intercom incident. 5–10s connect/total is plenty.
  • Error responses are structured. Intercom returns {type: "error.list", errors: [{code, message}]}. Map code values (not_found, parameter_invalid, unauthorized) rather than string-matching messages — messages change.
  • config:cache will freeze your token. Almost every "works locally, 401s in staging" report for packages like this is a cached config from a build step that ran before the env var existed.
  • Deletion is not archive. Intercom's delete is destructive and GDPR-relevant. For churned users, archive or tag — reserve delete for actual erasure requests, and know that re-creating a deleted contact with the same external_id does not resurrect their history.
  • Extension points to check before forking: whether the underlying HTTP client is bound as a singleton you can swap, whether requests are dispatched through a middleware/pipeline, and whether there are events emitted on request/response you can listen to for logging and metrics. If none exist, your service wrapper is the extension point — add timing and structured logging there from day one.
  • Watch the repo for 1.0.x releases. At initial release, expect method signatures and config keys to move. Read the diff before every bump; treat 1.x minor versions as potentially breaking until the package demonstrates otherwise.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core