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 Line Sdk Laravel Package

revolution/laravel-line-sdk

A Laravel wrapper for the LINE Messaging API that streamlines building LINE bots, handling webhooks, sending rich messages, and integrating LINE Login into PHP applications with familiar Laravel conventions.

View on GitHub
Deep Wiki
Context7

Getting Started

The package is a thin Laravel wrapper around the official linecorp/line-bot-sdk PHP SDK: it registers the Messaging API client(s) in the container, reads credentials from a published config file, and exposes a facade. Because it is thin, the fastest path to understanding it is to read the service provider in vendor/revolution/laravel-line-sdk/src/ — it tells you exactly which bindings and facade methods exist for the SDK version it pins.

1. Install

composer require revolution/laravel-line-sdk

Laravel auto-discovery registers the service provider. Publish the config (adjust the provider class to whatever the package ships):

php artisan vendor:publish --provider="Revolution\Line\LineServiceProvider"

2. Configure credentials

Get these from the LINE Developers Console → your Messaging API channel → Basic settings / Messaging API tab:

LINE_CHANNEL_ID=1655xxxxxx
LINE_CHANNEL_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
LINE_CHANNEL_ACCESS_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

The channel secret is only needed for webhook signature verification; the channel access token is needed for every outbound API call. Keep both in .env — never in config/line.php committed to git.

3. First use case: an echo webhook

Add a route (exempt from CSRF), verify the signature, and reply:

// routes/api.php
Route::post('/line/webhook', LineWebhookController::class);
public function __invoke(Request $request)
{
    $events = Line::parseEvent($request);   // verifies X-Line-Signature internally
    foreach ($events as $event) {
        if ($event->getType() !== 'message') {
            continue;
        }
        Line::replyText($event->getReplyToken(), 'You said: ' . $event->getMessage()->getText());
    }
    return response()->noContent();
}

If the facade does not expose helpers like parseEvent/replyText, drop one level down and use the SDK objects it resolves: build a LINEBot (or the v8 MessagingApiApi + MessagingApiBlobApi) from the container and call replyMessage/pushMessage with SDK message builders. That is also the escape hatch for any endpoint the wrapper hasn't wrapped.

4. Verify it works

Click Verify in the LINE console's Messaging API → Webhook settings — LINE sends an empty events array, so a clean 200 with no events is a pass. Then add your bot as a friend via its QR code and send it a message.

Implementation Patterns

Reply vs. push — pick deliberately

Reply Push
Token replyToken from the event userId / groupId / roomId
Validity Single use, ~1 minute Any time
Cost Free, not counted against quota Counts against monthly message quota
Use for Immediate response to a webhook event Notifications, reminders, broadcasts, queued jobs

Practical rule: in the webhook controller, always answer with a reply message so the interaction feels instant and costs nothing; use push from jobs, scheduled commands, and Laravel notifications.

Keep the webhook fast, do the work in a job

LINE retries any webhook that doesn't return 2xx within a few seconds, which produces duplicate handling. A good pattern is: verify signature → push the event onto a queue → return 200 → process in a job.

foreach (Line::parseEvent($request) as $event) {
    ProcessLineEvent::dispatch($event->toArray());
}
return response()->noContent();

Keep $event serialised as an array (SDK objects are not always cleanly serialisable) and rebuild the SDK object in the job if needed.

Model LINE users as first-class records

Link line_user_id to your users table (or a separate line_profiles table for users who only interact with the bot). Store the displayName, pictureUrl, and statusMessage from getProfile once, and refresh on demand — group and room members cannot be resolved to a profile at all.

$profile = Line::getProfile($event->getSource()->getUserId());

LineUser::updateOrCreate(
    ['line_user_id' => $profile->getUserId()],
    ['display_name' => $profile->getDisplayName(), 'avatar' => $profile->getPictureUrl()],
);

Use it as a notification channel

This is the highest-leverage day-to-day pattern: a custom Laravel notification channel means your existing Notification classes can fan out to LINE like they do to mail or Slack.

