# Line API

- Tool: FlutterFlow
- Difficulty: Intermediate
- Time required: 60 minutes
- Last updated: July 2026

## TL;DR

Connect FlutterFlow to LINE's Messaging API by building a Firebase Cloud Function that holds your Channel Access Token and forwards push-message requests to LINE's API. Your FlutterFlow app calls the Cloud Function — never LINE directly. You can only push to users who have already followed your LINE Official Account, making follower acquisition a critical first step.

## Sending LINE Messages from Your FlutterFlow App

LINE is the dominant messaging platform in Japan and widely used across Thailand, Taiwan, and Indonesia, with over 200 million monthly active users. For product founders targeting these markets, LINE's Messaging API unlocks push notifications, rich message cards, and chatbot interactions through a LINE Official Account. The critical business constraint to understand upfront: you can only send messages to users who have actively followed (friended) your LINE Official Account. Unlike SMS — which can reach any phone number — LINE messages are follower-gated. Building follower acquisition into your app's onboarding flow is therefore just as important as building the messaging integration itself.

Authentication uses a Channel Access Token: a long-lived Bearer token you issue in the LINE Developers Console. This token is a server secret — it gives whoever holds it the ability to send messages from your Official Account and access your channel's data. FlutterFlow apps run on users' devices (compiled Flutter), so any secret placed in an API Call header would be shipped inside the app bundle and extractable. The correct pattern is a Firebase Cloud Function proxy: your FlutterFlow app calls your function, which adds the Authorization header and calls LINE. Pricing for LINE's Messaging API depends on your Official Account plan — there is a free tier with a monthly message quota, then paid tiers above that (check the LINE for Business website for current pricing in your region, as plans vary by country).

