เว็บฮุก (JSON)

ส่งการตอบกลับจาก Google Forms แต่ละรายการเป็น JSON ที่มีลายเซ็นไปยังปลายทางของคุณเอง, Zapier, Make หรือ n8n และตรวจสอบลายเซ็น

กฎเว็บฮุกจะ POST การตอบกลับทุกรายการที่ตรงเงื่อนไขเป็น JSON ไปยัง URL ที่คุณกำหนด ใช้เพื่อป้อนข้อมูลเข้า CRM เครื่องมือสเปรดชีต เซิร์ฟเวอร์ของคุณเอง หรือแพลตฟอร์มอัตโนมัติอย่าง Zapier, Make หรือ n8n

สร้างกฎเว็บฮุก

  1. คลิก + กฎใหม่ แล้วเลือก เว็บฮุก
  2. เมื่อ: คง ทุกคำตอบ ไว้ หรือเลือก เฉพาะเมื่อได้รับอนุมัติ / เมื่อถูกปฏิเสธ แล้วตั้งผู้อนุมัติ เพิ่มเงื่อนไข เฉพาะเมื่อ เพื่อส่งเฉพาะการตอบกลับที่ตรงกัน
  3. ถึง: วาง URL ปลายทางของคุณ (HTTPS เท่านั้น) ไม่มีขั้นตอนข้อความ: กฎจะส่งข้อมูล JSON ที่มีรูปแบบตายตัว คลิก ดูข้อมูลที่ส่ง ใต้ URL เพื่อดูข้อมูลพร้อมคำถามในแบบฟอร์มของคุณและคัดลอกได้
  4. คลิก สร้างกฎ แล้วคัดลอกรหัสลับสำหรับลงนามที่แสดงเพียงครั้งเดียว (ดูด้านล่าง)

ส่งทดสอบ จะส่งข้อมูลตัวอย่างที่มีลายเซ็นไปยังปลายทางและแสดงสถานะ HTTP ที่ตอบกลับ URL ที่บันทึกจะถูกเก็บแบบเข้ารหัสและแสดงแบบปิดบัง คลิก แทนที่ เพื่อวาง URL ใหม่

ข้อมูลที่ส่ง

แต่ละคำขอเป็น POST, Content-Type: application/json พร้อมเนื้อหานี้:

{
  "version": 1,
  "event": "submitted",
  "form": { "id": "1AbC...", "name": "Workshop sign-up" },
  "response": {
    "id": "a3f1...",
    "submittedAt": "2026-01-31T09:30:00.000Z",
    "respondentEmail": "respondent@example.com",
    "answers": [
      { "questionId": "q1", "title": "Your name", "value": "Ada Lovelace" },
      { "questionId": "q3", "title": "Department", "value": "Ops" }
    ]
  },
  "rule": { "id": "rule id", "name": "Zapier: new lead" }
}
  • event เป็นค่าใดค่าหนึ่งใน submitted, approved, rejected และส่งมาในเฮดเดอร์ X-Skyfield-Event ด้วย
  • response.respondentEmail เป็น null เว้นแต่ฟอร์มจะเก็บที่อยู่อีเมล
  • answers[].value เป็นสตริงเสมอ คำตอบแบบช่องทำเครื่องหมายจะต่อกันด้วย ,
  • rule.id และ rule.name ระบุกฎที่ทำงาน โดย name เป็น null เมื่อกฎไม่มีชื่อ
  • ในเหตุการณ์ approved และ rejected จะมีฟิลด์เพิ่มเติม approval: { "decision": "approved", "decidedBy": "Dana" } โดย decidedBy คือชื่อที่ผู้อนุมัติพิมพ์ในหน้ายืนยัน หากไม่มีจะเป็นอีเมลของผู้อนุมัติ หรือ null

version จะคงเป็น 1 ตราบใดที่โครงสร้างด้านบนยังคงเดิม อาจมีการเพิ่มฟิลด์ใหม่ แต่จะไม่ลบหรือเปลี่ยนชื่อฟิลด์โดยไม่เพิ่มเลขเวอร์ชัน

การตรวจสอบลายเซ็น

ทุกคำขอมีเฮดเดอร์ X-Skyfield-Signature: sha256=<hex> ซึ่งเป็น HMAC-SHA256 ของเนื้อหาคำขอดิบโดยใช้รหัสลับสำหรับลงนามของกฎเป็นกุญแจ ตรวจสอบก่อนเชื่อถือคำขอ

รหัสลับ (whsec_...) จะแสดงครั้งเดียวทันทีหลังการบันทึกที่ทำให้กฎได้ URL เว็บฮุกเป็นครั้งแรก คัดลอกไว้ตอนนั้น เพราะจะไม่แสดงอีก การแทนที่ URL ภายหลังจะยังใช้รหัสลับเดิม หากทำหาย ให้เปิดกฎ คลิก รหัสลับสำหรับลงนามใหม่ แล้วบันทึก: รหัสลับใหม่จะแสดงครั้งเดียว และรหัสเดิมจะใช้ไม่ได้ทันที

คำนวณ HMAC จากไบต์ของเนื้อหาตามที่ได้รับมาทุกประการ หากแปลง JSON แล้วแปลงกลับก่อน ช่องว่างจะเปลี่ยนและการเปรียบเทียบจะล้มเหลว

Node.js

import { createHmac, timingSafeEqual } from 'node:crypto'

// rawBody: string or Buffer of the request body, before any JSON parsing
function verify(rawBody, header, secret) {
  const expected = 'sha256=' + createHmac('sha256', secret).update(rawBody).digest('hex')
  const a = Buffer.from(expected)
  const b = Buffer.from(header ?? '')
  return a.length === b.length && timingSafeEqual(a, b)
}

// Express example: use express.raw() so req.body is the untouched bytes
app.post('/hook', express.raw({ type: 'application/json' }), (req, res) => {
  if (!verify(req.body, req.get('X-Skyfield-Signature'), process.env.SKYFIELD_SECRET))
    return res.status(401).end()
  const payload = JSON.parse(req.body)
  res.status(200).end()
})

Python

import hmac, hashlib

def verify(raw_body: bytes, header: str, secret: str) -> bool:
    digest = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest("sha256=" + digest, header or "")

# Flask example
@app.post("/hook")
def hook():
    if not verify(request.get_data(), request.headers.get("X-Skyfield-Signature"), SECRET):
        return "", 401
    payload = request.get_json()
    return "", 200

ตอบกลับด้วยสถานะ 2xx ใดก็ได้ เนื้อหาการตอบกลับจะถูกละเว้น

Zapier, Make, n8n

ทั้งสามแพลตฟอร์มรับเว็บฮุก JSON ทั่วไปได้:

  • Zapier: ทริกเกอร์ Webhooks by Zapier เหตุการณ์ Catch Hook (หรือ Catch Raw Hook หากต้องการตรวจสอบลายเซ็นเอง) วาง URL ที่ Zapier แสดงลงในกฎ
  • Make: เพิ่มโมดูล Webhooks, Custom webhook แล้วคัดลอก URL
  • n8n: เพิ่มโหนด Webhook เมธอด POST แล้วใช้ production URL ของโหนดนั้น

ส่งทดสอบจากกฎ จากนั้นแมปฟิลด์ response.answers ในแพลตฟอร์ม ข้อมูลตัวอย่างใช้คำตอบจำลอง ทุกฟิลด์จึงมีค่าครบ

การส่งและขีดจำกัด

  • ปลายทางต้องเข้าถึงได้จากอินเทอร์เน็ตสาธารณะผ่าน HTTPS ที่อยู่ส่วนตัวและที่อยู่ภายในเครื่องจะถูกปฏิเสธตอนบันทึก
  • ไม่ติดตามการเปลี่ยนเส้นทาง (redirect): ใช้ URL ปลายทางสุดท้าย
  • ปลายทางมีเวลาตอบกลับ 5 วินาที หากหมดเวลาหรือตอบ 5xx จะลองใหม่หนึ่งครั้ง
  • การตอบกลับ 404 หรือ 410 หมายความว่าปลายทางไม่มีอยู่แล้ว: กฎจะถูกหยุดชั่วคราวและคุณจะได้รับอีเมลแจ้งหนึ่งฉบับ วาง URL ใหม่ในกฎเพื่อกลับมาทำงาน
  • หน้าประวัติแสดงการส่งแต่ละครั้งพร้อมสถานะ HTTP ที่ปลายทางของคุณตอบกลับ
  • กฎเว็บฮุกที่หยุดชั่วคราวหรือปิดอยู่จะไม่กีดขวางกฎอื่นในฟอร์ม

ควรรู้

  • กฎเว็บฮุกรองรับส่งเมื่อ ปลายทางจึงรับผลการอนุมัติแทนการส่งฟอร์มทุกครั้งได้ ดูที่ส่งเมื่อ
  • หากต้องการส่งเฉพาะการตอบกลับที่ผ่านการตรวจสอบ ให้ตั้ง ส่งเมื่อ ของกฎเป็น เฉพาะเมื่อได้รับอนุมัติ แล้วเลือกผู้อนุมัติ ดูที่การอนุมัติ ข้อมูลที่ส่งจะมีค่า approval.decision
  • เปลี่ยนช่องทาง… ย้ายกฎเว็บฮุกไปเป็นอีเมลหรือช่องแชต โดยระบุปลายทางใหม่ตรงนั้น หากเปลี่ยนกลับเป็นเว็บฮุก ต้องวาง URL อีกครั้ง
  • กฎเว็บฮุกต้องมีสิทธิ์การใช้งานที่ใช้งานอยู่ ช่วงทดลองใช้ฟรีนับรวมด้วย ดูที่สิ่งที่ต้องมีสิทธิ์การใช้งาน