class LineChannel
{
    public function send($notifiable, Notification $notification): void
    {
        if (! $userId = $notifiable->routeNotificationFor('line')) {
            return;
        }
        Line::pushText($userId, $notification->toLine($notifiable)->text);
    }
}

Then $user->notify(new InvoiceOverdue($invoice)) with via() returning [LineChannel::class] (or 'line' if you register a channel alias). Queue the notification and you get retry/backoff for free.

Build messages in dedicated classes

Inline message construction gets unreadable fast, especially for Flex Messages, whose payload is deeply nested JSON. Put each message shape in app/Line/Messages/ with a toArray() method, and keep reusable Flex templates in resources/line/ as JSON files you json_decode and inject values into. Test them by asserting the array structure rather than string-matching JSON.

Quick replies, imagemaps, and Flex carousels are all just extra keys on the message array — the builder in the package is a convenience, not a constraint, so you can always hand the SDK a raw array.

Broadcasts and rich menus

For bulk sends, chunk recipients, respect the SDK's per-request message limit, and throttle. Use broadcast for "everyone who follows the bot" and multicast for a known list (up to 500 IDs per call). Rich menu create/upload/set-default is a three-call sequence — wrap it in an artisan command so it is reproducible across environments.

Testing

The wrapper resolves concrete SDK clients, so mock at the boundary: bind a fake into the container, or use the facade's shouldReceive if it's a real facade. Do not rely on Http::fake() — the LINE SDK uses its own HTTP client, not Laravel's, so Http::fake() will not intercept it and you'll send real requests in tests.

Line::shouldReceive('replyText')->once()->with('token123', 'hello');

Gotchas and Tips

  • Signature verification needs the raw body. Use $request->getContent(), not $request->all(). Any middleware that re-encodes or trims the payload (or a proxy like some load balancers) will invalidate the HMAC and every event will fail verification.
  • Exempt the webhook from CSRF. It lives in routes/web.php in many tutorials; either move it to api.php or add the path to VerifyCsrfToken::$except.
  • Webhook URLs must be public HTTPS with a valid certificate. Self-signed certs and http:// are rejected. Use ngrok/Expose for local development and point the console at the tunnel.
  • Reply tokens are single-use and expire in about a minute. Never persist them to a database or queue them for later; if it's not instant, use push.
  • Return 200 quickly or get duplicate events. LINE retries non-2xx responses. Idempotency guards on your side (dedupe on webhook event ID) are worth having.
  • The webhook "Verify" button sends an empty events array. A crash on empty input is the single most common first-deploy failure — guard your loop.
  • The package's last release is from January 2022. Check the pinned linecorp/line-bot-sdk version against current PHP 8.2/8.3 and Laravel 10/11. If composer blocks install, either pin an older Laravel, fork the provider, or — realistically — copy the ~50-line service provider into app/Providers and bind the SDK yourself. The wrapper adds little you can't reproduce, and the official SDK is the part that actually matters.
  • Token type matters. Channel access token v2.1 is short-lived and must be refreshed; long-lived tokens don't expire but must be reissued manually. Pick one and document it, because a silently expired token looks identical to a permissions error.
  • Group, room, and multi-bot user IDs are not interchangeable. The same human has a different userId per bot, and group members' profiles are not retrievable. Don't assume a line_user_id is globally unique across your channels.
  • Config caching bites runtime overrides. If you try to switch channel credentials at runtime (multi-tenant, multiple bots), a singleton bound with the resolved config won't pick it up. Bind a fresh client per tenant rather than mutating config.
  • Mind the quota and 429s. Push messages consume your plan's monthly allowance; rate-limited or quota-exceeded calls surface as HTTP 429. Wrap push calls in retry-with-backoff, but never blindly retry 4xx errors other than 429.
  • Content download is a separate API object from the messaging one (blob vs. messaging). If you handle image/file messages, make sure the wrapper binds both, or resolve the blob client yourself.
  • Text with emoji and mentions: LINE's newer text object (textV2 with substitution) replaces the older emoji placeholder syntax; if you're copy-pasting older tutorials the $ emoji indices won't render.
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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core