Skip to content

Instantly share code, notes, and snippets.

@PamornT
Last active December 3, 2025 09:12
Show Gist options
  • Select an option

  • Save PamornT/c8e334db7d447473584de16ac3041a5b to your computer and use it in GitHub Desktop.

Select an option

Save PamornT/c8e334db7d447473584de16ac3041a5b to your computer and use it in GitHub Desktop.
const { onRequest } = require("firebase-functions/v2/https");
const fetch = require("node-fetch");
/**
* ENV (ควรย้ายไป .env หรือ Firebase Config)
*/
const CLIENT_ID = "xxxxx"; // ใส่ Channel ID
const CLIENT_SECRET = "xxxxx"; // ใส่ Channel Secret
/**
* 1. Get Stateless Token
*/
async function getStatelessToken() {
const params = new URLSearchParams({
grant_type: "client_credentials",
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
});
const res = await fetch("https://api.line.me/oauth2/v3/token", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: params,
});
if (!res.ok) throw new Error("Failed to get stateless token");
const data = await res.json();
return data.access_token;
}
/**
* 2. Get Notifier Token
*/
async function getNotifierToken(statelessToken, liffAccessToken) {
const res = await fetch(
"https://api.line.me/message/v3/notifier/token",
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${statelessToken}`,
},
body: JSON.stringify({
liffAccessToken: liffAccessToken,
}),
}
);
if (!res.ok) throw new Error("Failed to get notifier token");
const data = await res.json();
return data.notificationToken;
}
/**
* 3. Send Service Message
*/
async function sendServiceMessage(statelessToken, notifierToken) {
const res = await fetch(
"https://api.line.me/message/v3/notifier/send?target=service",
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${statelessToken}`,
},
body: JSON.stringify({
templateName: "join_d_m_en",
params: {
entry_date: "4 March 2025 09:41",
btn1_url: "https://line.me",
},
notificationToken: notifierToken,
}),
}
);
if (!res.ok) throw new Error("Failed to send service message");
return await res.json();
}
/**
* 🔥 MAIN API
* POST /sendServiceMessage
* body: { liffAccessToken }
*/
exports.sendServiceMessage = onRequest(async (req, res) => {
try {
const { liffAccessToken } = req.body;
if (!liffAccessToken) {
return res.status(400).json({ error: "Missing liffAccessToken" });
}
// Step 1
const statelessToken = await getStatelessToken();
// Step 2
const notifierToken = await getNotifierToken(
statelessToken,
liffAccessToken
);
// Step 3
const result = await sendServiceMessage(
statelessToken,
notifierToken
);
res.json({
success: true,
statelessToken,
notifierToken,
result,
});
} catch (err) {
res.status(500).json({
error: err.message || "Internal Error",
});
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment