การผสานรวม Webhook
Webhook ของ SORI API จะแจ้งระบบของคุณเกี่ยวกับเหตุการณ์สำคัญที่เกิดขึ้นภายใน แพลตฟอร์ม SORI เมื่อเชื่อมต่อ endpoint ของคุณเอง คุณจะตอบสนองต่อกิจกรรมของ แคมเปญ การยืนยันตัวตนของอุปกรณ์ และการอัปเดตโดยผู้ดูแลระบบได้แบบเกือบเรียลไทม์
ภาพรวม
SORI API มีฟังก์ชัน Webhook สำหรับส่ง payload แบบ JSON ที่มีโครงสร้างทันทีที่ เกิดเหตุการณ์สำคัญ โดยกำหนดค่า Webhook ได้ภายใน SORI Console และรองรับหมวดหมู่ ต่อไปนี้:
- เหตุการณ์แคมเปญ (`campaign.*`) ทริกเกอร์เมื่ออุปกรณ์รู้จำแคมเปญได้ หรือเมื่อผู้ใช้คลิกไปยัง action URL
- เหตุการณ์การยืนยันตัวตน (`authentication`) ทริกเกอร์เมื่ออุปกรณ์ลงชื่อเข้าใช้ผ่านขั้นตอนการยืนยันตัวตนของ SORI สำเร็จ
- เหตุการณ์เกี่ยวกับสื่อ (Material) ของผู้ดูแลระบบ (`admin.material.*`)การแจ้งเตือนแบบเลือกใช้ ซึ่งส่งออกมาเมื่อมีการสร้าง อัปเดต หรือลบสื่อภายใน Console
การแจ้งเตือนแบบเกือบเรียลไทม์ช่วยให้คุณสามารถ:
- การวิเคราะห์ทันที ติดตามและวิเคราะห์ประสิทธิภาพของแคมเปญทันทีที่มีกิจกรรมเกิดขึ้น
- การตรวจสอบการยืนยันตัวตน กระทบยอดการเข้าสู่ระบบของอุปกรณ์กับบันทึกเซสชันของคุณเอง
- การตรวจจับการทุจริต ตรวจจับรูปแบบที่ผิดปกติทันทีที่เกิดขึ้น
- แดชบอร์ดสด แสดงข้อมูลล่าสุดบนแดชบอร์ด
การตั้งค่า Webhook
SORI มีสองวิธีในการกำหนดค่า endpoint ของ Webhook:
URL ของ Webhook ส่วนกลาง
- ตั้งค่าในส่วน Settings
- ใช้กับทุกแคมเปญโดยค่าเริ่มต้น
- ทำหน้าที่เป็น endpoint สำรองเมื่อแคมเปญไม่ได้กำหนดค่าแทนที่
URL ของ Webhook เฉพาะแคมเปญ
- กำหนดค่าใน Advanced settings ของแต่ละแคมเปญ
- แทนที่ URL ของ Webhook ส่วนกลางสำหรับแคมเปญนั้นโดยเฉพาะ
- มีประโยชน์เมื่อแคมเปญแต่ละรายการต้องใช้การจัดการเฉพาะ
การสมัครรับเหตุการณ์ (Settings → Webhooks)
ใน Account Settings คุณสามารถเลือกหมวดหมู่เหตุการณ์ที่บัญชีจะรับได้:
- Campaign events: สมัครรับการแจ้งเตือน
campaign.*(กิจกรรม impression และ click) - Authentication events: สมัครรับเหตุการณ์
authenticationที่ส่งออกมาระหว่างอุปกรณ์เข้าสู่ระบบ - Administrative events: สมัครรับการแจ้งเตือน
admin.material.*ที่ส่งเมื่อผู้ใช้ Console จัดการสื่อ
บัญชีใหม่จะเปิดใช้ Campaign events และ Authentication events โดยค่าเริ่มต้น ผู้ดูแลระบบสามารถปรับช่องทำเครื่องหมายเหล่านี้ได้ทุกเมื่อ และการเปลี่ยนแปลงจะมีผล ทันทีต่อการส่ง Webhook ครั้งถัดไป
วิธีตั้งค่า Webhook
- เตรียม endpoint แบบ HTTPS บนเซิร์ฟเวอร์เพื่อรับเหตุการณ์ Webhook
- กำหนดค่าอย่างใดอย่างหนึ่งต่อไปนี้:
- URL ของ Webhook ส่วนกลางใน Settings หรือ
- URL ของ Webhook เฉพาะแคมเปญในการตั้งค่าของแต่ละแคมเปญ
- เลือกหมวดหมู่เหตุการณ์ที่ต้องการรับใน Settings → Webhooks
- ตรวจสอบว่า endpoint รองรับคำขอ POST ที่มี payload แบบ JSON และตอบกลับ อย่างรวดเร็ว (ภายในห้าวินาที)
ประเภทเหตุการณ์
payload ของ Webhook แต่ละรายการมีฟิลด์ event ซึ่งเก็บชื่อเหตุการณ์มาตรฐาน เพื่อความชัดเจน การผสานรวมใหม่ควรแยกการทำงานตามค่า event
เหตุการณ์การแสดงผลแคมเปญ (campaign.impression)
ส่งเมื่อแคมเปญแสดงบนอุปกรณ์ของผู้ใช้สำเร็จ เหตุการณ์นี้พร้อมใช้งานเมื่อเปิดใช้ Campaign events
เหตุการณ์การคลิกแคมเปญ (campaign.click)
ส่งเมื่อผู้ใช้แตะแคมเปญและถูกเปลี่ยนเส้นทางไปยัง action URL เหตุการณ์นี้พร้อมใช้งาน เมื่อเปิดใช้ Campaign events
เหตุการณ์การยืนยันตัวตน (authentication)
ส่งหลังจากอุปกรณ์ยืนยันตัวตนกับ SORI เสร็จสมบูรณ์ payload มีพารามิเตอร์ query ที่ส่งมาพร้อมกับคำขอยืนยันตัวตน ซึ่งใช้เชื่อมโยงการเข้าสู่ระบบกับตัวระบุเซสชัน ของคุณเองได้
การจัดการเหตุการณ์ Webhook
เมื่อ endpoint ได้รับเหตุการณ์ Webhook จะมี payload แบบ JSON ที่ระบุรายละเอียด ของเหตุการณ์ ตัวอย่างของเหตุการณ์แต่ละประเภทแสดงไว้ด้านล่าง ฟิลด์ที่ระบุเป็น null อาจถูกละไว้ทั้งหมดเมื่อไม่มีค่า
Schema ของ payload
ฟิลด์ต่อไปนี้จะถูกส่งมากับ Webhook ของแคมเปญทุกรายการ เว้นแต่จะระบุไว้เป็นอย่างอื่น
| ฟิลด์ | ประเภท | คำอธิบาย |
|---|---|---|
event | string | ชื่อเหตุการณ์มาตรฐาน เช่น campaign.impression, campaign.click หรือ authentication |
event_type | string | สำเนาเดิมของ event ซึ่งยังส่งออกมาเพื่อรองรับความเข้ากันได้ย้อนหลัง |
account_id | string | ตัวระบุบัญชี SORI ที่เป็นเจ้าของแคมเปญ |
created_at | ISO 8601 string | เวลาฝั่งเซิร์ฟเวอร์เมื่อสร้างออบเจ็กต์เหตุการณ์ |
timestamp | ISO 8601 string | เวลาประทับการส่งที่เพิ่มก่อนส่งออก ใช้ประโยชน์ในการตรวจสอบ idempotency |
activity_id | string | ตัวระบุที่ไม่ซ้ำกันของ impression หรือ click นั้น (เฉพาะเหตุการณ์แคมเปญ) |
device_id | string | อุปกรณ์/เซสชันที่ทริกเกอร์เหตุการณ์ หากมีข้อมูล |
platform | string | แพลตฟอร์มไคลเอนต์ที่ SDK รายงาน (Android, iOS เป็นต้น) |
metadata | object | คู่คีย์-ค่าแบบกำหนดเองที่ส่งต่อจาก SDK หรือคำขอยืนยันตัวตน |
geolocation.viewer_country | string | ประเทศที่ได้จาก CloudFront GeoIP (ส่งคืน Unknown หากตรวจหาไม่ได้) |
geolocation.viewer_region | string | ภูมิภาค/รัฐที่ได้จากการค้นหา GeoIP |
geolocation.viewer_city | string | เมืองที่ได้จากการค้นหา GeoIP |
campaign.id | string | ตัวระบุแคมเปญที่ปรับให้อยู่ในรูปแบบมาตรฐาน ซึ่งรับประกันว่าตรงกับ ID ใน Console |
campaign.name | string | ชื่อแคมเปญที่แสดง ณ เวลาที่เกิดเหตุการณ์ |
campaign.tags | string[] | แท็กที่กำหนดให้แคมเปญ (อาร์เรย์ว่างหากไม่มี) |
campaign.image | string (URL) | URL แบบ HTTPS ของภาพขนาดย่อของแคมเปญ หากกำหนดไว้ |
material.id | string | ตัวระบุสื่อที่รู้จำได้ (เฉพาะเหตุการณ์แคมเปญ) |
material.name | string | ชื่อสื่อ โดยจะละฟิลด์นี้เมื่อไม่มีสื่อที่เกี่ยวข้อง |
material.tags | string[] | แท็กที่จัดเก็บไว้ในระเบียนสื่อ (อาร์เรย์ว่างหากไม่มี) |
material.image | string (URL) | URL ของภาพตัวอย่างสื่อ หากมี |
ฟิลด์เดิม
event_type, campaign_id, campaign_name, material_id และ material_name เป็นฟิลด์ซ้ำแบบเดิมที่คงไว้เพื่อรองรับความเข้ากันได้ย้อนหลังเท่านั้น และจะถูกนำออก ในรุ่นถัดไป โปรดปรับการผสานรวมให้ใช้ฟิลด์ event ร่วมกับออบเจ็กต์ campaign และ material ที่ซ้อนอยู่ เพื่อความชัดเจน payload ตัวอย่างด้านล่างจึงไม่รวม คีย์ที่เลิกใช้เหล่านี้
สำหรับเหตุการณ์ impression:
{
"event": "campaign.impression",
"account_id": "acc_123456",
"created_at": "2025-10-14T05:25:12.421Z",
"activity_id": "act_7890",
"device_id": "device_abc",
"platform": "Android",
"metadata": {
"session": "abcd-1234"
},
"geolocation": {
"viewer_country": "United States",
"viewer_region": "Michigan",
"viewer_city": "Ann Arbor"
},
"campaign": {
"id": "cmp_1234",
"name": "Fall Promotion",
"tags": [
"retail",
"autumn"
],
"image": "https://cdn.soriapi.com/campaigns/cmp_1234.png"
},
"material": {
"id": "mat_5678",
"name": "Audio Spot 15s",
"tags": [
"audio",
"15s"
],
"image": "https://cdn.soriapi.com/materials/mat_5678.png"
},
"timestamp": "2025-10-14T05:25:12.421Z"
}สำหรับเหตุการณ์ click:
{
"event": "campaign.click",
"account_id": "acc_123456",
"created_at": "2025-10-14T05:26:03.009Z",
"activity_id": "act_7890",
"device_id": "device_abc",
"platform": "Android",
"metadata": {
"session": "abcd-1234",
"utm_source": "push"
},
"geolocation": {
"viewer_country": "United States",
"viewer_region": "Michigan",
"viewer_city": "Ann Arbor"
},
"campaign": {
"id": "cmp_1234",
"name": "Fall Promotion",
"tags": [
"retail",
"autumn"
],
"image": "https://cdn.soriapi.com/campaigns/cmp_1234.png"
},
"material": {
"id": "mat_5678",
"name": "Audio Spot 15s",
"tags": [
"audio",
"15s"
],
"image": "https://cdn.soriapi.com/materials/mat_5678.png"
},
"timestamp": "2025-10-14T05:26:03.009Z"
}สำหรับเหตุการณ์การยืนยันตัวตน:
{
"event": "authentication",
"account_id": "acc_123456",
"created_at": "2025-10-14T05:15:44.832Z",
"device_id": "device_abc",
"platform": "Android",
"metadata": {
"app_version": "1.8.0",
"session": "abcd-1234"
},
"geolocation": {
"viewer_country": "United States",
"viewer_region": "Michigan",
"viewer_city": "Ann Arbor"
},
"timestamp": "2025-10-14T05:15:44.832Z"
}Metadata แบบกำหนดเอง
ฟิลด์ metadata คือแมปแบบคีย์-ค่าที่ SDK ส่งมา (สำหรับเหตุการณ์แคมเปญ) หรือมาจากพารามิเตอร์ query ของคำขอยืนยันตัวตน (สำหรับเหตุการณ์การยืนยันตัวตน) ฟิลด์นี้ใช้ระบุผู้ใช้หรืออุปกรณ์และส่งบริบทเพิ่มเติมได้ โดยเป็นฟิลด์ที่เลือกใช้ได้ โปรดดูรายละเอียดเพิ่มเติมในส่วน ตัวให้บริการ Metadata
หมายเหตุเกี่ยวกับข้อมูลตำแหน่ง
ค่าตำแหน่งทางภูมิศาสตร์อยู่ภายในออบเจ็กต์ geolocation ข้อมูลนี้อ้างอิงจาก การประมาณค่าของ CloudFront GeoIP และอาจไม่แม่นยำเสมอไป หากไม่มีข้อมูลที่แน่นอน ระบบจะส่งคืนค่า Unknown
ข้อกำหนดในการตอบกลับ
endpoint ของ Webhook ควร:
- ตอบกลับด้วยรหัสสถานะ
2xxเพื่อยืนยันว่าได้รับข้อมูลแล้ว - ประมวลผลเหตุการณ์แบบอะซิงโครนัสหากทำได้ เพื่อหลีกเลี่ยงการบล็อก
- จัดการเหตุการณ์แบบ idempotent (โดยใช้เวลาประทับหรือ activity ID)
- ตอบกลับภายใน 5 วินาที เพื่อหลีกเลี่ยงการหมดเวลา
ข้อควรพิจารณาด้านความปลอดภัย
- ใช้ HTTPS สำหรับ endpoint ของ Webhook ทุกครั้งที่ทำได้ เพื่อรักษาความเป็นส่วนตัวของข้อมูล
- ตรวจสอบโครงสร้าง payload ที่เข้ามาและยืนยันค่า
event - เก็บ URL ของ Webhook ไว้เป็นความลับ
- เมื่อกำหนดค่า
app_idและsecret_keyแล้ว ให้ตรวจสอบ headerX-SORI-Signatureกับสำเนา payload ของคุณเพื่อยืนยันความถูกต้อง
การจัดการข้อผิดพลาด
หาก endpoint รับเหตุการณ์ไม่สำเร็จ SORI API Server จะ:
- ลองส่งรายการที่ล้มเหลวใหม่สูงสุด 3 ครั้ง
- ใช้การหน่วงเวลาแบบทวีคูณ (exponential backoff) ระหว่างการลองใหม่แต่ละครั้ง
- ยกเลิกเหตุการณ์หลังจากลองใหม่ครบทุกครั้งแล้ว
ตัวอย่างการนำไปใช้
Python (FastAPI)
from fastapi import FastAPI, Request
app = FastAPI()
@app.post("/webhook")
async def webhook(request: Request):
payload = await request.json()
event = payload.get("event")
if event == "campaign.impression":
# Handle impression event
pass
elif event == "campaign.click":
# Handle click event
pass
elif event == "authentication":
# Handle authentication event
pass
return {"status": "success"}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=3000)Node.js (Express)
import express from "express";
const app = express();
app.use(express.json());
app.post("/webhook", (req, res) => {
const payload = req.body;
const event = payload.event;
if (event === "campaign.impression") {
// Handle impression event
} else if (event === "campaign.click") {
// Handle click event
} else if (event === "authentication") {
// Handle authentication event
}
res.status(200).send({ status: "success" });
});
app.listen(3000, () => {
console.log("Server is running on port 3000");
});