เอกสารประกอบ
Outbound webhook: payload และลายเซ็น
รับการแจ้งเตือนและรายงานจาก AutoPSEO เป็น JSON ที่มีลายเซ็นที่ปลายทาง HTTPS ใดก็ได้ ครอบคลุม request header, ฟิลด์ใน body, ประเภทอีเวนต์ และวิธีตรวจสอบลายเซ็น
Outbound webhook จะส่งการแจ้งเตือน รายงานที่ตั้งเวลาไว้ ข้อความทดสอบ และสรุปรายงานจาก AutoPSEO ไปยังปลายทางที่คุณดูแลเอง โดยส่งเป็น JSON POST หนึ่งครั้งต่อหนึ่งข้อความ และลงลายเซ็นด้วย HMAC-SHA256 ใช้ได้กับ Zapier, Make, n8n, เครื่องมือจัดการเหตุการณ์ หรือโค้ดของคุณเอง โดยไม่ต้องมีบัญชี Slack หรือ Teams หากต้องการ webhook ที่ส่งบทความไปยังเว็บไซต์ของคุณ นั่นเป็นส่วนของ content engine ดูการส่งมอบเนื้อหา
เพิ่ม webhook
- ในส่วน Outbound webhooks คลิก New webhook
- ตั้ง Name แล้ววาง URL ของปลายทาง ต้องเป็น HTTPS สาธารณะเท่านั้น ระบบจะปฏิเสธ
httpธรรมดา,localhost, ชื่อที่ลงท้ายด้วย.localหรือ.internal, โฮสต์ที่ไม่มีจุด และ IP แบบ private หรือ link-local - คัดลอกลายเซ็นลับ (signing secret) ที่แสดงหลังบันทึก ระบบจะแสดงให้ดูเพียงครั้งเดียวเท่านั้น
- คลิก Send test เพื่อส่งอีเวนต์
testจากนั้นผูกรายงานที่ตั้งเวลาหรือการแจ้งเตือนเข้ากับ webhook
หน้าตาของ webhook request
ทุกข้อความเป็น POST ที่มี header ดังนี้
| Header | ค่า |
|---|---|
Content-Type | application/json |
User-Agent | AutoPSEO-Webhook/1.0 |
X-AutoPSEO-Event | ประเภทอีเวนต์ เช่น traffic_drop |
X-AutoPSEO-Signature | sha256= ตามด้วยอักขระเลขฐานสิบหกตัวพิมพ์เล็ก 64 ตัว |
ด้านล่างคือการแจ้งเตือนทราฟฟิกลดลงของ property แบบ domain จากรอบ 06:00 UTC วันที่ 12 ตุลาคม 2026 จัดรูปแบบให้อ่านง่าย (ที่ส่งจริงเป็น JSON แบบกะทัดรัด และค่า id กับ site_id เป็นค่าที่สมมติขึ้น)
{
"id": "9b2e61f04c3a4d7e8f15a0b6c2d39e47",
"event_type": "traffic_drop",
"severity": "high",
"site_id": "4f0c1e9a2b7d4c58",
"site_url": "sc-domain:example.com",
"occurred_at": "2026-10-12T06:00:04.183Z",
"title": "Traffic drop: example.com",
"text": "Clicks 1,500 vs 2,000 in the previous window (-25.0%).",
"url": "https://app.autopseo.com/property/sc-domain%3Aexample.com",
"payload": {
"fields": [
{ "label": "Metric", "value": "clicks" },
{ "label": "Current", "value": "1,500" },
{ "label": "Baseline", "value": "2,000" },
{ "label": "Window", "value": "7 days (2026-10-05 → 2026-10-11 vs 2026-09-28 → 2026-10-04)" },
{ "label": "Change", "value": "-25.0%" }
],
"table": null,
"detector": "traffic_drop",
"window": 7,
"range": { "start": "2026-10-05", "end": "2026-10-11", "compStart": "2026-09-28", "compEnd": "2026-10-04" },
"result": {
"fired": true,
"metric": "clicks",
"value": 1500,
"baseline": 2000,
"change": -0.25,
"severity": "high",
"summary": "Clicks 1,500 vs 2,000 in the previous window (-25.0%)."
}
},
"source": "autopseo"
}
ฟิลด์ระดับบนสุดเหมือนกันในทุกอีเวนต์
| ฟิลด์ | ค่าที่เก็บ |
|---|---|
id | สตริงเลขฐานสิบหกสุ่มยาว 32 ตัวอักษร ใหม่ทุก request |
event_type | สิ่งที่เกิดขึ้น (ดูหัวข้อถัดไป) |
severity | critical, high, medium หรือ low สำหรับการแจ้งเตือน และ info สำหรับรายงาน สรุป และการทดสอบ |
site_id | id ของ property ใน AutoPSEO หรือ null สำหรับการทดสอบและ property เดโม |
site_url | property ของ Search Console เช่น sc-domain:example.com หรือ https://www.example.com/ หรือ null สำหรับการทดสอบ |
occurred_at | เวลาที่สร้างข้อความ ในรูปแบบ ISO 8601 เป็น UTC |
title, text | หัวข้อและประโยคสรุปที่ Slack และ Teams แสดง |
url | รายงานใน AutoPSEO หรือ null สำหรับการทดสอบ |
payload.fields | ค่าที่มีป้ายกำกับ ซึ่ง Slack แสดงเป็น fields และ Teams แสดงเป็น facts |
payload.table | columns และ rows สำหรับรายงานและสรุป นอกนั้นเป็น null |
source | เป็น autopseo เสมอ |
อัตราส่วนเป็นเศษส่วน เช่น change ที่เป็น -0.25 หมายถึงลดลง 25% และ ctr ที่เป็น 0.034 หมายถึง 3.4%
ประเภทอีเวนต์
event_type | ส่งเมื่อ | คีย์เพิ่มเติมใน payload |
|---|---|---|
traffic_drop, traffic_spike, position_drop, ctr_drop, new_lost_rankings, anomaly, index_flip, rank_drop, audit_regression | กฎการแจ้งเตือนทำงาน ทั้งตามกำหนดเวลาหรือผ่าน Test rule | detector, window, range (ช่วงวันที่ หรือ null สำหรับ index_flip, rank_drop และ audit_regression), result |
scheduled_report | รายงานที่ตั้งเวลาไว้ถูกส่งออก ทั้งตามกำหนดเวลาหรือผ่าน Send now | reportType (summary, queries, pages หรือ rankings), range (ช่วงวันที่พร้อม label), totals, previous |
report_summary | มีผู้ใช้กด Send to Slack ในหน้ารายงาน | ไม่มี ตัวเลขอยู่ใน fields และ table |
test | มีผู้ใช้คลิก Send test ที่ webhook | sample ซึ่งเป็น true เสมอ |
result ทวนสิ่งที่ detector วัดได้ ได้แก่ fired, metric, value, baseline, change (เป็น null เมื่อไม่มีข้อมูลให้เปรียบเทียบ), severity และ summary และสำหรับ anomaly จะมี z ซึ่งเป็น modified z-score เพิ่มเข้ามา ส่วน totals และ previous เก็บ clicks, impressions, ctr และ position ของสองช่วงเวลาในรายงาน รายละเอียดว่า detector แต่ละตัววัดอะไรอยู่ในหัวข้อการแจ้งเตือน
วิธีตรวจสอบลายเซ็น
ลายเซ็นคือ HMAC-SHA256 ของไบต์ที่ AutoPSEO ส่งมาตามจริงทุกไบต์ โดยใช้ signing secret ของ webhook เป็นกุญแจ และเขียนเป็น sha256= ตามด้วยเลขฐานสิบหกตัวพิมพ์เล็ก วิธีตรวจสอบมีดังนี้
- อ่าน raw request body ก่อนแปลง JSON เพราะการ parse แล้วแปลงกลับเป็นข้อความอีกครั้งอาจทำให้ไบต์เปลี่ยนไป
- คำนวณ HMAC-SHA256 จากไบต์เหล่านั้น โดยใช้ secret เป็นข้อความ คือสตริง 64 ตัวอักษรตามที่แสดงทุกประการ ไม่ต้องถอดรหัสจากเลขฐานสิบหก
- เติม
sha256=นำหน้าผลลัพธ์ แล้วเปรียบเทียบกับ headerX-AutoPSEO-Signatureแบบ constant time - ปฏิเสธ request หากไม่ตรงกัน แต่ถ้าตรงให้ตอบกลับด้วยสถานะ 2xx ทันที แล้วค่อยทำงานที่ใช้เวลานานหลังจากนั้น
ตัวรับสำหรับ Node.js ที่ไม่ต้องพึ่งไลบรารีภายนอก
import { createServer } from 'node:http';
import { createHmac, timingSafeEqual } from 'node:crypto';
const secret = process.env.AUTOPSEO_WEBHOOK_SECRET;
createServer((req, res) => {
const chunks = [];
req.on('data', (chunk) => chunks.push(chunk));
req.on('end', () => {
const raw = Buffer.concat(chunks);
const expected = Buffer.from('sha256=' + createHmac('sha256', secret).update(raw).digest('hex'));
const received = Buffer.from(String(req.headers['x-autopseo-signature'] || ''));
if (received.length !== expected.length || !timingSafeEqual(received, expected)) {
res.writeHead(401).end();
return;
}
res.writeHead(204).end();
const event = JSON.parse(raw.toString('utf8'));
console.log(event.event_type, event.severity, event.site_url);
});
}).listen(8080);
ต้องตรวจความยาวก่อน เพราะ timingSafeEqual ของ Node จะ throw error เมื่อ buffer สองตัวมีความยาวไม่เท่ากัน
กฎการส่งมอบ
- แต่ละข้อความถูกส่งเพียงหนึ่งครั้ง โดยมี timeout 10 วินาที การตอบกลับด้วยสถานะใดก็ตามที่ไม่ใช่ 2xx ถือว่าล้มเหลว และจะถูกเก็บไว้ใน Delivery history พร้อมรหัสสถานะและส่วนต้นของ response body ที่คุณตอบกลับ
- ระบบไม่ตามการ redirect การตอบกลับ 3xx จะถือว่าล้มเหลว พร้อมข้อความแนะนำให้ใช้ URL ปลายทางจริง
- ไม่มีการลองส่งซ้ำตามเวลา การแจ้งเตือนที่ส่งไม่สำเร็จจะไม่ถูกทำเครื่องหมายว่าส่งแล้ว ดังนั้นการตรวจครั้งถัดไปจะประเมินใหม่และส่งอีกครั้งหากยังเข้าเงื่อนไข ซึ่งสำหรับ detector ส่วนใหญ่คือเช้าวันถัดไป และสำหรับ index flip คือชั่วโมงถัดไป ส่วนรายงานที่ตั้งเวลาไว้และส่งไม่สำเร็จจะไม่ถูกส่งซ้ำในรอบเดียวกัน ให้ใช้ Send now หลังแก้ไขปลายทางแล้ว
idถูกสร้างใหม่ทุก request จึงระบุถึงการส่งแต่ละครั้ง ไม่ใช่ตัวอีเวนต์ หากต้องการกรองการแจ้งเตือนซ้ำ ให้ใช้event_type,site_urlและวันที่ของoccurred_atร่วมกัน เพราะกฎหนึ่งข้อจะส่งไม่เกินหนึ่งครั้งต่อ property ต่อวัน UTC เว้นแต่มีผู้ใช้สั่ง Test rule
ลายเซ็นลับ (signing secret)
AutoPSEO แสดง signing secret เพียงครั้งเดียวตอนที่คุณบันทึก webhook และจะไม่แสดงในรายการอีก ให้เก็บไว้ในการตั้งค่าของตัวรับทันที ควบคู่กับปลายทางที่มันปกป้องอยู่
ตัว URL ถูกเก็บแบบเข้ารหัส และในรายการจะแสดงเฉพาะโฮสต์กับอักขระท้ายสุดเท่านั้น การลบ webhook จะลบทุกกฎที่ส่งมายัง webhook นั้นด้วย หากต้องการการ์ดที่อ่านง่ายในช่อง Teams แทนที่จะเป็น JSON ให้ดู Microsoft Teams