此 API 提供類似 NT Notify 的功能,允許應用程式向使用者發送通知。您需要生成 API Token 進行身份驗證。
端點: GET /api/status
描述: 查詢 API 服務狀態。
Authorization: Bearer YOUR_API_TOKEN
{
"status": 200,
"message": "服務運行中",
"data": {
"app": "NT-Notify",
"status": "ok",
"server_time": "2026-09-08T12:34:56+08:00"
}
}
{
"status": 401,
"message": "Token 無效或未提供"
}
| 參數名稱 | 類型 | 描述 |
|---|---|---|
| status | integer | HTTP 狀態碼 |
| message | string | 狀態訊息 |
| data.app | string | 服務名稱 |
| data.status | string | 服務狀態,固定為 ok |
| data.server_time | string | 伺服器目前時間(ISO 8601 格式) |
curl -X GET \
/api/status \
-H 'Authorization: Bearer YOUR_API_TOKEN'
<?php
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => '/api/status',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer YOUR_API_TOKEN',
],
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
fetch('/api/status', {
method: 'GET',
headers: {
'Authorization': 'Bearer YOUR_API_TOKEN'
}
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
端點: POST /api/notify
描述: 發送通知訊息。
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
| 參數名稱 | 類型 | 必填 | 描述 |
|---|---|---|---|
| message | string | 是 | 要發送的訊息內容 (最多 5000 字元) |
| title | string | 否 | 訊息標題 (最多 255 字元) |
| image_url | string | 否 | 要附加的圖片 URL |
| recipient_id | string | 否 | 指定單一接收者的 LINE 用戶 ID |
| recipient_ids | array | 否 | 指定多個接收者的 LINE 用戶 ID 陣列,用於群發訊息 (最多 500 位) |
| send_to_all | boolean | 否 | 是否發送給所有會員 (廣播),設為 true 時需謹慎使用 |
| recipient_group_id | string | 否 | 指定單一接收群組的 LINE 群組 ID |
| recipient_group_ids | array 或 string | 否 | 指定多個接收群組的 LINE 群組 ID 陣列。也可以用逗號分隔的字串,例如: "id1,id2,id3" |
{
"success": true,
"message": "訊息已發送",
"data": {
"recipients_count": 1,
"sent_at": "2023-10-15T12:34:56Z"
}
}
{
"success": false,
"message": "驗證失敗",
"errors": {
"message": ["訊息內容不能為空"]
}
}
| 參數名稱 | 類型 | 描述 |
|---|---|---|
| success | boolean | 是否成功 (true: 成功, false: 失敗) |
| message | string | 狀態訊息 |
| data.recipients_count | integer | 接收訊息的用戶數量 (僅在成功時提供) |
| data.sent_at | string | 訊息發送時間 (ISO 8601 格式,僅在成功時提供) |
| errors | object | 驗證錯誤訊息 (僅在參數驗證失敗時提供) |
# 基本發送
curl -X POST \
/api/notify \
-H 'Authorization: Bearer YOUR_API_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"message": "Hello World",
"title": "通知標題",
"image_url": "https://example.com/image.jpg"
}'
# 發送給特定用戶
curl -X POST \
/api/notify \
-H 'Authorization: Bearer YOUR_API_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"message": "This is a personal message",
"title": "個人通知",
"recipient_id": "U4af4980629..."
}'
# 群發給多個用戶
curl -X POST \
/api/notify \
-H 'Authorization: Bearer YOUR_API_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"message": "This is a group message",
"title": "群組通知",
"recipient_ids": ["U4af4980629...", "U8c6d6tx42b..."]
}'
# 廣播給所有用戶
curl -X POST \
/api/notify \
-H 'Authorization: Bearer YOUR_API_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"message": "This is a broadcast message",
"title": "廣播通知",
"send_to_all": true
}'
<?php
/**
* 發送簡單通知訊息
*/
function sendNotification($message, $title = null, $imageUrl = null) {
$apiUrl = 'https://notify.example.com/api/notify';
$apiToken = 'YOUR_API_TOKEN_HERE';
// 準備請求資料
$data = [
'message' => $message
];
// 如果有標題,加入 data
if (!empty($title)) {
$data['title'] = $title;
}
// 如果有圖片 URL,加入 data
if (!empty($imageUrl)) {
$data['image_url'] = $imageUrl;
}
// 初始化 cURL
$ch = curl_init($apiUrl);
// 設定 cURL 選項
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $apiToken
]);
// 執行 cURL 請求
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
/**
* 發送訊息給特定使用者
*/
function sendToUser($message, $recipientId, $title = null, $imageUrl = null) {
$apiUrl = 'https://notify.example.com/api/notify';
$apiToken = 'YOUR_API_TOKEN_HERE';
// 準備請求資料
$data = [
'message' => $message,
'recipient_id' => $recipientId
];
// 如果有標題,加入 data
if (!empty($title)) {
$data['title'] = $title;
}
// 如果有圖片 URL,加入 data
if (!empty($imageUrl)) {
$data['image_url'] = $imageUrl;
}
// 初始化 cURL
$ch = curl_init($apiUrl);
// 設定 cURL 選項
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $apiToken
]);
// 執行 cURL 請求
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
// 使用範例
// sendNotification('這是一條通知訊息', '測試標題');
// sendToUser('這是發送給特定用戶的訊息', 'U4af4980629...', '個人通知');
import requests
import json
# 設定 NT-Notify API 的 URL 和 API Token
API_URL = 'https://notify.example.com/api/notify'
API_TOKEN = 'YOUR_API_TOKEN_HERE' # 請將此替換為您的實際 API Token
def send_notification(message, title=None, image_url=None):
"""
發送簡單通知訊息
"""
# 準備請求資料
data = {'message': message}
# 如果有標題,加入 data
if title:
data['title'] = title
# 如果有圖片 URL,加入 data
if image_url:
data['image_url'] = image_url
# 設定請求標頭
headers = {
'Content-Type': 'application/json',
'Authorization': f'Bearer {API_TOKEN}'
}
# 發送 API 請求
response = requests.post(API_URL, headers=headers, json=data)
return response.json()
def send_to_user(message, recipient_id, title=None, image_url=None):
"""
發送訊息給特定使用者
"""
# 準備請求資料
data = {
'message': message,
'recipient_id': recipient_id
}
# 如果有標題,加入 data
if title:
data['title'] = title
# 如果有圖片 URL,加入 data
if image_url:
data['image_url'] = image_url
# 設定請求標頭
headers = {
'Content-Type': 'application/json',
'Authorization': f'Bearer {API_TOKEN}'
}
# 發送 API 請求
response = requests.post(API_URL, headers=headers, json=data)
return response.json()
# 使用範例
# result = send_notification("這是一條測試訊息", "測試標題")
# print(result)
// 設定 API 相關常數
const API_URL = '/api/notify';
const API_TOKEN = 'YOUR_API_TOKEN';
/**
* 發送基本通知
*/
async function sendNotification(message, title, imageUrl) {
// 準備請求資料
const data = { message };
// 如果有標題,加入 data
if (title) {
data.title = title;
}
// 如果有圖片 URL,加入 data
if (imageUrl) {
data.image_url = imageUrl;
}
try {
const response = await fetch(API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${API_TOKEN}`
},
body: JSON.stringify(data)
});
return await response.json();
} catch (error) {
console.error('Error:', error);
return { success: false, message: error.message };
}
}
/**
* 發送訊息給特定用戶
*/
async function sendToUser(message, recipientId, title, imageUrl) {
// 準備請求資料
const data = {
message,
recipient_id: recipientId
};
// 如果有標題,加入 data
if (title) {
data.title = title;
}
// 如果有圖片 URL,加入 data
if (imageUrl) {
data.image_url = imageUrl;
}
try {
const response = await fetch(API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${API_TOKEN}`
},
body: JSON.stringify(data)
});
return await response.json();
} catch (error) {
console.error('Error:', error);
return { success: false, message: error.message };
}
}
// 使用範例
// sendNotification('Hello World', '通知標題', 'https://example.com/image.jpg')
// .then(data => console.log(data));
// 設定 NT-Notify API 的 URL 和 API Token
var API_URL = 'https://notify.example.com/api/notify';
var API_TOKEN = 'YOUR_API_TOKEN_HERE'; // 請將此替換為您的實際 API Token
/**
* 發送單一訊息通知
*/
function sendNotification(message, title, imageUrl) {
// 準備請求資料
var payload = {
'message': message
};
// 如果有標題,加入 payload
if (title && title.trim() !== '') {
payload.title = title;
}
// 如果有圖片 URL,加入 payload
if (imageUrl && imageUrl.trim() !== '') {
payload.image_url = imageUrl;
}
// 設定 API 請求選項
var options = {
'method': 'post',
'contentType': 'application/json',
'headers': {
'Authorization': 'Bearer ' + API_TOKEN
},
'payload': JSON.stringify(payload),
'muteHttpExceptions': true
};
// 發送 API 請求
var response = UrlFetchApp.fetch(API_URL, options);
// 解析 API 回應
var result = JSON.parse(response.getContentText());
// 記錄結果
Logger.log('發送結果: ' + result.message);
return result;
}
/**
* 發送訊息給特定使用者
*/
function sendToUser(message, recipientId, title, imageUrl) {
// 準備請求資料
var payload = {
'message': message,
'recipient_id': recipientId
};
// 如果有標題,加入 payload
if (title && title.trim() !== '') {
payload.title = title;
}
// 如果有圖片 URL,加入 payload
if (imageUrl && imageUrl.trim() !== '') {
payload.image_url = imageUrl;
}
// 設定 API 請求選項
var options = {
'method': 'post',
'contentType': 'application/json',
'headers': {
'Authorization': 'Bearer ' + API_TOKEN
},
'payload': JSON.stringify(payload),
'muteHttpExceptions': true
};
// 發送 API 請求
var response = UrlFetchApp.fetch(API_URL, options);
return JSON.parse(response.getContentText());
}
/**
* 發送訊息給特定群組
*/
function sendToSpecificGroup() {
sendWebhook('這是發送給特定群組的訊息', {
'recipient_group_id': 'C4af4980629...'
});
}
/**
* 群發訊息給多個群組
*/
function sendToMultipleGroups() {
sendWebhook('這是群發給多個群組的訊息', {
'recipient_group_ids': ['C4af4980629...', 'C8c6d6tx42b...']
});
}
// 使用範例
// function testNotify() {
// sendNotification('這是一條通知訊息', '測試標題');
// }
您可以下載以下完整的範例程式碼:
本系統提供 API 查詢 LINE Bot 收到的訊息紀錄,支援多種篩選條件。認證方式與其他端點相同,使用 API Token(Authorization: Bearer YOUR_API_TOKEN),無需另外登入取得 Token。
端點: GET /api/messages
描述: 查詢目前登入使用者旗下「所有 Bot」接收到的訊息,可加上 bot_id 參數縮小範圍,適合跨 Bot 統一查詢。
Authorization: Bearer YOUR_API_TOKEN
| 參數名稱 | 類型 | 必填 | 描述 |
|---|---|---|---|
| bot_id | integer | 否 | 篩選特定 Bot(不填則查詢所有 Bot) |
| line_user_id | string | 否 | 篩選特定 LINE 用戶 |
| line_group_id | string | 否 | 篩選特定 LINE 群組 |
| source_type | string | 否 | user 或 group |
| message_type | string | 否 | 訊息類型:text、image、sticker 等 |
| start_date | string | 否 | 起始日期,格式 Y-m-d |
| end_date | string | 否 | 結束日期,格式 Y-m-d |
| per_page | integer | 否 | 每頁筆數(預設 15,最大 100) |
| direction | string | 否 | in(接收)、out(發送)或 all;不填等同 all。其他值回 422 |
| exclude_inbound_copies | boolean | 否 | 帶 1 時排除收訊複製(is_inbound_copy=true 的列),避免同一則收到的訊息出現兩次。不帶時行為不變 |
meta)| 欄位 | 說明 |
|---|---|
| meta.server_time | 伺服器產生回應的時間(ISO-8601,含時區) |
| meta.last_received_at | 在同樣篩選條件下(不受分頁影響),最後一筆接收訊息的時間;沒有符合的訊息時為 null。只反映接收方向,direction=out 時固定為 null,不代表沒有收到任何訊息 |
direction=in),也會複製一份到發送紀錄供後台紀錄頁檢視;這份複製在 API 中會以 direction=out、channel=line 出現,但它其實是對方說的話,不是 Bot 發出的訊息。
因此不帶 direction(或 direction=all)時,每則收到的訊息會出現兩筆。
要查「客戶說了什麼」,請帶 direction=in;要同時看 Bot 發出的訊息又不想重複,請帶 exclude_inbound_copies=1。
| 欄位 | 說明 |
|---|---|
| unsent_at | 對方在 LINE 撤回該則訊息的時間;未撤回為 null。撤回的訊息仍會回傳(內容保留),請依此欄位自行決定是否顯示。收訊複製( is_inbound_copy=true)的限制:只有「撤回標記」功能上線後寫入的複製能被標記;更早的複製一律為 null,不代表未撤回,請以 direction=in 那筆為準 |
| is_inbound_copy | true 表示這筆是收到訊息時寫入的複製(direction=out 且 channel=line),內容與對應的 direction=in 那筆重複 |
| original_name | 收到的媒體/檔案在對方裝置上的原始檔名(LINE 只在 file 訊息提供 fileName);沒有或 direction=out 時為 null。content 的網址副檔名不一定正確,要顯示檔名請用這個欄位 |
| file_size | 收到的媒體/檔案大小(bytes,整數);沒有或 direction=out 時為 null |
| media_mime | 系統實際偵測到的 MIME type(例如 application/zip);沒有或 direction=out 時為 null |
# 查詢所有 Bot 的接收訊息
curl -X GET "http://YOUR_DOMAIN/api/messages?per_page=20" \
-H "Authorization: Bearer YOUR_API_TOKEN"
# 篩選某日期範圍內的群組訊息
curl -X GET "http://YOUR_DOMAIN/api/messages?source_type=group&start_date=2024-01-01&end_date=2024-01-31" \
-H "Authorization: Bearer YOUR_API_TOKEN"
# 特定 Bot + 特定用戶
curl -X GET "http://YOUR_DOMAIN/api/messages?bot_id=1&line_user_id=U4af4980629..." \
-H "Authorization: Bearer YOUR_API_TOKEN"
<?php
$apiUrl = 'https://YOUR_DOMAIN/api/messages';
$apiToken = 'YOUR_API_TOKEN';
$params = http_build_query([
'source_type' => 'user',
'start_date' => '2024-01-01',
'end_date' => '2024-01-31',
'per_page' => 20,
]);
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $apiUrl . '?' . $params,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer {$apiToken}"],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
echo "共 " . $response['data']['total'] . " 則訊息\n";
foreach ($response['data']['data'] as $msg) {
echo "[{$msg['created_at']}] {$msg['content']}\n";
}
const apiToken = 'YOUR_API_TOKEN';
async function getAllMessages(filters = {}) {
const params = new URLSearchParams(filters).toString();
const res = await fetch(`/api/messages?${params}`, {
headers: { 'Authorization': `Bearer ${apiToken}` }
});
return await res.json();
}
// 查詢所有 Bot 今日的個人訊息
const today = new Date().toISOString().split('T')[0];
getAllMessages({ source_type: 'user', start_date: today })
.then(data => {
console.log(`共 ${data.data.total} 則訊息`);
data.data.data.forEach(msg => {
console.log(`[${msg.created_at}] ${msg.content}`);
});
});
群組管理支援自訂分類(category / subcategory / tags / note),可用於「一群一個倉庫」的分群檢視。認證方式:API Token(Authorization: Bearer YOUR_API_TOKEN)。
端點: GET /api/groups
描述: 取得目前 Token 擁有者名下所有群組,可用 bot_id、category 篩選。
Authorization: Bearer YOUR_API_TOKEN
| 參數名稱 | 類型 | 必填 | 描述 |
|---|---|---|---|
| bot_id | integer | 否 | 篩選特定 Bot |
| category | string | 否 | 篩選特定分類 |
{
"status": 200,
"message": "取得群組清單成功",
"data": [
{
"id": 1,
"user_bot_id": 1,
"line_group_id": "Cd48b3679f5e6564d8fdd2b180e518376",
"group_name": "丟資料用",
"category": "測試",
"subcategory": null,
"tags": null,
"note": null,
"created_at": "2026-09-07T22:30:30+08:00"
}
]
}
| 狀態碼 | 說明 |
|---|---|
| 401 | Token 無效或未提供 |
端點: PUT /api/groups/{id}/taxonomy
描述: {id} 為群組在本系統的內部 ID(GET /api/groups 回應中的 id,非 line_group_id)。
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
| 參數名稱 | 類型 | 必填 | 描述 |
|---|---|---|---|
| category | string | 否 | 分類(最多 255 字元) |
| subcategory | string | 否 | 子分類(最多 255 字元) |
| tags | array<string> | 否 | 標籤(多值) |
| note | string | 否 | 備註 |
{
"status": 200,
"message": "群組分類更新成功",
"data": { "id": 1, "category": "測試", "subcategory": null, "tags": null, "note": null }
}
| 狀態碼 | 說明 |
|---|---|
| 401 | Token 無效或未提供 |
| 403 | 該群組不屬於目前 Token 的擁有者 |
| 404 | 找不到指定的群組 |
| 422 | 參數驗證失敗 |
curl -X PUT "http://YOUR_DOMAIN/api/groups/1/taxonomy" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"category": "測試", "tags": ["重要", "供應商"]}'
把某個群組的訊息一次匯出(文字格式 + 媒體 ZIP),採非同步處理:先建立匯出工作,再輪詢工作狀態取得下載連結。認證方式:API Token。
端點: POST /api/groups/{line_group_id}/exports
描述: {line_group_id} 為 LINE 群組 ID(例如 Cd48b3679f5e6564d8fdd2b180e518376)。
Authorization: Bearer YOUR_API_TOKEN
| 參數名稱 | 類型 | 必填 | 描述 |
|---|---|---|---|
| format | string | 否 | txt、csv(預設)或 jsonl |
| start_date | string | 否 | 起始日期,格式 Y-m-d |
| end_date | string | 否 | 結束日期,格式 Y-m-d |
| include_media | boolean | 否 | 是否一併打包照片/影片/檔案的 ZIP |
| message_type | string | 否 | 篩選訊息類型 |
{
"status": 202,
"message": "匯出工作已建立",
"job_id": 1,
"export_status": "pending"
}
| 狀態碼 | 說明 |
|---|---|
| 401 | Token 無效或未提供 |
| 404 | 找不到群組或沒有權限 |
| 422 | 參數驗證失敗 |
curl -X POST "http://YOUR_DOMAIN/api/groups/Cd48b3679f5e6564d8fdd2b180e518376/exports" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-d "format=csv&include_media=1"
端點: GET /api/exports/{job_id}
描述: {job_id} 為建立匯出工作時回傳的 job_id。
{
"status": 200,
"message": "取得匯出工作狀態成功",
"data": {
"job_id": 1,
"status": "completed",
"file_url": "https://.../exports/xxx.zip",
"expires_at": "2026-09-09T22:30:30+08:00",
"error": null
}
}
status 可能為 pending、processing、completed 或 failed;
file_url 只在 completed 且未過期時提供,下載連結有效期限至少 24 小時。
| 狀態碼 | 說明 |
|---|---|
| 401 | Token 無效或未提供 |
| 404 | 找不到匯出工作或沒有權限 |
把 bot 加入群組前的歷史對話(LINE App 匯出的 .txt)與照片/影片補進同一個群組的倉庫,一併採非同步處理。認證方式:API Token。
端點: POST /api/groups/{line_group_id}/imports
描述: multipart/form-data 上傳。
Authorization: Bearer YOUR_API_TOKEN
Content-Type: multipart/form-data
| 參數名稱 | 類型 | 必填 | 描述 |
|---|---|---|---|
| chat_txt | file | 是 | LINE App 匯出的聊天紀錄 .txt(最大 5MB) |
| media[] | file[] | 否 | 照片/影片/檔案,可多個(每個最大 50MB) |
| name_map | string(JSON) | 否 | 「.txt 顯示名稱 → 會員」對應表,例如 {"TK Lin": "U4af..."} |
{
"status": 202,
"message": "匯入工作已建立",
"job_id": 1,
"import_status": "pending"
}
| 狀態碼 | 說明 |
|---|---|
| 401 | Token 無效或未提供 |
| 404 | 找不到群組或沒有權限 |
| 422 | 參數錯誤(檔案格式/大小、name_map 非合法 JSON 等) |
curl -X POST "http://YOUR_DOMAIN/api/groups/Cd48b3679f5e6564d8fdd2b180e518376/imports" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-F "chat_txt=@/path/to/chat.txt" \
-F "media[]=@/path/to/photo1.jpg" \
-F "media[]=@/path/to/photo2.jpg" \
-F 'name_map={"TK Lin":"U4af4980629..."}'
端點: GET /api/imports/{job_id}
{
"status": 200,
"message": "取得匯入工作狀態成功",
"data": {
"id": 1,
"group_id": "Cd48b3679f5e6564d8fdd2b180e518376",
"status": "completed",
"stats": { "inserted": 12, "skipped": 0, "media_matched": 2, "media_unmatched": 0 },
"error_message": null
}
}
status 可能為 pending、processing、completed 或 failed;stats 內容依實際解析結果而定。
| 狀態碼 | 說明 |
|---|---|
| 401 | Token 無效或未提供 |
| 404 | 找不到匯入工作或沒有權限 |
端點: DELETE /api/imports/{job_id}
描述: 刪除該匯入批次寫入的所有訊息(origin = import),webhook 收到的訊息不受影響。
{
"status": 200,
"message": "匯入批次已撤銷",
"deleted_count": 12
}
| 狀態碼 | 說明 |
|---|---|
| 401 | Token 無效或未提供 |
| 404 | 找不到匯入工作或沒有權限 |
curl -X DELETE "http://YOUR_DOMAIN/api/imports/1" \
-H "Authorization: Bearer YOUR_API_TOKEN"
以 LINE Bot 主動發送訊息給個人、會員或群組,可附圖片、影片或檔案。認證方式:API Token(Authorization: Bearer YOUR_API_TOKEN)。對外發送 API 目前僅支援 LINE。
端點: POST /api/messages/send
描述: 以指定 Bot 發送文字訊息,可附圖片/影片(公開 HTTPS 網址或 multipart 直接上傳)或檔案。只帶網址時可用 JSON;要上傳圖片、影片或檔案時請用 multipart/form-data。
Authorization: Bearer YOUR_API_TOKEN
| 參數名稱 | 類型 | 必填 | 描述 |
|---|---|---|---|
| bot_id | integer | 是 | 發送用的 Bot ID,必須屬於此 Token 的擁有者 |
| message | string | 是 | 文字內容,最多 5000 字(LINE 文字上限)。帶 file 時,系統會在末尾附上檔名、下載連結與期限,合計也不得超過 5000 字,否則回 422 |
| target_type | string | 是 | 收件對象類型:direct、member、multicast、group、multigroup(見下表) |
| direct_user_id | string | target_type=direct 時 | LINE userId |
| member_id | integer | target_type=member 時 | 會員 id(需屬於此 Bot 且為啟用狀態) |
| member_ids | array of integer | target_type=multicast 時 | 會員 id 陣列,最多 500 位 |
| group_id | string | target_type=group 時 | LINE 群組 ID(C 開頭) |
| group_ids | array of string | target_type=multigroup 時 | LINE 群組 ID 陣列;不屬於此 Bot 或未啟用的群組會被略過 |
| image_url | string | 否 | 圖片網址,必須是 https:// 開頭的公開網址(最長 1000 字元);與 image 擇一 |
| video_url | string | 否 | 影片網址(https://,最長 1000 字元);與 video 擇一。帶影片時必須同時帶縮圖(preview_image_url 或 preview_image) |
| preview_image_url | string | 否 | 影片縮圖網址(https://,最長 1000 字元);與 preview_image 擇一 |
| image | file | 否 | 僅 multipart;jpg/png,上限 10MB;與 image_url 擇一 |
| video | file | 否 | 僅 multipart;mp4,上限 200MB;與 video_url 擇一,必須同時帶縮圖 |
| preview_image | file | 否 | 僅 multipart;jpg/png,上限 1MB;與 preview_image_url 擇一 |
| file | file | 否 | 僅 multipart;pdf/zip/docx/xlsx/csv/txt,上限 20MB。LINE 沒有檔案訊息類型:檔案存於私有儲存,訊息末尾附上下載連結 |
| file_expires_days | integer | 否 | 下載連結有效天數,1–7,預設 3;只能搭配 file 使用 |
image_url/video_url/preview_image_url,LINE 只接受公開 HTTPS;(2)媒體直接上傳:image/video/preview_image,系統先上傳成公開網址再發送;同一媒體的網址與上傳檔只能擇一,兩者都帶回 422;(3)檔案:file,以下載連結附在文字訊息末尾。不接受 send_type 參數,帶了回 422。
upload_max_filesize 回 422「檔案超過伺服器上傳上限」;(3)整個請求超過 php.ini 的 post_max_size 時,在進入本端點之前就回 413(不是 422)。實際可用上限取決於部署環境的 php.ini 與前端代理(例如 nginx 的 client_max_body_size),程式上限不保證等於實際上限。
| target_type | 收件對象 | 搭配參數 |
|---|---|---|
direct | 指定 LINE 用戶 | direct_user_id |
member | 單一會員(找不到或未啟用回 404) | member_id |
multicast | 多位會員,上限 500 位(一個都找不到回 404) | member_ids |
group | 單一群組(找不到或未啟用回 404) | group_id |
multigroup | 多個群組,逐一發送(一個都找不到回 404) | group_ids |
{
"status": 200,
"message": "訊息發送成功",
"data": {
"file": {
"id": 12,
"url": "https://YOUR_DOMAIN/f/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"expires_at": "2026-10-23T12:34:56+08:00"
}
}
}
沒帶 file 且不是 multigroup 時,回應不含 data。data.file.id 可用 DELETE /api/sent-files/{id} 撤銷下載連結。
{
"status": 502,
"message": "訊息發送失敗",
"error": {
"reason": "line_rate_limited",
"line_status": 429,
"detail": "LINE API 回 429:本月訊息額度已用完或觸發 rate limit,額度重置或降速前重試無效"
},
"data": {
"groups": {
"succeeded": ["Cxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1"],
"failed": [
{"group_id": "Cxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx2", "reason": "line_rate_limited", "line_status": 429}
],
"skipped": []
}
}
}
| reason | 說明 |
|---|---|
line_rate_limited | LINE 回 429:本月訊息額度已用完或觸發 rate limit,額度重置或降速前重試無效 |
line_unauthorized | LINE 回 401:Channel Access Token 無效或已過期 |
line_rejected | LINE 回其他 4xx:請檢查收件 ID 與訊息內容是否符合 LINE 規格 |
line_server_error | LINE 回 5xx,可稍後重試 |
line_unreachable | 連線 LINE 失敗或逾時(此時 line_status 為 null) |
line_failed | 發送失敗但沒有細節 |
time_budget_exceeded | multigroup 超過時間預算,其餘群組未發送(列在 data.groups.skipped) |
error.line_status 為 LINE 回的 HTTP 狀態碼。target_type=multigroup 時另回 data.groups:succeeded(已送達的群組 ID)、failed(group_id、reason、line_status)、skipped(未發送的群組 ID)。
data.groups.failed 與 skipped 只重送沒收到的群組。
| 狀態碼 | 說明 |
|---|---|
| 401 | Token 無效或未提供 |
| 404 | Bot、會員或群組不存在,或不屬於此 Token 的擁有者 |
| 413 | 請求超過 php.ini post_max_size(在本端點之前回應) |
| 422 | 參數錯誤,errors 會列出欄位與原因(含超過大小上限、message 超過 5000 字) |
| 500 | 檔案或媒體儲存失敗(訊息未發送),或伺服器內部錯誤(訊息不含內部細節) |
curl -X POST "http://YOUR_DOMAIN/api/messages/send" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-F "bot_id=6" \
-F "message=出貨通知" \
-F "target_type=group" \
-F "group_id=Cxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-F "file=@報價單.pdf" \
-F "file_expires_days=3"
端點: DELETE /api/sent-files/{id}
描述: {id} 為發送時回應的 data.file.id。撤銷後下載連結回 410;重複撤銷視為成功。
Authorization: Bearer YOUR_API_TOKEN
{
"status": 200,
"message": "已撤銷",
"data": {
"id": 12,
"revoked_at": "2026-10-20T12:34:56+08:00"
}
}
| 狀態碼 | 說明 |
|---|---|
| 401 | Token 無效或未提供 |
| 404 | 檔案不存在或不屬於此 Token 的擁有者 |
| 500 | 伺服器內部錯誤(訊息不含內部細節) |
curl -X DELETE "http://YOUR_DOMAIN/api/sent-files/12" \
-H "Authorization: Bearer YOUR_API_TOKEN"
端點: GET /f/{token}
描述: 收件人點訊息中的下載連結即走這個端點。不需登入,連結中的 token 即憑證,請勿外流。HEAD 請求只回標頭,不計入下載次數。
| 狀態碼 | 內容 | 說明 |
|---|---|---|
| 200 | 檔案本體 | 以附件下載(Content-Disposition: attachment,保留原始檔名) |
| 404 | 純文字「找不到檔案」 | 連結不存在,或檔案已不在儲存體 |
| 410 | 純文字「下載連結已失效」 | 已撤銷、已過期,或所屬 Bot 已刪除 |
| 503 | 純文字「檔案暫時無法下載,請稍後再試」 | 儲存體暫時錯誤 |
端點: GET /api/bots/{id}/quota(單一 Bot)、GET /api/bots/quota(所有 Bot)
描述: 向 LINE 查詢本月訊息額度與用量,只能查此 Token 擁有者自己的 Bot。
Authorization: Bearer YOUR_API_TOKEN
{
"status": "success",
"data": {
"bot_id": 17,
"bot_name": "NT-AI",
"type": "limited",
"unlimited": false,
"limit": 3000,
"usage": 199,
"remaining": 2801
}
}
{
"status": "success",
"data": [
{"bot_id": 17, "bot_name": "NT-AI", "type": "limited", "unlimited": false, "limit": 3000, "usage": 199, "remaining": 2801, "error": null},
{"bot_id": 18, "bot_name": "客服", "type": "none", "unlimited": true, "limit": null, "usage": 52, "remaining": null, "error": null},
{"bot_id": 19, "bot_name": "測試", "type": null, "unlimited": null, "limit": null, "usage": null, "remaining": null, "error": "LINE API 暫時無法取得額度資訊,請稍後再試"}
]
}
| 參數名稱 | 類型 | 描述 |
|---|---|---|
| type | string | LINE 的額度類型;none 表示無上限方案 |
| unlimited | boolean | true 表示無上限方案(type=none) |
| limit | integer/null | 本月額度;無上限時為 null(不是 0) |
| usage | integer | 本月已用量 |
| remaining | integer/null | 剩餘額度(不小於 0);無上限時為 null |
| error | string/null | 僅 GET /api/bots/quota:該 Bot 查詢失敗時的原因,此時數字欄位與 type、unlimited 皆為 null |
{
"status": "error",
"message": "LINE API 暫時無法取得額度資訊,請稍後再試"
}
| 狀態碼 | 說明 |
|---|---|
| 400 | 此 Bot 尚未設定 Channel Access Token |
| 401 | Token 無效或未提供 |
| 404 | Bot 不存在或不屬於當前用戶 |
| 500 | 伺服器內部錯誤(訊息不含內部細節) |
| 502 | 上游 LINE API 查詢失敗:LINE 401 時提示檢查 Token;429 為 rate limit;其他(5xx、逾時)請稍後再試 |
GET /api/bots/quota 中個別 Bot 查詢失敗不影響其他 Bot,該筆以 error 說明原因、整體仍回 200。整批有 30 秒時間預算,超過後其餘 Bot 不查詢並帶 error,請改用 GET /api/bots/{id}/quota 單獨查詢。
curl -X GET "http://YOUR_DOMAIN/api/bots/17/quota" \
-H "Authorization: Bearer YOUR_API_TOKEN"
本系統提供 Webhook URL,您可以通過 HTTP 請求直接發送訊息而無需使用 API Token。
端點: POST /webhook/{botId}/{token}
描述: 使用 Webhook URL 直接發送通知訊息。請求 body 不含 events 陣列時視為發送請求(含 events 的是 LINE 平台事件)。
獲取方式: 在 Bot 管理頁面中可以看到每個 Bot 生成的唯一 Webhook URL(即上述路徑的完整網址,{botId} 與 {token} 已代入)。
| 參數名稱 | 類型 | 必填 | 描述 |
|---|---|---|---|
| message | string | 是 | 要發送的訊息內容(最多 5000 字元) |
| title | string | 否 | 訊息標題(最多 255 字元),會顯示在訊息開頭 |
| image_url | string | 否 | 要附加的圖片 URL(必須是公開可訪問的圖片) |
| video_url | string | 否 | 要附加的影片 URL(必須是 https:// 開頭、公開可訪問,最多 1000 字元)。需同時提供 preview_image_url,且必須指定發送目標(recipient_id/recipient_ids/recipient_group_id/recipient_group_ids),否則回傳 422 |
| preview_image_url | string | 否 | 影片的預覽縮圖 URL(必須是 https:// 開頭,最多 1000 字元)。帶 video_url 時必填;單獨使用會回傳 422 |
| recipient_id | string | 否 | 指定單一接收者的 LINE 用戶 ID |
| recipient_ids | array 或 string | 否 | 指定多個接收者的 LINE 用戶 ID 陣列,最多 500 個。也可以用逗號分隔的字串,例如: "id1,id2,id3" |
| send_to_all | boolean | 否 | 是否發送給所有會員(廣播,需謹慎使用) |
| recipient_group_id | string | 否 | 指定單一接收群組的 LINE 群組 ID |
| recipient_group_ids | array 或 string | 否 | 指定多個接收群組的 LINE 群組 ID 陣列。也可以用逗號分隔的字串,例如: "id1,id2,id3" |
{
"status": "success",
"message": "訊息發送成功",
"data": {
"recipients_count": 1,
"sent_at": "2023-12-31T12:34:56"
}
}
{
"status": "error",
"message": "錯誤訊息",
"errors": {
"message": ["訊息內容不能為空"]
}
}
# 基本用法
curl -X POST \
"YOUR_WEBHOOK_URL" \
-H 'Content-Type: application/json' \
-d '{"message":"Hello World"}'
# 添加標題和圖片
curl -X POST \
"YOUR_WEBHOOK_URL" \
-H 'Content-Type: application/json' \
-d '{
"message":"這是訊息內容",
"title":"訊息標題",
"image_url":"https://example.com/image.jpg"
}'
# 發送給特定用戶
curl -X POST \
"YOUR_WEBHOOK_URL" \
-H 'Content-Type: application/json' \
-d '{
"message":"這是發送給特定用戶的訊息",
"recipient_id":"U4af4980629..."
}'
# 群發給多個用戶
curl -X POST \
"YOUR_WEBHOOK_URL" \
-H 'Content-Type: application/json' \
-d '{
"message":"這是群發訊息",
"recipient_ids":["U4af4980629...", "U8c6d6tx42b..."]
}'
# 發送給特定群組
curl -X POST \
"YOUR_WEBHOOK_URL" \
-H 'Content-Type: application/json' \
-d '{
"message":"這是發送給特定群組的訊息",
"recipient_group_id":"C4af4980629..."
}'
# 群發給多個群組
curl -X POST \
"YOUR_WEBHOOK_URL" \
-H 'Content-Type: application/json' \
-d '{
"message":"這是群發給多個群組的訊息",
"recipient_group_ids":["C4af4980629...", "C8c6d6tx42b..."]
}'
<?php
$webhookUrl = 'YOUR_WEBHOOK_URL';
// 基本用法
function sendWebhook($message, $extraParams = []) {
global $webhookUrl;
// 準備請求資料
$data = array_merge(['message' => $message], $extraParams);
// 初始化 cURL
$ch = curl_init($webhookUrl);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($data),
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
]);
// 執行請求
$response = curl_exec($ch);
$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return [
'code' => $statusCode,
'response' => json_decode($response, true)
];
}
// 發送基本訊息
$result = sendWebhook('Hello World');
// 添加標題和圖片
$result = sendWebhook('這是訊息內容', [
'title' => '訊息標題',
'image_url' => 'https://example.com/image.jpg'
]);
// 發送給特定用戶
$result = sendWebhook('這是發送給特定用戶的訊息', [
'recipient_id' => 'U4af4980629...'
]);
// 群發給多個用戶
$result = sendWebhook('這是群發訊息', [
'recipient_ids' => ['U4af4980629...', 'U8c6d6tx42b...']
]);
// 發送給特定群組
$result = sendWebhook('這是發送給特定群組的訊息', [
'recipient_group_id' => 'C4af4980629...'
]);
// 群發給多個群組
$result = sendWebhook('這是群發給多個群組的訊息', [
'recipient_group_ids' => ['C4af4980629...', 'C8c6d6tx42b...']
]);
const webhookUrl = 'YOUR_WEBHOOK_URL';
// 基本發送函數
async function sendWebhook(message, extraParams = {}) {
try {
const response = await fetch(webhookUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
message,
...extraParams
})
});
return await response.json();
} catch (error) {
console.error('Error:', error);
return { status: 'error', message: error.message };
}
}
// 基本用法
sendWebhook('Hello World')
.then(result => console.log(result));
// 添加標題和圖片
sendWebhook('這是訊息內容', {
title: '訊息標題',
image_url: 'https://example.com/image.jpg'
}).then(result => console.log(result));
// 發送給特定用戶
sendWebhook('這是發送給特定用戶的訊息', {
recipient_id: 'U4af4980629...'
}).then(result => console.log(result));
// 群發給多個用戶
sendWebhook('這是群發訊息', {
recipient_ids: ['U4af4980629...', 'U8c6d6tx42b...']
}).then(result => console.log(result));
// 發送給特定群組
sendWebhook('這是發送給特定群組的訊息', {
recipient_group_id: 'C4af4980629...'
}).then(result => console.log(result));
// 群發給多個群組
sendWebhook('這是群發給多個群組的訊息', {
recipient_group_ids: ['C4af4980629...', 'C8c6d6tx42b...']
}).then(result => console.log(result));
// Google Apps Script 範例
// 設定 Webhook URL
var WEBHOOK_URL = 'YOUR_WEBHOOK_URL';
/**
* 基本發送函數
*
* @param {string} message 訊息內容
* @param {object} extraParams 額外參數
* @return {object} API 回應
*/
function sendWebhook(message, extraParams) {
// 準備請求資料
var payload = {
'message': message
};
// 合併額外參數
if (extraParams) {
for (var key in extraParams) {
payload[key] = extraParams[key];
}
}
// 設定 API 請求選項
var options = {
'method': 'post',
'contentType': 'application/json',
'payload': JSON.stringify(payload),
'muteHttpExceptions': true
};
// 發送 API 請求
var response = UrlFetchApp.fetch(WEBHOOK_URL, options);
// 解析 API 回應
var result = JSON.parse(response.getContentText());
// 記錄結果
Logger.log('發送結果: ' + result.message);
return result;
}
/**
* 發送基本訊息
*/
function sendBasicMessage() {
sendWebhook('Hello World');
}
/**
* 發送帶標題和圖片的訊息
*/
function sendRichMessage() {
sendWebhook('這是訊息內容', {
'title': '訊息標題',
'image_url': 'https://example.com/image.jpg'
});
}
/**
* 發送訊息給特定用戶
*/
function sendToSpecificUser() {
sendWebhook('這是發送給特定用戶的訊息', {
'recipient_id': 'U4af4980629...'
});
}
/**
* 群發訊息給多個用戶
*/
function sendToMultipleUsers() {
sendWebhook('這是群發訊息', {
'recipient_ids': ['U4af4980629...', 'U8c6d6tx42b...']
});
}
/**
* 發送訊息給特定群組
*/
function sendToSpecificGroup() {
sendWebhook('這是發送給特定群組的訊息', {
'recipient_group_id': 'C4af4980629...'
});
}
/**
* 群發訊息給多個群組
*/
function sendToMultipleGroups() {
sendWebhook('這是群發給多個群組的訊息', {
'recipient_group_ids': ['C4af4980629...', 'C8c6d6tx42b...']
});
}
/**
* 與 Google Sheet 整合範例
* 根據試算表內容發送訊息
*/
function sendMessagesFromSheet() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var dataRange = sheet.getRange("A2:C" + sheet.getLastRow());
var data = dataRange.getValues();
for (var i = 0; i < data.length; i++) {
var row = data[i];
var message = row[0]; // A列:訊息內容
var userId = row[1]; // B列:LINE用戶ID
var isSent = row[2]; // C列:是否已發送
// 如果尚未發送
if (!isSent) {
// 發送訊息
var result = sendWebhook(message, {
'recipient_id': userId
});
// 如果發送成功,標記為已發送
if (result.status === 'success') {
sheet.getRange(i + 2, 3).setValue(true);
}
}
}
}