line-bot-sdk-python: routing LINE webhook events with WebhookHandler and MessagingApi
LINE Messaging API SDK for Python
At a glance
- What is it?
- line-bot-sdk-python is the official Python SDK for LINE's Messaging API, providing a webhook handler and a generated API client to build bots in Python. The README contains an inconsistency between the synopsis and the handler documentation that affects which message type to import when filtering incoming events.
- Who is it for?
- Build LINE bots with this SDK when Python 3.10+ and pydantic 2.x fit your existing stack. Check the pydantic constraint first on any existing project, because pydantic >=2.0.3,<3 excludes any project pinned to pydantic 1.x. Before writing a webhook handler, register a channel at developers.line.biz to get a channel access token and channel secret; the README does not document those steps.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 11, 2026, and from our analysis. They are not legal advice.
Editorial analysis
LINE Messaging API SDK connects a Python server to LINE channel events
Building a bot on LINE means responding to webhook events the platform sends when users interact with a channel. This SDK handles that exchange from the Python side: verifying incoming webhook signatures, parsing the event payload, and calling LINE's Messaging API to post replies. The package is on PyPI at https://pypi.python.org/pypi/line-bot-sdk, with official API documentation available in English and Japanese at developers.line.biz.
Six example applications ship with the repository under examples/: aiohttp-echo, fastapi-echo, flask-echo, flask-kitchensink, rich-menu and simple-server-echo. They span the main Python web frameworks and use cases from basic echo bots to rich menu switching, with simple-server-echo using Python's wsgiref.simple_server module for the most minimal setup. Python 3.10 is the minimum supported version.
The package targets LINE's Messaging API. A docs/ directory at the repository root holds additional documentation, and the feature-specific API references live inside the installed package under linebot/v3/<feature>/docs/.
pip install line-bot-sdk pulls in pydantic 2.x, aiohttp and six other packages
The install command is a single line.
pip install line-bot-sdkThe requirements.txt lists eight runtime dependencies: requests >=2.32.3,<3; urllib3 >=2.0.5,<3; aiohttp >=3.10.9,<4; future >=1.0.0; pydantic >=2.0.3,<3; aenum >=3.1.11,<4; python_dateutil >=2.5.3,<3; and Deprecated >=1.2.18.
Pydantic is the constraint to check first. The project requires pydantic version 2. A project already using pydantic 1.x will hit a conflict, because pydantic >=2.0.3,<3 and any pydantic <2 pin cannot both be satisfied at the same installation. Verify the pydantic version before adding this SDK to an existing project.
Aiohttp ships as a runtime dependency even when your application uses only synchronous frameworks like Flask. The aiohttp-echo example in the repository is why it is present. In a tight container image, the combined footprint of aiohttp and pydantic 2 is worth factoring in.
A Flask webhook endpoint requires a channel access token and a channel secret
The synopsis shows a complete Flask application. It imports WebhookHandler from linebot.v3, TextMessageContent and MessageEvent from linebot.v3.webhooks, and MessagingApi with Configuration, ApiClient, ReplyMessageRequest and TextMessage from linebot.v3.messaging. Two credentials go into separate objects: the channel access token goes into Configuration, and the channel secret goes into WebhookHandler.
configuration = Configuration(access_token='YOUR_CHANNEL_ACCESS_TOKEN')
handler = WebhookHandler('YOUR_CHANNEL_SECRET')The /callback route reads the X-Line-Signature header, extracts the raw body, and passes both to handler.handle. If the signature does not match, InvalidSignatureError is raised and the route returns HTTP 400.
@app.route("/callback", methods=['POST'])
def callback():
signature = request.headers['X-Line-Signature']
body = request.get_data(as_text=True)
try:
handler.handle(body, signature)
except InvalidSignatureError:
abort(400)
return 'OK'The reply goes out through MessagingApi.reply_message_with_http_info, which takes a ReplyMessageRequest carrying the event's reply_token and the TextMessage to send back. The channel access token and channel secret both come from the LINE Developers console; the README gives no steps for registering a channel or obtaining them.
WebhookParser returns all events at once; WebhookHandler dispatches each by decorated type
Two classes handle incoming webhooks and they differ on where dispatch logic lives. WebhookParser.parse takes the raw body and signature, verifies the signature, and returns either a list of Event objects or a WebhookPayload object depending on the as_payload argument. The application code then iterates over the events in whatever order it needs.
parser = linebot.v3.WebhookParser('YOUR_CHANNEL_SECRET')
events = parser.parse(body, signature)
for event in events:
do_something(event)WebhookHandler holds a registry of callbacks added via its @add decorator, each mapped to an event class and optionally a message class. When handle is called, it parses the payload, verifies the signature, then dispatches each event to the first matching callback. Events with no matching handler are sent to a default callback if one is registered through @handler.default.
With WebhookParser, a single function receives all events and branches on application logic. With WebhookHandler, each event type maps to its own decorated function. Both classes raise InvalidSignatureError when the signature check fails.
Handler arity determines how many arguments the callback receives at dispatch time
The @handler.add decorator adjusts what it passes to the callback based on the number of arguments the decorated function declares. A function with zero arguments is called with none at all. A function with exactly one argument receives only the event object. A function with more than one argument receives the event as the first argument and the destination property from the webhook payload as the second argument.
@handler.add(MessageEvent)
def handle_message(event, destination):
# do something
passThis arity-based dispatch means that adding a second parameter to an existing callback silently changes what gets passed to it at runtime. Most Python event-handling frameworks ask the developer to declare what a callback needs through a type annotation or a separate argument list, not by counting the function's parameters. The README documents the three arity cases but does not explain the design rationale behind the approach or warn about the silent behavior change when a parameter is added.
The synopsis uses TextMessageContent as the message= filter but the add section uses TextMessage
A close reading of the README reveals a discrepancy between two code blocks that each show the @handler.add decorator with a message= filter but use different classes.
In the synopsis at the top of the README, the filter is written as:
@handler.add(MessageEvent, message=TextMessageContent)TextMessageContent comes from linebot.v3.webhooks and represents an incoming message received from a LINE user.
The add method's documentation section, which appears lower in the same file, uses a different class as the filter:
@handler.add(MessageEvent, message=TextMessage)TextMessage comes from linebot.v3.messaging and is the class used to construct outgoing reply messages. These are two different classes serving opposite roles. The handler's matching logic checks whether event.message is an instance of the class passed to message=. Because LINE delivers TextMessageContent objects in webhook payloads for incoming text messages, a filter of message=TextMessage would not match any incoming text event.
The synopsis is the correct example for the v3 import structure. Using TextMessage as the message= filter in production code would cause the handler to silently skip all incoming text messages, with no error raised.
v3 code is generated from LINE's OpenAPI spec, and API docs live inside the package
The repository root includes generate-code.py, a generator/ directory, and a .openapi-generator-ignore file. A .gitmodules file tracks line-openapi as a git submodule, which holds LINE's OpenAPI specification. The v3 client code is generated from that spec rather than written by hand, following the pattern used by other auto-generated OpenAPI SDKs.
For developers reading the API reference, the documentation lives inside the installed package: MessagingApi details are under linebot/v3/messaging/docs/MessagingApi.md, and each other feature group follows the same layout under linebot/v3/<feature>/docs/. This is the path the README points to for full API coverage, separate from the official developers.line.biz documentation.
Because the v3 code is generated, edits made directly to the linebot/v3/ source tree would be overwritten when the SDK regenerates from an updated spec. Customisations belong in application code, not in the package source.
The SDK is distributed under Apache-2.0, with the last push on 2026-09-18. Version 3.25.0, released on 2026-07-07, added Message Edited Webhook support; v3.24.0, released on 2026-07-01, added the rich menu summary API and daily report API.
Editorial conclusion
Build LINE bots with this SDK when Python 3.10+ and pydantic 2.x fit your existing stack. Check the pydantic constraint first on any existing project, because pydantic >=2.0.3,<3 excludes any project pinned to pydantic 1.x. Before writing a webhook handler, register a channel at developers.line.biz to get a channel access token and channel secret; the README does not document those steps. When you write the first @handler.add callback, import TextMessageContent from linebot.v3.webhooks as the message= filter, not TextMessage from linebot.v3.messaging, because those two classes represent opposite directions of the message flow.
Frequently asked questions
How do I install line-bot-sdk?
Install it from PyPI by running pip install line-bot-sdk. The package requires Python 3.10 or newer and installs eight runtime packages including pydantic 2.x and aiohttp.
What is the difference between WebhookHandler and WebhookParser in line-bot-sdk-python?
WebhookParser.parse returns all events as a list and leaves dispatch logic to the application. WebhookHandler holds a registry of decorated callbacks, each mapped to an event type, and dispatches each event automatically when handle is called.
Does line-bot-sdk-python support async frameworks like FastAPI and aiohttp?
The repository includes example applications named aiohttp-echo and fastapi-echo under the examples/ directory. The runtime requirements include aiohttp >=3.10.9,<4 as a dependency.
Which web frameworks does line-bot-sdk-python work with?
The repository provides examples for Flask, FastAPI, aiohttp and wsgiref.simple_server, named flask-echo, fastapi-echo, aiohttp-echo and simple-server-echo respectively under the examples/ directory.
What does skip_signature_verification do in WebhookHandler?
Both WebhookParser and WebhookHandler accept skip_signature_verification as a constructor parameter. It takes a callable that returns a boolean, with the default of lambda: False meaning signature verification is not skipped.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/line-line-bot-sdk-python)