Inbound events — when a user sends a message back, follows your account, or blocks it — arrive at a webhook that LINE calls on your server. Your Cloud Function handles these events and writes relevant data (like a new follower's userId) to Firestore. Your FlutterFlow app reads Firestore in real time so it always has up-to-date follower data to push messages to.

## Before you start

- A LINE Developers Console account at developers.line.biz (free to create with a LINE personal account)
- A LINE Official Account linked to a Messaging API channel in the Developers Console
- A Firebase project with Cloud Functions enabled (Blaze pay-as-you-go plan required for outbound HTTP calls from functions)
- A FlutterFlow project connected to the same Firebase project
- Node.js familiarity for writing and deploying the Cloud Function (or use the Firebase Console's inline editor)

## Step-by-step guide

### 1. Create a Messaging API channel and issue a Channel Access Token in LINE Developers Console

Go to developers.line.biz and log in with your LINE account. In the top navigation, click Console. You'll land on the provider and channel overview. If you don't have a provider yet, click Create and fill in your company or developer name.

Under your provider, click Create a channel and choose Messaging API from the channel type list. Fill in the channel name (this is the name followers see), category, and subcategory. Accept the LINE Official Account terms and the Messaging API terms, then click Create.

Once your channel is created, click on it to open the channel settings. Navigate to the Messaging API tab. You'll see a Webhook settings section — note the Webhook URL field; you'll fill this in after deploying your Cloud Function. Scroll further to find the Channel Access Token section. Click Issue (or Re-issue if one exists). Copy the long token string that appears. This is your Channel Access Token — treat it like a password. It will typically start with a long alphanumeric string and is valid indefinitely until you re-issue it.

Also note your Channel ID and Channel Secret from the Basic settings tab — you'll need the Channel Secret if you implement LINE Login for capturing userIds. Back on the Messaging API tab, turn on Use webhook (set it to Enabled). Now you're ready to set up the backend proxy.

**Expected result:** You have a Messaging API channel created, a Channel Access Token issued and copied, and webhook delivery is enabled on the channel settings page.

### 2. Deploy a Firebase Cloud Function as the push-message proxy and webhook receiver

Your Cloud Function serves two purposes: (1) it proxies push-message requests from your FlutterFlow app to LINE's API, keeping the Channel Access Token server-side; (2) it acts as the webhook endpoint that LINE calls when events happen (new follower, user message, unfollow). Both are handled in the same function file.

In the Firebase Console, go to your project and click Functions in the left sidebar. Click Get started if you haven't enabled Functions, then follow the setup wizard. For the Blaze plan requirement: Cloud Functions that make outbound HTTP requests (like calling api.line.me) require the Blaze pay-as-you-go Firebase plan. The free Spark plan blocks outbound calls to external URLs.

Create the function shown in the code block below. The function exposes two HTTP endpoints: POST /sendMessage (called by your FlutterFlow app) and POST /webhook (registered with LINE for inbound events). The Channel Access Token is stored in Firebase environment config — never hard-coded. Set it with the Firebase CLI command: firebase functions:config:set line.channel_access_token="YOUR_TOKEN_HERE".

After deploying, copy the function's public HTTPS URL (shown in the Firebase Console under Functions). Go back to your LINE Developers Console → Messaging API tab → Webhook settings and paste the webhook URL (append /webhook to the function base URL). Click Verify to confirm LINE can reach your endpoint. The LINE console will show 200 OK if the function is deployed correctly.

```
// Firebase Cloud Function: LINE Messaging API proxy + webhook receiver
// npm install axios cors
// firebase functions:config:set line.channel_access_token="YOUR_LONG_TOKEN"

const functions = require('firebase-functions');
const admin = require('firebase-admin');
const cors = require('cors')({ origin: true });
const axios = require('axios');

admin.initializeApp();
const db = admin.firestore();

const LINE_TOKEN = functions.config().line.channel_access_token;
const LINE_API = 'https://api.line.me/v2/bot';

// Called by FlutterFlow to send a push message
exports.sendMessage = functions.https.onRequest((req, res) => {
  cors(req, res, async () => {
    if (req.method !== 'POST') return res.status(405).send('Method Not Allowed');
    const { userId, message } = req.body;
    if (!userId || !message) {
      return res.status(400).json({ error: 'userId and message are required' });
    }
    try {
      const response = await axios.post(
        `${LINE_API}/message/push`,
        { to: userId, messages: [{ type: 'text', text: message }] },
        { headers: { 'Authorization': `Bearer ${LINE_TOKEN}`, 'Content-Type': 'application/json' } }
      );
      return res.status(200).json({ success: true, data: response.data });
    } catch (error) {
      const status = error.response?.status || 500;
      const detail = error.response?.data || error.message;
      return res.status(status).json({ error: detail });
    }
  });
});

// LINE webhook — receives events (follow, message, unfollow)
exports.lineWebhook = functions.https.onRequest(async (req, res) => {
  const events = req.body.events || [];
  for (const event of events) {
    if (event.type === 'follow' || event.type === 'message') {
      const userId = event.source?.userId;
      if (userId) {
        await db.collection('line_followers').doc(userId).set(
          { userId, lastEvent: event.type, updatedAt: admin.firestore.FieldValue.serverTimestamp() },
          { merge: true }
        );
      }
    }
  }
  return res.status(200).send('OK');
});
```

**Expected result:** Two Cloud Functions are deployed — sendMessage and lineWebhook — with their HTTPS URLs visible in the Firebase Console. The LINE Developers Console shows a 200 OK response when you click Verify Webhook.

### 3. Create a FlutterFlow API Group pointing at your sendMessage Cloud Function

In FlutterFlow, open your project and click API Calls in the left navigation panel (the two-arrows icon). Click + Add → Create API Group. Name the group something like LINE_Messaging. For the Base URL, paste the base URL of your Firebase Cloud Functions project — it will look like https://us-central1-YOUR_PROJECT_ID.cloudfunctions.net. Leave the Headers section empty for now (the token lives in the Cloud Function, not here).

Now add an API Call inside the group: click the + Add button next to your new API group and choose Create API Call. Name it SendPushMessage. Set the Method to POST. For the Endpoint, enter /sendMessage (the path you defined in the Cloud Function).

Click the Body tab. Set the body type to JSON. In the JSON body editor, add the following structure and use variables for the dynamic parts:

{
  "userId": "[userId]",
  "message": "[message]"
}

To make userId and message into FlutterFlow variables, click the Variables tab first and add two variables: userId (type: String) and message (type: String). Then reference them in the body using the double-bracket syntax {{ userId }} and {{ message }}.

Finally, click the Response & Test tab. In the test panel, fill in a real LINE userId from your Firestore collection (or a test userId from a follower on your Official Account) and a test message text. Click Test API Call. If the function is deployed and the userId belongs to a follower, you should receive a success response and see the message appear in that user's LINE chat. If you get a 400 error, the most common cause is that the userId doesn't belong to a follower of your Official Account.

```
{
  "userId": "{{ userId }}",
  "message": "{{ message }}"
}
```

**Expected result:** The API Call test in FlutterFlow returns a 200 response with {"success": true}. The test LINE user receives the message in their LINE app within a few seconds.

### 4. Capture LINE userIds via LINE Login and store them in Firestore

Before you can push messages to any user, you need their LINE userId — the unique identifier for each LINE account that has followed your Official Account. There are two ways to capture it:

Method A (Webhook, passive): When a user follows your Official Account, LINE sends a 'follow' event to your webhook. Your Cloud Function (Step 2) already handles this by writing the userId to a Firestore collection called line_followers. This means any FlutterFlow user who separately follows your LINE Official Account will have their userId stored automatically. The challenge: you need to link that userId to the user's account in your app.

Method B (LINE Login, active): LINE Login is an OAuth flow that lets users sign in to your app with their LINE account. When they do, you receive their userId, display name, and profile picture. This is the best way to tie a LINE userId to an app user record. Implementing LINE Login requires either a Cloud Function OAuth flow (recommended) or integrating the flutter_line_sdk pub.dev package as a Custom Action in FlutterFlow.

For most founders, the simplest path is a combination: prompt users in the app to follow your LINE Official Account by showing a QR code (generated from your Official Account's LINE friend link), and capture the follow event via webhook. In the FlutterFlow action flow, after the user taps 'Follow on LINE', trigger an API Call that polls Firestore for their userId (matched by their in-app user ID or email, which you can ask them to input in a short linking step).

Once you have userIds in Firestore, query them from FlutterFlow as a Firestore collection and use them as the userId input in your SendPushMessage API Call.

**Expected result:** Your Firestore line_followers collection contains documents with userId fields for every user who has followed your LINE Official Account. These userIds are available to query from FlutterFlow.

### 5. Trigger the LINE push from a button or automation in your FlutterFlow app

Now wire everything together. In FlutterFlow, open the screen or component where you want to trigger a LINE message — for example, an Order Shipped screen, a Post Created screen, or a Send Notification admin panel.

Select the button (or any widget) that should trigger the send. Open the Actions panel on the right side, click + Add Action, and choose Backend/API Calls → API Call. Select the LINE_Messaging group and the SendPushMessage call.

In the variable binding panel, bind userId to the Firestore field that holds the target user's LINE userId. You can fetch this via a Firestore query earlier in the action flow — for example, query the line_followers collection where an email field matches the current app user's email. Bind message to a Text field on the screen, an app state variable, or a hardcoded template string like "Your order has shipped! Check your app for tracking."

Add a success action after the API Call: show a Snackbar with 'Message sent to LINE' so the admin or the app flow knows the call succeeded. Add an error action to show an error message if the call fails (check the response status code in the condition).

For bulk sends — notifying all followers — do not loop through userIds in a single FlutterFlow action flow, as each iteration is a separate API call and large lists will be slow and fragile. Instead, pass the full list of userIds to your Cloud Function in one call and let the function iterate server-side using LINE's multicast endpoint (POST /message/multicast with a to array of up to 500 userIds).

```
// For bulk sends, update your Cloud Function to support multicast:
exports.sendMulticast = functions.https.onRequest((req, res) => {
  cors(req, res, async () => {
    if (req.method !== 'POST') return res.status(405).send('Method Not Allowed');
    const { userIds, message } = req.body;
    if (!userIds || !Array.isArray(userIds) || !message) {
      return res.status(400).json({ error: 'userIds array and message are required' });
    }
    // LINE multicast supports up to 500 recipients per call
    const chunks = [];
    for (let i = 0; i < userIds.length; i += 500) {
      chunks.push(userIds.slice(i, i + 500));
    }
    const results = [];
    for (const chunk of chunks) {
      const response = await axios.post(
        `${LINE_API}/message/multicast`,
        { to: chunk, messages: [{ type: 'text', text: message }] },
        { headers: { 'Authorization': `Bearer ${LINE_TOKEN}`, 'Content-Type': 'application/json' } }
      );
      results.push(response.data);
    }
    return res.status(200).json({ success: true, chunks: results.length });
  });
});
```

**Expected result:** Tapping the trigger button in FlutterFlow sends a LINE message to the target user's LINE app. The action flow shows a success Snackbar. For bulk sends, the multicast Cloud Function fans out to all followers efficiently.

## Best practices

- Store your Channel Access Token only in Firebase Functions environment config — never hard-code it in function source code or pass it through your FlutterFlow app.
- Use LINE's multicast endpoint (POST /message/multicast) for bulk sends instead of looping individual push calls — multicast handles up to 500 recipients per request and is dramatically faster.
- Always validate that a userId exists in your Firestore followers collection before triggering a push — sending to a non-follower returns a 400 error that wastes API quota.
- Add a webhook signature verification step to your Cloud Function using the X-Line-Signature header and your Channel Secret — this prevents malicious actors from spoofing fake events to your webhook.
- Design your app's onboarding to actively drive LINE follows early (QR code on the welcome screen, deep link on profile page) because every push message you want to send depends on follower count.
- Handle the unfollow webhook event by marking users in Firestore as unsubscribed — sending messages to users who blocked your account wastes quota and can trigger spam flags.
- Monitor your monthly message quota in the LINE Developers Console; exceeding the free tier limit silently stops message delivery rather than throwing an error.

## Use cases

### E-commerce app that sends order status updates via LINE

A FlutterFlow shopping app lets customers opt in to LINE notifications during checkout. When an order ships, the app triggers a push message to the customer's LINE chat with a tracking link. The customer's LINE userId is stored in Firestore alongside their order record, linked during the LINE Login onboarding step.

Prompt example:

```
When an order status changes to 'Shipped', send a LINE push message to the customer's LINE userId with the order number and tracking link.
```

### Appointment booking app with LINE reminders

A health or beauty booking app sends LINE appointment reminders 24 hours before a scheduled slot. Users connect their LINE account during sign-up, and the app stores their userId. A scheduled Cloud Function query fires daily and sends reminders to all users with appointments the next day.

Prompt example:

```
Send a LINE message reminder to users 24 hours before their appointment, including the date, time, and service name.
```

### Community app that notifies followers of new posts

A creator community app built in FlutterFlow sends LINE push notifications to followers whenever a new post is published. Followers opted in to notifications by following the creator's LINE Official Account, and their userIds are stored in Firestore. A batch push call fans out to all stored follower userIds when a new post is submitted.

Prompt example:

```
When a new post is created, send a LINE push message to all followers with the post title and a deep link back to the app.
```

## Troubleshooting

### 400 Bad Request from the Cloud Function when sending a push message

Cause: The most common cause is that the userId you're sending to is not a follower of your LINE Official Account. You can only message users who have added your account. A second cause is a malformed request body (missing 'to' or 'messages' fields).

Solution: Verify the userId exists in Firestore as a document written by the follow webhook. Confirm the user has followed your LINE Official Account by checking the Followers count in LINE Official Account Manager. If the userId is correct, log the exact request and response in your Cloud Function using console.log and check Firebase Function logs for the LINE API error detail.

### 401 Unauthorized from the LINE API inside the Cloud Function

Cause: The Channel Access Token is invalid, expired, or hasn't been set correctly in Firebase Functions config.

Solution: In your LINE Developers Console, go to the channel → Messaging API tab → Channel Access Token section. If the token was re-issued, set the new token: run 'firebase functions:config:set line.channel_access_token="NEW_TOKEN"' and redeploy. Confirm with 'firebase functions:config:get' that the token value is correct before redeploying.

### LINE webhook verification fails — LINE console shows an error instead of 200 OK

Cause: The webhook URL is incorrect (wrong path, wrong region, or the function isn't deployed), or the function returned a non-200 response during LINE's verification ping.

Solution: Make sure the webhook URL in the LINE Developers Console ends with /lineWebhook (or whatever path you used for the webhook export). Check Firebase Function logs for any startup errors. The webhook handler must return 200 for LINE's verification request — ensure the function does not throw an error before reaching res.status(200).send('OK').

### LINE Login redirect URI mismatch error during OAuth flow

Cause: The redirect URI registered in the LINE Login channel settings does not exactly match the one your Cloud Function is using as the OAuth callback.

Solution: In LINE Developers Console → LINE Login channel → App settings, add the exact redirect URI your Cloud Function uses (including the trailing path and query parameters format). Even a missing trailing slash causes a mismatch. Keep separate redirect URIs for development (e.g., localhost functions) and production.

## Frequently asked questions

### Can I send LINE messages to any phone number, or only to followers?

Only to followers — users who have added your LINE Official Account by scanning your QR code, clicking your friend link, or searching for your account by ID. LINE does not allow cold outreach to arbitrary phone numbers. This is a fundamental LINE platform design decision to prevent spam. Your integration's effectiveness depends entirely on your follower count.

### Can my FlutterFlow app receive messages that users send back via LINE?

Not directly. Inbound LINE messages arrive as webhook events on your Cloud Function, not in the FlutterFlow app. The correct pattern is: Cloud Function receives the message event and writes it to a Firestore collection; your FlutterFlow app reads that Firestore collection in real time using a Firestore stream listener. This gives you a near-real-time inbox experience without the app ever needing a public HTTP endpoint.

### Do I need a business account to use the LINE Messaging API?

You need a LINE Official Account, which you create through the LINE Official Account Manager (manager.line.biz). You can register with a personal LINE account for a small or individual developer account. To enable the Messaging API channel, you then link your Official Account to a Messaging API channel in the LINE Developers Console. The free tier of the Official Account includes a monthly message quota — check the current LINE for Business pricing page for your country, as quotas and pricing differ between Japan and other markets.

### What happens if I put the Channel Access Token directly in a FlutterFlow API Call header?

The token would be compiled into your app bundle and shipped to every device that downloads your app. Anyone with a copy of the APK or IPA file can extract it using standard reverse-engineering tools, then use it to send messages from your LINE Official Account, access your messaging stats, or revoke your own token. Always proxy LINE API calls through a Firebase Cloud Function that holds the token in a server-side environment variable.

### Can I send rich messages (images, buttons, carousels) from FlutterFlow to LINE?

Yes — LINE's Messaging API supports rich message types including image messages, flex messages (card layouts with buttons, images, and text), template messages (button, carousel, confirm), and more. Update your Cloud Function's messages array to include the appropriate type object instead of the simple text type. The LINE Messaging API documentation at developers.line.biz lists all supported message types with example JSON payloads.

---

Source: https://www.rapidevelopers.com/flutterflow-integrations/line-api
© RapidDev — https://www.rapidevelopers.com/flutterflow-integrations/line-api
