LINE Messaging API Tutorial: Complete Integration Guide for Developers
Master LINE Messaging API, Login API, and LIFF SDK. Complete developer tutorial with code examples for Node.js, Python, and PHP. Build production-ready LINE API integrations.

#LINE APIs Overview
LINE provides several APIs for different integration needs:
| API | Purpose | Use Case |
|---|---|---|
| Messaging API | Send/receive messages | Chatbots, notifications |
| LINE Login | User authentication | Single sign-on |
| LIFF SDK | In-LINE web apps | Mini-apps, forms |
| Notify API | Simple notifications | Alerts, monitoring |
| Pay API | Payments | E-commerce |
#Choosing the Right API
- Building a chatbot? β Messaging API
- Adding social login? β LINE Login
- Creating in-LINE experience? β LIFF SDK
- Just sending alerts? β LINE Notify
This tutorial covers the three most common: Messaging API, LINE Login, and LIFF SDK.
#Developer Setup
#Step 1: Create LINE Developers Account
- Go to developers.line.biz
- Log in with your LINE account
- Accept the developer agreement
#Step 2: Create a Provider
A provider represents your company or project:
Provider: "My Company"
βββ Channel: Messaging API (Bot)
βββ Channel: LINE Login
βββ Channel: LIFF App
#Step 3: Create Channels
For each integration type, create the appropriate channel:
Messaging API Channel:
- Channel name: Your bot name
- Channel description: What your bot does
- Category: Select appropriate category
- Privacy policy URL: Required for production
LINE Login Channel:
- App types: Web app, Native app, or both
- Callback URLs: Where users return after login
#Step 4: Gather Credentials
You'll need these credentials:
| Credential | Where to Find | Used For |
|---|---|---|
| Channel ID | Basic settings | All APIs |
| Channel Secret | Basic settings | Signature verification |
| Channel Access Token | Messaging API tab | API calls |
| LIFF ID | LIFF tab | LIFF SDK |
#Messaging API Deep Dive
#Architecture Overview
User β LINE App β LINE Platform β Your Webhook β Your Server
β
Reply/Push β LINE Platform β User
#Setting Up Your Server (Node.js)
const express = require('express');
const crypto = require('crypto');
const axios = require('axios');
const app = express();
app.use(express.json());
const CHANNEL_SECRET = process.env.LINE_CHANNEL_SECRET;
const CHANNEL_ACCESS_TOKEN = process.env.LINE_CHANNEL_ACCESS_TOKEN;
// Signature verification middleware
function validateSignature(req, res, next) {
const signature = req.headers['x-line-signature'];
const body = JSON.stringify(req.body);
const hash = crypto
.createHmac('SHA256', CHANNEL_SECRET)
.update(body)
.digest('base64');
if (hash !== signature) {
return res.status(401).send('Invalid signature');
}
next();
}
// Webhook endpoint
app.post('/webhook', validateSignature, async (req, res) => {
const events = req.body.events;
for (const event of events) {
await handleEvent(event);
}
res.status(200).send('OK');
});
async function handleEvent(event) {
if (event.type === 'message' && event.message.type === 'text') {
await replyMessage(event.replyToken, {
type: 'text',
text: `You said: ${event.message.text}`
});
}
}
async function replyMessage(replyToken, message) {
await axios.post('https://api.line.me/v2/bot/message/reply', {
replyToken,
messages: [message]
}, {
headers: {
'Authorization': `Bearer ${CHANNEL_ACCESS_TOKEN}`,
'Content-Type': 'application/json'
}
});
}
app.listen(3000);
#Python Implementation
from flask import Flask, request, abort
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError
from linebot.models import MessageEvent, TextMessage, TextSendMessage
import os
app = Flask(__name__)
line_bot_api = LineBotApi(os.environ['LINE_CHANNEL_ACCESS_TOKEN'])
handler = WebhookHandler(os.environ['LINE_CHANNEL_SECRET'])
@app.route('/webhook', methods=['POST'])
def webhook():
signature = request.headers['X-Line-Signature']
body = request.get_data(as_text=True)
try:
handler.handle(body, signature)
except InvalidSignatureError:
abort(400)
return 'OK'
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text=f'You said: {event.message.text}')
)
if __name__ == '__main__':
app.run(port=3000)
#Message Types
LINE supports various message types:
Text Message:
{
"type": "text",
"text": "Hello, World!"
}
Image Message:
{
"type": "image",
"originalContentUrl": "https://example.com/image.jpg",
"previewImageUrl": "https://example.com/preview.jpg"
}
Flex Message (Custom Layout):
{
"type": "flex",
"altText": "Product Card",
"contents": {
"type": "bubble",
"hero": {
"type": "image",
"url": "https://example.com/product.jpg",
"size": "full",
"aspectRatio": "20:13"
},
"body": {
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "text",
"text": "Product Name",
"weight": "bold",
"size": "xl"
},
{
"type": "text",
"text": "ΰΈΏ1,999",
"color": "#06C755"
}
]
},
"footer": {
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "button",
"action": {
"type": "uri",
"label": "Buy Now",
"uri": "https://example.com/buy"
},
"style": "primary",
"color": "#06C755"
}
]
}
}
}
#Push vs Reply Messages
| Type | Cost | When to Use |
|---|---|---|
| Reply | Free | Responding to user events |
| Push | Paid | Proactive messages |
Push Message Example:
async function pushMessage(userId, message) {
await axios.post('https://api.line.me/v2/bot/message/push', {
to: userId,
messages: [message]
}, {
headers: {
'Authorization': `Bearer ${CHANNEL_ACCESS_TOKEN}`,
'Content-Type': 'application/json'
}
});
}
#LINE Login Integration
#OAuth 2.0 Flow
1. User clicks "Login with LINE"
2. Redirect to LINE authorization URL
3. User grants permission
4. LINE redirects back with authorization code
5. Exchange code for access token
6. Fetch user profile with token
#Implementation (Node.js + Express)
const express = require('express');
const axios = require('axios');
const app = express();
const CLIENT_ID = process.env.LINE_LOGIN_CHANNEL_ID;
const CLIENT_SECRET = process.env.LINE_LOGIN_CHANNEL_SECRET;
const REDIRECT_URI = 'https://your-app.com/callback';
// Step 1: Redirect to LINE
app.get('/login', (req, res) => {
const state = generateRandomState();
const authUrl = `https://access.line.me/oauth2/v2.1/authorize?
response_type=code
&client_id=${CLIENT_ID}
&redirect_uri=${encodeURIComponent(REDIRECT_URI)}
&state=${state}
&scope=profile%20openid%20email`;
res.redirect(authUrl);
});
// Step 2: Handle callback
app.get('/callback', async (req, res) => {
const { code, state } = req.query;
// Verify state to prevent CSRF
if (!verifyState(state)) {
return res.status(400).send('Invalid state');
}
// Exchange code for token
const tokenResponse = await axios.post(
'https://api.line.me/oauth2/v2.1/token',
new URLSearchParams({
grant_type: 'authorization_code',
code,
redirect_uri: REDIRECT_URI,
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET
}),
{ headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
);
const { access_token, id_token } = tokenResponse.data;
// Fetch user profile
const profileResponse = await axios.get(
'https://api.line.me/v2/profile',
{ headers: { 'Authorization': `Bearer ${access_token}` } }
);
const { userId, displayName, pictureUrl } = profileResponse.data;
// Create session, redirect to app
req.session.user = { userId, displayName, pictureUrl };
res.redirect('/dashboard');
});
#LIFF SDK Development
#What is LIFF?
LIFF (LINE Front-end Framework) lets you create web apps that run inside LINE:
- Access LINE user profile without login
- Send messages from web app
- Share content to LINE chats
- Close app and return to chat
#Setting Up LIFF
- Create LIFF app in LINE Developers Console
- Add your endpoint URL
- Include LIFF SDK in your app
<script src="https://static.line-scdn.net/liff/edge/2/sdk.js"></script>
#LIFF Initialization
async function initializeLiff() {
try {
await liff.init({ liffId: 'YOUR_LIFF_ID' });
if (!liff.isLoggedIn()) {
liff.login();
return;
}
const profile = await liff.getProfile();
console.log('User:', profile.displayName);
} catch (error) {
console.error('LIFF init failed:', error);
}
}
initializeLiff();
#Common LIFF Operations
Send Message:
await liff.sendMessages([
{ type: 'text', text: 'Hello from LIFF!' }
]);
Share Target Picker:
if (liff.isApiAvailable('shareTargetPicker')) {
await liff.shareTargetPicker([
{ type: 'text', text: 'Check out this product!' }
]);
}
Close LIFF:
liff.closeWindow();
Learn more about LIFF in our LIFF Development Guide.
#Webhook Implementation
#Event Types
| Event | Triggered When |
|---|---|
| message | User sends a message |
| follow | User adds your bot |
| unfollow | User blocks your bot |
| postback | User taps a button |
| join | Bot joins a group |
| leave | Bot leaves a group |
#Handling Different Events
async function handleEvent(event) {
switch (event.type) {
case 'message':
return handleMessage(event);
case 'follow':
return handleFollow(event);
case 'postback':
return handlePostback(event);
default:
console.log('Unhandled event:', event.type);
}
}
async function handleFollow(event) {
const userId = event.source.userId;
// Send welcome message
await replyMessage(event.replyToken, [
{ type: 'text', text: 'Welcome! Thanks for following us.' },
{ type: 'text', text: 'How can I help you today?' }
]);
// Save user to database
await saveNewUser(userId);
}
async function handlePostback(event) {
const data = new URLSearchParams(event.postback.data);
const action = data.get('action');
switch (action) {
case 'book':
return handleBooking(event, data);
case 'cancel':
return handleCancellation(event, data);
}
}
#Best Practices & Security
#Security Checklist
- Always verify webhook signatures
- Use HTTPS for all endpoints
- Store secrets in environment variables
- Implement rate limiting
- Validate all user input
#Performance Tips
- Use reply messages when possible (free)
- Batch push messages (up to 500 per request)
- Cache user profiles (avoid repeated API calls)
- Implement proper error handling
- Use async/await for non-blocking operations
#Error Handling
async function safeReply(replyToken, messages) {
try {
await replyMessage(replyToken, messages);
} catch (error) {
if (error.response?.status === 400) {
console.log('Invalid reply token - message already sent');
} else {
console.error('Reply failed:', error.message);
// Implement retry logic or fallback
}
}
}
#Rate Limits
Be aware of API rate limits:
| API | Limit |
|---|---|
| Reply message | 1 per webhook event |
| Push message | Varies by plan |
| Multicast | 500 users per request |
| Broadcast | No limit (but costs apply) |
Need help with LINE API integration?
Try LineBot.pro for no-code chatbot building, or contact our LINE Development team for custom integration projects.
Related Resources:
Related Services
Ready to Automate Your LINE Business?
Start automating your LINE communications with LineBot.pro today.