← บทความทั้งหมด
บทช่วยสอน

โยนเอกสาร Webhook ให้ Devin Desktop แล้วได้ตัวรับข้อความ LINE ใน 20 นาที

Devin Desktop — รีแบรนด์จาก Windsurf ต้นปี 2026 พร้อมโมเดล SWE-1.6 ที่ผลิต output ได้ 950 tokens/วินาที — เป็นเครื่องมือ AI coding ที่นักพัฒนารอบตัวผมพูดถึงมากที่สุดตอนนี้ วิธีใช้ตรงไปตรงมา: โยนเอกสารอ้างอิงให้มัน อธิบายสิ่งที่ต้องการ iterate จนรันได้ ผมอยากลองว่า workflow แบบนี้จะไปได้ไกลแค่ไหนเมื่อเอกสารอ้างอิงเป็น webhook API ไม่ใช่คู่มือเฟรมเวิร์ก

ภารกิจ: เขียน Python server รับข้อความ LINE ผ่าน webhook event แล้ว log แบบ structured — handler แบบที่ทีมเล็กๆ จะ deploy หน้า message queue หรือระบบ ticket ไม่ต้อง LINE Official Account ไม่ต้อง Messaging API credentials ไม่ต้องจัดการ channel access token แค่ข้อความขาเข้ามาในรูป JSON มาตรฐานก็พอ

สิ่งที่จะได้

FastAPI server (ประมาณ 40 บรรทัด):

  1. รับ event message.received จาก webhook รวมของ UnifyPort
  2. ยืนยันทุก delivery ด้วย HMAC-SHA256 กับ signing_secret
  3. Log แต่ละข้อความเป็น structured JSON — provider, sender, text, timestamp
  4. คืน 200 สำหรับทุก event, 401 เมื่อลายเซ็นไม่ถูกต้อง

เวลา: ประมาณ 20 นาที ต้องมี UnifyPort workspace ที่เชื่อมบัญชี LINE แล้ว (สแกน QR จากแอป LINE) และ Python 3.10+

ทำไมไม่ใช้ LINE Messaging API ตรงๆ?

เส้นทางทางการ:

  1. สร้าง LINE Official Account — ต้องมี LINE Business ID ต้องยืนยันตัวตนบริษัทหรือบุคคล
  2. เปิด Messaging API ใน LINE Developers console — ตั้งค่า channel สร้าง channel access token กำหนด webhook URL
  3. Parse webhook payload ของ LINE: event มาในรูป {"events": [{"type": "message", "message": {"type": "text", "text": "..."}, "source": {"userId": "U..."}}]} — ซ้อนกัน เฉพาะ LINE
  4. ยืนยันลายเซ็น ด้วย channel secret ผ่าน x-line-signature — LINE ใช้ HMAC-SHA256 เข้ารหัส Base64 ไม่ใช่ hex
  5. จัดการ reply token: แต่ละ event มี replyToken ที่มีอายุ 30 วินาที — พลาดหน้าต่างเวลา reply ก็ล้มเหลวเงียบๆ

โค้ดรันได้ แต่รันได้เฉพาะ LINE รูปแบบ webhook payload, format ลายเซ็น, กลไก reply token — ไม่มีอะไรนำไปใช้กับ WhatsApp หรือ Telegram ได้ เพิ่มแพลตฟอร์มที่สองก็ต้องทำ integration ใหม่ตั้งแต่ศูนย์

อินเทอร์เฟซไม่เป็นทางการของ UnifyPort เชื่อมต่อบัญชี LINE ส่วนตัว — สแกน QR ไม่ต้อง Official Account — ส่งทุกข้อความขาเข้าเป็น event message.received มาตรฐาน format เดียวกับ WhatsApp, Telegram, TikTok, Zalo และ X handler เดียวรับทั้ง 6 แพลตฟอร์ม

เตรียมตัว: ป้อนเอกสาร API ให้ Devin Desktop

เปิด Devin Desktop สร้าง session ใหม่ ก่อน prompt แรก ให้ context:

  1. วาง payload event message.received จากเอกสาร webhook ของ UnifyPort:
    {
      "event": "message.received",
      "account_id": "acct_7kQnWx",
      "provider": "line",
      "from": "user_a3f82c",
      "text": "เลื่อนไปวันศุกร์ได้ไหมครับ",
      "timestamp": 1751270400,
      "message_id": "line_msg_5e9d21"
    }
  2. วางส่วนยืนยัน HMAC-SHA256 — header x-unifyport-signature คำนวณ hex digest จาก raw request body ด้วย signing_secret

Devin index เนื้อหาที่วางเป็น session context SWE-1.6 Fast ประมวลผลที่ 950 tok/s ย่อยเอกสารภายในไม่กี่วินาที Cursor, Claude Code, Copilot ก็ทำแบบเดียวกัน — วางหรือแนบ เครื่องมือเปลี่ยนได้ เอกสารต่างหากที่สำคัญ

กระบวนการ build

Prompt แรก — โครง handler:

จากเอกสาร webhook ของ UnifyPort ที่ผมเพิ่งวาง เขียน FastAPI server มี route POST /webhook เมื่อ event เป็น “message.received” ให้ log provider, from, text และ timestamp เป็น structured JSON ด้วย logging module ของ Python คืน 200 สำหรับทุก event ใช้ uvicorn รัน

Devin อ่าน context แล้วสร้าง:

from fastapi import FastAPI, Request
import logging, json

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("inbound")

app = FastAPI()

@app.post("/webhook")
async def webhook(request: Request):
    evt = await request.json()
    if evt.get("event") == "message.received":
        logger.info(json.dumps({
            "provider": evt["provider"],
            "from": evt["from"],
            "text": evt["text"],
            "timestamp": evt["timestamp"],
            "message_id": evt["message_id"],
        }))
    return {"status": "ok"}

12 บรรทัด handler ไม่มี import เฉพาะ LINE ไม่มี linebot SDK ไม่มี channel access token โครงสร้าง event แบนพอที่ไม่ต้อง parse อะไรเพิ่ม

Prompt ที่สอง — ยืนยันลายเซ็น:

เพิ่มการยืนยันลายเซ็น HMAC-SHA256 header คือ x-unifyport-signature secret มาจากตัวแปรสภาพแวดล้อม UNIFYPORT_SIGNING_SECRET HMAC คำนวณจาก raw request body bytes ไม่ใช่ JSON ที่ serialize ใหม่ คืน 401 ถ้ายืนยันไม่ผ่าน ใช้ timing-safe comparison

Prompt ที่สาม — รวมและจัดระเบียบ:

รวมการยืนยันลายเซ็นเข้ากับ webhook handler parse body เป็น JSON หลังจากยืนยันผ่านแล้ว เพิ่ม GET /health health check เพิ่ม uvicorn.run port 8000

ไฟล์ server.py ฉบับสมบูรณ์:

from fastapi import FastAPI, Request, HTTPException
import hmac, hashlib, os, json, logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("inbound")

SIGNING_SECRET = os.environ["UNIFYPORT_SIGNING_SECRET"]

app = FastAPI()

@app.get("/health")
async def health():
    return {"status": "ok"}

@app.post("/webhook")
async def webhook(request: Request):
    body = await request.body()
    sig = request.headers.get("x-unifyport-signature", "")
    expected = hmac.new(
        SIGNING_SECRET.encode(), body, hashlib.sha256
    ).hexdigest()
    if not hmac.compare_digest(sig, expected):
        raise HTTPException(status_code=401, detail="invalid signature")

    evt = json.loads(body)
    if evt.get("event") == "message.received":
        logger.info(json.dumps({
            "provider": evt["provider"],
            "from": evt["from"],
            "text": evt["text"],
            "timestamp": evt["timestamp"],
            "message_id": evt["message_id"],
        }))
    return {"status": "ok"}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

ไม่ถึง 40 บรรทัด ยืนยันลายเซ็นแล้ว structured logging พร้อม deploy หลัง reverse proxy ใดก็ได้

รันแล้วดูข้อความ LINE เข้ามา

เชื่อมบัญชี LINE ใน UnifyPort workspace — LINE รองรับ QR code auth เปิดแอป LINE สแกนแล้วเชื่อมได้ภายในไม่กี่วินาที ไม่ต้อง LINE Official Account ไม่ต้อง Business ID ไม่ต้องตั้งค่า Messaging API

ลงทะเบียน webhook endpoint ชี้ไปที่ server ของคุณ กำหนด subscribed_events: ["message.received"] และ signing_secret เริ่ม server:

UNIFYPORT_SIGNING_SECRET=your_secret python server.py

ให้เพื่อนส่งข้อความทดสอบมาที่ LINE ของคุณ event มาถึง:

{
  "event": "message.received",
  "account_id": "acct_3Xk1wL",
  "provider": "line",
  "from": "user_a3f82c",
  "text": "เลื่อนไปวันศุกร์ได้ไหมครับ",
  "timestamp": 1751270400,
  "message_id": "line_msg_5e9d21"
}

Server ยืนยันลายเซ็นแล้ว output structured JSON ลง log ถ้ายืนยันลายเซ็นไม่ผ่านคืน 401 — ตรวจสอบว่า UNIFYPORT_SIGNING_SECRET ตรงกับค่าที่ตั้งบน webhook endpoint

เพิ่ม WhatsApp โดยไม่แก้โค้ดแม้แต่บรรทัดเดียว

เชื่อมบัญชี WhatsApp ใน workspace เดียวกัน subscribe webhook endpoint เดียวกัน ข้อความ WhatsApp มาถึงในรูปแบบเดียวกัน:

{
  "event": "message.received",
  "account_id": "acct_7kQnWx",
  "provider": "whatsapp",
  "from": "user_d4f29a",
  "text": "ยืนยันออเดอร์แล้วครับ จัดส่งวันจันทร์",
  "timestamp": 1751270460,
  "message_id": "wa_msg_8b3e71"
}

Handler เดียวกัน Structured log เดียวกัน field provider เปลี่ยนจาก "line" เป็น "whatsapp" แต่ code path เหมือนกันทุกประการ Handler ของ LINE Messaging API จะต้องสร้าง integration กับ WhatsApp แยกต่างหาก — webhook payload ต่างกัน format ลายเซ็นต่างกัน SDK ต่างกัน handler นี้รับ 6 แพลตฟอร์มเพราะโครงสร้าง event ไม่เปลี่ยน

ในประเทศไทยที่ LINE เป็นแพลตฟอร์มหลัก การเพิ่ม WhatsApp หรือ Telegram เข้ามาในระบบที่รับข้อความ LINE อยู่แล้ว ไม่ได้เพิ่ม SDK ใหม่หรือโมเดลราคาใหม่ — แค่เพิ่มค่า provider ใน payload นั่นคือ workflow ทั้งหมด: ป้อน เอกสาร API ของ UnifyPort ให้ Devin Desktop อธิบาย handler iterate จนรันได้ เครื่องมือเขียนโค้ด webhook มาตรฐานทำให้โค้ดใช้ได้กับทุกช่องทาง เปลี่ยนเป็น Cursor, Claude Code หรือ Copilot ก็ได้ — เอกสารเดิม handler ไม่เกิน 40 บรรทัด