Developer wiki

เชื่อม PropThunder กับระบบของคุณ

คู่มือแบบลงมือทำสำหรับ API key, REST endpoint, Webhook, การตรวจลายเซ็น, การ retry และการทดสอบ — สรุปสั้นอยู่ที่หน้า /developers

1. สร้าง API key

ไปที่ การเชื่อมต่อ → API และ Webhook เฉพาะเจ้าของ workspace เท่านั้นที่สร้างคีย์ได้ ตั้งชื่อคีย์ให้รู้ว่าใช้ที่ไหน เช่น “ฟอร์มเว็บไซต์” แล้วคัดลอกทันที เพราะระบบจะแสดงคีย์เต็มเพียงครั้งเดียวและเก็บเฉพาะ hash

ห้ามใส่ API key ใน JavaScript ฝั่งเบราว์เซอร์หรือ repository สาธารณะ ให้เรียก API จากเซิร์ฟเวอร์ของคุณเท่านั้น

รูปแบบคีย์: pt_live_… · header: Authorization: Bearer …

2. การยืนยันตัวตนและข้อจำกัด

Base URLhttps://propthunder.com/api/v1
  • จำกัด 120 requests/นาทีต่อคีย์ เกินแล้วได้ 429 พร้อม Retry-After
  • รับ-ส่ง JSON (UTF-8) วันที่เป็น ISO 8601 พร้อม offset ราคาเป็นจำนวนเต็มบาท
  • รายการใช้ limit (สูงสุด 100) และ offset ดูต่อด้วย next_offset เมื่อ has_more = true
  • เจ้าของเท่านั้นที่สร้างคีย์/เว็บฮุกได้ สมาชิกทีมใช้คีย์ที่มีอยู่เรียก API ได้
curl "https://propthunder.com/api/v1/contacts?limit=10&offset=0" \
  -H "Authorization: Bearer pt_live_..." \
  -H "Accept: application/json"

3. REST API

MethodEndpointใช้ทำอะไร
GET/api/v1/contactsดูลูกค้า ค้นด้วย q กรอง stage_id
POST/api/v1/contactsสร้างลูกค้าเข้าขั้นแรกของ pipeline
GET/api/v1/contacts/{id}ดูลูกค้าหนึ่งคน
PATCH/api/v1/contacts/{id}แก้ข้อมูล ย้าย stage_id มอบหมาย assigned_to
GET/api/v1/stagesขั้น pipeline และ id
GET/api/v1/listingsดูประกาศ กรอง status
POST/api/v1/tasksสร้างงาน ผูกกับลูกค้าได้

ส่งลูกค้าจากเว็บไซต์ของคุณ

POST /contacts คือการเชื่อมต่อแรกที่ใช้บ่อย ชื่อบังคับ ควรมีเบอร์หรืออีเมล ลูกค้าจะเข้าขั้นแรกของ pipeline และเกิด event contact.created

curl -X POST "https://propthunder.com/api/v1/contacts" \
  -H "Authorization: Bearer pt_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "สมชาย ใจดี",
    "phone": "0812345678",
    "email": "somchai@example.com",
    "source": "website",
    "interest": "buy",
    "budget_max": 5000000,
    "tags": ["website", "condo"],
    "notes": "สนใจคอนโดใกล้ BTS"
  }'

ย้ายลูกค้าไปขั้นอื่น:

curl -X PATCH "https://propthunder.com/api/v1/contacts/CONTACT_ID" \
  -H "Authorization: Bearer pt_live_..." \
  -H "Content-Type: application/json" \
  -d '{"stage_id":"STAGE_ID","deal_value":4290000}'

4. สร้าง Webhook endpoint

  1. เตรียม HTTPS URL บนเซิร์ฟเวอร์ของคุณที่รับ POST และตอบ 2xx อย่างเร็ว (ภายใน 10 วินาที)
  2. ใน การเชื่อมต่อ → API และ Webhook เพิ่ม URL และเลือกเหตุการณ์ที่ต้องการ
  3. คัดลอก signing secret ที่แสดงครั้งเดียว เก็บเป็น environment variable ฝั่งเซิร์ฟเวอร์
  4. กด “ส่งทดสอบ” เพื่อตรวจการเชื่อมต่อ ผลจะอยู่ในตาราง delivery log
  5. เปิด endpoint ไว้ ถ้าต้อง deploy ให้ปิดชั่วคราวได้
รับเฉพาะ HTTPS และ IP สาธารณะ ไม่ตาม redirect timeout 10 วินาที ถ้าตอบไม่ใช่ 2xx ระบบจะลองใหม่

5. เหตุการณ์และ payload

header ที่ส่งมาทุกครั้ง:

POST https://your-app.example/webhooks/propthunder
Content-Type: application/json
PropThunder-Event: contact.created
PropThunder-Timestamp: 1761411600
PropThunder-Signature: v1=<hex hmac>

{
  "event": "contact.created",
  "created_at": "2026-10-25T09:00:00.000Z",
  "data": {
    "contactId": "3f6c...",
    "name": "สมชาย ใจดี",
    "phone": "0812345678",
    "email": "somchai@example.com",
    "source": "website"
  }
}
เหตุการณ์เกิดเมื่อdata
contact.createdสร้างลูกค้าใหม่จากฟอร์ม เว็บไซต์ LINE หรือ APIcontactId, name, phone, email, source
contact.updatedข้อมูลลูกค้าถูกแก้ไขcontactId, name, fields (ชื่อฟิลด์ที่เปลี่ยน)
contact.stage_changedลูกค้าถูกย้ายขั้นใน pipelinecontactId, name, from, to, stageId, kind, viaWorkflow, viaAi
inquiry.createdมีลูกค้าส่งข้อความสอบถามจากประกาศหรือหน้าเว็บcontactId, name, phone, email, source, message, propertyId, title
listing.createdประกาศใหม่ถูกสร้างid, slug, title, status, price
listing.updatedประกาศถูกแก้ไขหรือเปลี่ยนสถานะid, slug, title, status, price
task.completedงานถูกทำเครื่องหมายว่าเสร็จtaskId, title, contactId

ปุ่มส่งทดสอบจะส่ง event ชื่อ ping (ไม่อยู่ในรายการที่เลือกได้) เข้ามาที่ endpoint ด้วย

6. ตรวจลายเซ็น

คำนวณ HMAC-SHA256 ของ `${timestamp}.${rawBody}` ด้วย secret ของ endpoint แล้วเทียบค่าแบบ timing-safe พร้อมปฏิเสธ timestamp ที่เก่ากว่า 5 นาที สำคัญ: ต้องใช้ raw body ก่อน parse JSON

import crypto from "node:crypto";

export function verifyPropThunderWebhook(req, rawBody, secret) {
  const timestamp = req.headers["propthunder-timestamp"];
  const signature = String(req.headers["propthunder-signature"] ?? "").replace(/^v1=/, "");
  if (!timestamp || Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;

  const expected = crypto
    .createHmac("sha256", secret)
    .update(timestamp + "." + rawBody)
    .digest("hex");

  return signature.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}

ตัวอย่าง Express: ใช้ express.raw({ type: 'application/json' }) แล้วส่ง req.body.toString() เป็น rawBody

7. Retry, log และการทดสอบ

  • ถ้าส่งไม่สำเร็จ ระบบลองสูงสุด 6 ครั้ง โดยเว้นช่วงเพิ่มขึ้น (ประมาณ 2, 4, 8, 16 และ 32 นาที)
  • หน้า API และ Webhook แสดง delivery ล่าสุดพร้อมสถานะและ error
  • ตอบ 2xx ทันทีแล้วประมวลผลแบบ async อย่าทำงานช้าก่อนตอบ
  • กดส่งทดสอบหลังเปลี่ยน endpoint ผลทดสอบจะอยู่ใน log เดียวกัน
  • เขียน handler ให้ idempotent เพราะหลัง retry อาจได้รับ event เดิมซ้ำ

8. แก้ปัญหา

401 Unauthorized

ลืมส่ง Bearer, คีย์ถูกเพิกถอน หรือรูปแบบ header ผิด

404 Not found

ข้อมูลไม่อยู่ใน workspace ของคีย์นี้

422 Invalid input

ตรวจฟิลด์บังคับ, stage_id/assignee_id และรูปแบบวันที่

429 Rate limited

รอตาม Retry-After แล้วค่อยเรียกใหม่

Webhook ไม่มา

ตรวจว่า endpoint เปิดอยู่ เป็น HTTPS สาธารณะ เลือก event แล้ว และดู delivery log

ลายเซ็นไม่ตรง

ใช้ raw body และ secret ของ endpoint นั้น exactly; อย่า sign หลัง parse object

พร้อมเชื่อมต่อแล้วใช่ไหม?

สร้างคีย์หรือ WebhookAPI reference