ใช้ Sender Token เพื่อส่งการแจ้งเตือนผ่าน API ของระบบหลังบ้าน (ควรใช้ฝั่งเซิร์ฟเวอร์เท่านั้น และเก็บโทเค็นนี้เป็นความลับ)
| Key | ความหมาย |
|---|---|
| sender_token String (Required) |
Sender Token ที่ได้จากแอป (เก็บเป็นความลับ); ระบบเก่ายังส่งชื่อ receiver_token ได้ แต่ควรใช้ชื่อนี้ |
| title String (Required) |
หัวข้อของการแจ้งเตือน |
| body String (Required) |
ข้อความสำรองแบบ Plain ที่ต้องส่งเสมอ แม้ใช้ Markdown เพื่อให้ Receiver รุ่นเก่าแสดงผลได้ |
| content_type String (Optional) |
ชนิดเนื้อหา: plain (ค่าเริ่มต้น) หรือ markdown ห้ามใช้ HTML |
| body_markdown String (Conditional) |
Markdown ที่จะแสดงบน Receiver เมื่อ content_type=markdown; ต้องไม่ว่าง และไม่รองรับ HTML, WebView หรือ JavaScript |
| actions Array (Conditional) |
ปุ่มตอบกลับไม่เกิน 3 ปุ่ม ดูกติกาในหัวข้อ Interactive Action; ถ้าไม่ต้องการปุ่มให้ละ field นี้ |
| request_id String (Conditional) |
รหัสคำขอของระบบคุณ ต้องมีเมื่อส่ง actions และห้ามซ้ำภายใน Sender เดียวกัน |
| expires_at ISO-8601 (Conditional) |
เวลาหมดอายุของ action ต้องอยู่ในอนาคตและไม่เกิน 24 ชั่วโมงจากเวลาที่รับคำขอ |
| target_id String (Optional) |
Target เดียวแบบเดิม ใช้ได้กับ Push ทั่วไป และต้องใช้ field นี้ (ไม่ใช่ target_ids) เมื่อมี Interactive Action |
| target_ids Array (Optional) |
ระบุ Target หลายค่าในรูปแบบ array; ถ้าไม่ใส่จะเป็น Broadcast และห้ามใช้ร่วมกับ Interactive Action |
| data.custom_tag String (Optional) |
แท็กที่กำหนดเองสำหรับให้ Receiver แยกการ์ดหรือกรองข้อความ เช่น attendance, billing, homework |
| data.* Object (Optional) |
ข้อมูลเพิ่มเติมของระบบคุณ ทุกค่าจะถูกแปลงเป็น String; หลีกเลี่ยงชื่อที่ขึ้นต้นด้วย _ ซึ่งสงวนไว้สำหรับ metadata ของ NotiPush |
ตัวอย่าง Response เมื่อ Firebase พร้อมใช้งาน
{
"ok": true,
"successCount": 1,
"failureCount": 0
}
sent=0; ถ้า Firebase ยังไม่พร้อมแต่มี Receiver ระบบจะตอบ simulated=true พร้อมจำนวนอุปกรณ์ใน sent. ข้อความ Markdown/Interactive จะมี message_id ทั้งสองกรณี
{
"ok": true,
"simulated": true,
"sent": 1,
"message_id": "message-uuid-for-rich-message"
}
สำหรับข้อความ Rich ในโหมด Firebase ค่า message_id จะอยู่ใน metadata ของ FCM เพื่อให้ Receiver ดึงรายละเอียดจาก Backend; ผู้เรียก API ควรใช้ค่า success/failure เป็นผลการส่งหลัก
| รหัสสถานะ | ความหมาย | รายละเอียดเพิ่มเติม |
|---|---|---|
400 |
คำขอไม่ถูกต้อง | ขาด sender_token, title หรือ body; หรือ field ของ Markdown/Action ไม่ถูกต้อง |
403 |
ถูกปฏิเสธ | sender_token ไม่ถูกต้อง, plan หมดอายุ, ใช้โควตารายวันครบ, demo ถูกปิด หรือเนื้อหาถูกบล็อก |
409 |
ขัดแย้ง | request_id ซ้ำภายใน Sender เดิม (duplicate_request_id) |
413 |
Payload ใหญ่เกินไป | ระบบลดขนาดแล้วแต่ยังเกินขีดจำกัด FCM 4096 bytes (payload_too_large) |
422 |
ข้อมูลไม่สมบูรณ์ | พบข้อความซ้ำภายใน 5 วินาที (duplicate_message) |
429 |
ส่งคำขอบ่อยเกินไป | เกิน limit ต่อวินาทีของแผน (too_many_requests) |
500 |
ข้อผิดพลาดเซิร์ฟเวอร์ | ฐานข้อมูล, Firebase หรือระบบภายในผิดพลาด (fcm_error หรือ server_error) |
ข้อความ Markdown ใช้ได้กับ Sender ทุก policy โดยต้องส่ง body แบบ Plain เป็น fallback เสมอ ส่วนปุ่ม Interactive ใช้ได้เฉพาะ Sender ที่ตั้งเป็น verified_target และต้องยืนยัน Target ก่อน
curl -X POST "https://notipush.app/api/send-push" \
-H "Content-Type: application/json" \
-d '{
"sender_token": "YOUR_SENDER_TOKEN",
"title": "ยืนยันรายการ",
"body": "กรุณาเปิดแอปเพื่อยืนยันรายการ",
"content_type": "markdown",
"body_markdown": "**รายละเอียดรายการ**\n\nยอดรวม: **1,000 บาท**",
"target_id": "TARGET_ID",
"request_id": "REQUEST_ID",
"expires_at": "EXPIRY_ISO8601_WITHIN_24_HOURS",
"actions": [
{ "id": "approve", "label": "อนุมัติ", "style": "primary" },
{ "id": "deny", "label": "ปฏิเสธ", "style": "danger" }
],
"data": { "custom_tag": "billing" }
}'
| กติกา | รายละเอียด |
|---|---|
content_type |
ใช้ plain (ค่าเริ่มต้น) หรือ markdown; ไม่รองรับ html, WebView หรือ JavaScript |
actions |
มีได้ไม่เกิน 3 รายการ และแต่ละรายการต้องมี id (A-Z, a-z, 0-9, underscore หรือ hyphen), label 1–80 ตัวอักษร และ style เป็น primary, secondary, success หรือ danger |
target_id |
Interactive ต้องใช้ Target เดียวผ่าน field นี้เท่านั้น; ใช้ target_ids หรือค่าที่มี comma จะถูกปฏิเสธ |
request_id |
ต้องมีเมื่อมี action และต้องไม่ซ้ำภายใน Sender เดิม; ซ้ำแล้วตอบ 409 duplicate_request_id โดยไม่ส่งซ้ำ |
expires_at |
ต้องมีเมื่อมี action เป็นเวลา ISO-8601 ที่อยู่ในอนาคตและไม่เกิน 24 ชั่วโมง; เมื่อหมดอายุ Receiver จะกด action ไม่ได้ |
body, body_markdown หรือ data
หากใช้ actions ระบบ Sender ต้องตั้งค่า verification URL, action webhook URL และ secret ผ่านหน้า Sender Integration ก่อนเปิดใช้ verified_target โดย URL ต้องเป็น HTTPS port 443 และห้ามมี redirect ไปยัง private address
เมื่อ Receiver ลงทะเบียน Target แบบ protected ระบบจะส่ง signed POST ไปยัง verification URL ของคุณ ให้ตอบ JSON นี้เมื่อรหัสถูกต้องและ Target ผูกกับผู้ใช้ของคุณแล้ว
POST https://YOUR_INTEGRATION_HOST/notipush/verify
X-NotiPush-Event-ID: EVENT_UUID
X-NotiPush-Timestamp: UNIX_TIMESTAMP
X-NotiPush-Signature: v1=HMAC_SHA256_HEX
{
"event_id": "EVENT_UUID",
"type": "subscription.verify",
"sender_id": "SENDER_UUID",
"notify_token": "NOTIFY_TOKEN_UUID",
"target_id": "TARGET_ID",
"verification_code": "ONE_TIME_CODE",
"receiver_install_id": "INSTALL_UUID",
"platform": "android",
"timestamp": "2026-09-11T00:00:00.000Z"
}
HTTP 200
{ "verified": true, "external_subject_id": "EXTERNAL_SUBJECT_ID" }
เมื่อ Receiver กด action ระบบจะบันทึก event ก่อน แล้วส่ง signed POST ไปยัง action webhook แบบ asynchronous; endpoint ของคุณต้องใช้ event_id ทำ idempotency
POST https://YOUR_INTEGRATION_HOST/notipush/action
X-NotiPush-Event-ID: EVENT_UUID
X-NotiPush-Timestamp: UNIX_TIMESTAMP
X-NotiPush-Signature: v1=HMAC_SHA256_HEX
{
"event_id": "EVENT_UUID",
"type": "notification.action",
"sender_id": "SENDER_UUID",
"message_id": "MESSAGE_UUID",
"request_id": "REQUEST_ID",
"action_id": "approve",
"target_id": "TARGET_ID",
"external_subject_id": "EXTERNAL_SUBJECT_ID",
"receiver_install_id": "INSTALL_UUID",
"responded_at": "2026-09-11T00:00:00.000Z"
}
ตรวจลายเซ็นด้วย HMAC-SHA256 บนค่า UNIX_TIMESTAMP + '.' + raw JSON body และยอมรับเฉพาะ timestamp ที่อยู่ในหน้าต่างเวลาที่ระบบของคุณกำหนด
event_id เดิม 2xx ถือว่าสำเร็จ ส่วน 4xx ที่ไม่ใช่ 408/425/429 จะจบเป็น failed
ใช้ endpoint นี้จากระบบของคุณเมื่อ Target ไม่ควรรับแจ้งเตือนอีกต่อไป เช่น เปลี่ยนผู้ใช้หรือยกเลิกสิทธิ์ ระบบจะ revoke เฉพาะ verified subscription ของ Target นั้น และไม่ลบประวัติ
curl -X POST "https://notipush.app/api/sender/targets/revoke" \
-H "Content-Type: application/json" \
-d '{
"sender_token": "YOUR_SENDER_TOKEN",
"target_id": "TARGET_ID"
}'
{ "ok": true, "revoked_count": 1 }
ต้องส่ง Target เดียวเท่านั้น (ห้าม comma หรือ array) และ endpoint นี้ใช้ Sender Token จึงควรเรียกจาก server ของคุณเท่านั้น
คุณสามารถสร้างลิงก์สำหรับให้ผู้รับ (Receiver) สแกนหรือกดเปิดเพื่อเพิ่มช่องรับแจ้งเตือนได้อัตโนมัติ โดยใส่ Notify Token และ Target ID (ถ้าต้องการ) ลงในลิงก์
ใช้ลิงก์นี้ได้ทั้งบนเว็บ, แอป และ QR Code — จะ redirect ไปเปิดแอป Receiver อัตโนมัติ หรือพาไป App Store/Play Store หากยังไม่ได้ติดตั้ง
หากต้องการระบุ Target ID ด้วย:
| Parameter | ความหมาย |
|---|---|
| t String (Required) |
Notify Token ของคุณ (ค่าสาธารณะ ไม่ใช่ Sender Token) |
| tg String (Optional) |
Target ID สำหรับติดป้ายกำกับอุปกรณ์/กลุ่มของผู้รับ (ระบบของคุณเป็นคนกำหนด) |
นำลิงก์ที่สร้างด้านบนไปสร้าง QR Code ด้วยเว็บไซต์ หรือ Library ในภาษาโปรแกรมของคุณ ไม่มี endpoint สำหรับสร้าง QR Code บนเซิร์ฟเวอร์ ผู้รับสแกน QR Code แล้วจะเปิดแอป Receiver พร้อมลงทะเบียนอัตโนมัติ
import qrcode
notify_token = "YOUR_NOTIFY_TOKEN"
target_id = "room-101" # Optional
url = f"https://notipush.app/r/?t={notify_token}&tg={target_id}"
img = qrcode.make(url)
img.save("notipush_qr.png")
print(f"QR Code saved: {url}")
const QRCode = require('qrcode');
const notifyToken = "YOUR_NOTIFY_TOKEN";
const targetId = "room-101"; // Optional
const url = `https://notipush.app/r/?t=${notifyToken}&tg=${targetId}`;
QRCode.toFile('notipush_qr.png', url, (err) => {
if (err) throw err;
console.log(`QR Code saved: ${url}`);
});
Target ID คือค่าที่ระบบของคุณ (Sender) เป็นคนกำหนดขึ้นมา ฝังไว้ในลิงก์หรือ QR Code ตอนที่ผู้รับลงทะเบียน เมื่อจำเป็นต้องส่งแจ้งเตือนเจาะจง คุณระบุ target_id ใน API call แล้วเฉพาะอุปกรณ์ที่ลงทะเบียนด้วย ID นั้นเท่านั้นที่จะได้รับ
target_id สำหรับ Target เดียว หรือ target_ids สำหรับหลาย Target; ไม่ใส่ทั้งสอง field คือ Broadcast. Interactive Action ต้องใช้ target_id เดียวเท่านั้นออกแบบ Target ID ตามโครงสร้างของระบบคุณ เช่น รหัสลูกค้า, ชื่อห้อง, แผนก, สาขา เป็นต้น
ใส่ Target ID ลงในลิงก์ แล้วสร้าง QR Code หรือส่งลิงก์ให้ผู้รับ
แอป Receiver จะลงทะเบียนพร้อมผูก Target ID ไว้กับอุปกรณ์โดยอัตโนมัติ
เรียก API พร้อมใส่ target_id จะส่งเฉพาะอุปกรณ์ที่ลงทะเบียนด้วย ID นั้น ถ้าไม่ใส่จะส่งหาทุกคน (Broadcast)
| สถานการณ์ | Target ID | ลิงก์ตัวอย่าง |
|---|---|---|
| 🏨 แจ้งเตือนเฉพาะห้อง | room-101 |
.../r/?t=TOKEN&tg=room-101 |
| 👤 แจ้งเตือนลูกค้ารายบุคคล | cust-5678 |
.../r/?t=TOKEN&tg=cust-5678 |
| 🏢 แจ้งเตือนเฉพาะแผนก | dept-sales |
.../r/?t=TOKEN&tg=dept-sales |
| 🏪 แจ้งเตือนเฉพาะสาขา | branch-bkk01 |
.../r/?t=TOKEN&tg=branch-bkk01 |
| 📢 ส่งทุกคน (Broadcast) | ไม่ต้องใส่ | .../r/?t=TOKEN |
curl -X POST "https://notipush.app/api/send-push" \
-H "Content-Type: application/json" \
-d '{
"sender_token": "YOUR_SENDER_TOKEN",
"title": "ห้อง 101 — อาหารพร้อมเสิร์ฟ",
"body": "กรุณามารับที่เคาน์เตอร์ชั้น 1",
"target_ids": ["room-101"]
}'
curl -X POST "https://notipush.app/api/send-push" \
-H "Content-Type: application/json" \
-d '{
"sender_token": "YOUR_SENDER_TOKEN",
"title": "แจ้งเตือนฉุกเฉิน",
"body": "กรุณาอพยพออกจากอาคารทันที",
"target_ids": ["floor-1", "floor-2", "emergency"]
}'
💡 ไม่ใส่ target_ids = ส่งหาทุกคนที่ติดตามช่องนี้ (Broadcast) | ใส่ target_ids = ส่งหาอุปกรณ์ที่ลงทะเบียนด้วย ID ใดๆ ในรายการ (array มีค่าเดียวก็ได้สำหรับเป้าหมายเดียว)
room-{หมายเลข}, cust-{รหัส})tg=TARGET_ID ที่แตกต่างกันสำหรับแต่ละอุปกรณ์หรือกลุ่มtarget_ids ใน API call ตาม Mapping ที่เก็บไว้