Tutorial

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.

LineBot.pro Team20 min read
LINE Messaging API Tutorial: Complete Integration Guide for Developers

#LINE APIs Overview

LINE provides several APIs for different integration needs:

APIPurposeUse Case
Messaging APISend/receive messagesChatbots, notifications
LINE LoginUser authenticationSingle sign-on
LIFF SDKIn-LINE web appsMini-apps, forms
Notify APISimple notificationsAlerts, monitoring
Pay APIPaymentsE-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

  1. Go to developers.line.biz
  2. Log in with your LINE account
  3. Accept the developer agreement

#Step 2: Create a Provider

A provider represents your company or project:

diagram
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:

CredentialWhere to FindUsed For
Channel IDBasic settingsAll APIs
Channel SecretBasic settingsSignature verification
Channel Access TokenMessaging API tabAPI calls
LIFF IDLIFF tabLIFF SDK

#Messaging API Deep Dive

#Architecture Overview

diagram
User β†’ LINE App β†’ LINE Platform β†’ Your Webhook β†’ Your Server
                                      ↓
                      Reply/Push β†’ LINE Platform β†’ User

#Setting Up Your Server (Node.js)

javascript
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

python
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:

json
{
  "type": "text",
  "text": "Hello, World!"
}

Image Message:

json
{
  "type": "image",
  "originalContentUrl": "https://example.com/image.jpg",
  "previewImageUrl": "https://example.com/preview.jpg"
}

Flex Message (Custom Layout):

json
{
  "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

TypeCostWhen to Use
ReplyFreeResponding to user events
PushPaidProactive messages

Push Message Example:

javascript
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)

javascript
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

  1. Create LIFF app in LINE Developers Console
  2. Add your endpoint URL
  3. Include LIFF SDK in your app
html
<script src="https://static.line-scdn.net/liff/edge/2/sdk.js"></script>

#LIFF Initialization

javascript
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:

javascript
await liff.sendMessages([
  { type: 'text', text: 'Hello from LIFF!' }
]);

Share Target Picker:

javascript
if (liff.isApiAvailable('shareTargetPicker')) {
  await liff.shareTargetPicker([
    { type: 'text', text: 'Check out this product!' }
  ]);
}

Close LIFF:

javascript
liff.closeWindow();

Learn more about LIFF in our LIFF Development Guide.

#Webhook Implementation

#Event Types

EventTriggered When
messageUser sends a message
followUser adds your bot
unfollowUser blocks your bot
postbackUser taps a button
joinBot joins a group
leaveBot leaves a group

#Handling Different Events

javascript
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

  1. Always verify webhook signatures
  2. Use HTTPS for all endpoints
  3. Store secrets in environment variables
  4. Implement rate limiting
  5. 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

javascript
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:

APILimit
Reply message1 per webhook event
Push messageVaries by plan
Multicast500 users per request
BroadcastNo 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:

LineBot.pro

Ready to Automate Your LINE Business?

Start automating your LINE communications with LineBot.pro today.