สำหรับนักพัฒนา · v1
Partner API
ส่งประกาศขาย/เช่าอสังหาฯ จากระบบของบริษัทท่านเข้า PropertyMost อัตโนมัติ สร้าง แก้ไข เปลี่ยนสถานะ และปิดประกาศได้ด้วยรหัสอ้างอิงของท่านเอง
เริ่มต้น
- สมัครสมาชิก PropertyMost ด้วยอีเมลบริษัท ประกาศทั้งหมดจะอยู่ในบัญชีนี้
- ติดต่อทีมงานทาง LINE @511gsago เพื่อขอเปิดใช้ Partner API และรับ API key
- Base URL:
https://api.propertymost.com/api/partner/v1 - ทุกคำขอและคำตอบเป็น JSON (UTF-8) ผ่าน HTTPS เท่านั้น
การยืนยันตัวตน
ส่ง API key ใน header ทุกคำขอ เก็บ key ไว้ฝั่งเซิร์ฟเวอร์เท่านั้น ห้ามใส่ในแอปมือถือหรือโค้ดหน้าเว็บ
curl https://api.propertymost.com/api/partner/v1/me \
-H "Authorization: Bearer pm_live_xxxxxxxxxxxxxxxx"จำกัดจำนวนครั้งต่อนาทีต่อ key (ค่าเริ่มต้น 60) ดูเหลือได้จาก header X-RateLimit-Remaining ถ้าเกิน จะได้ 429 พร้อม Retry-After
Endpoint
/meข้อมูลบัญชีพาร์ทเนอร์ ค่าที่ตั้งไว้ และจำนวนรูปสูงสุดต่อประกาศ/property-typesประเภททรัพย์ (ใช้ slug ใน propertyType)/provincesรายชื่อจังหวัด/districts?province={id หรือชื่อ}เขต/อำเภอ พร้อม id/projects?q={คำค้น}ค้นโครงการ (อย่างน้อย 2 ตัวอักษร) สูงสุด 20 รายการ/listings/{externalId}สร้างหรืออัปเดตประกาศ/listings?status=&page=&pageSize=&updatedSince=ประกาศทั้งหมดของท่าน (pageSize สูงสุด 100)/listings/{externalId}ดูประกาศ สถานะ ลิงก์บนเว็บ และยอดเข้าชม/listings/{externalId}/statusเปลี่ยนสถานะ active / paused / sold / rented/listings/{externalId}ปิดประกาศ (ส่ง PUT อีกครั้งเพื่อเปิดใหม่)/listings/bulkส่งครั้งละไม่เกิน 500 รายการ ทำงานเบื้องหลัง (upsert หรือ full_sync)/jobs, /jobs/{jobId}?onlyFailed=trueความคืบหน้าและผลรายการต่อรายการของงาน bulk/leads?since=&limit=ผู้สนใจประกาศ (ดูเบอร์ / เริ่มแชท) แบบไม่ระบุตัวตน/webhookดูการตั้งค่า webhook/webhookตั้ง URL และเหตุการณ์ที่ต้องการรับ/webhook/testส่งเหตุการณ์ทดสอบไปที่ URL/webhookลบ webhookสร้าง/อัปเดตประกาศ
externalId คือรหัสประกาศในระบบของท่าน (A-Z a-z 0-9 . _ - ไม่เกิน 100 ตัวอักษร) ส่ง PUT ซ้ำด้วยรหัสเดิม = อัปเดตประกาศเดิม ไม่เกิดประกาศซ้ำ จึงส่งทั้ง stock ซ้ำทุกวันได้อย่างปลอดภัย ข้อมูลที่ส่งจะแทนที่ของเดิมทั้งหมด ช่องที่ไม่ส่งจะถูกล้างเป็นค่าว่าง
curl -X PUT https://api.propertymost.com/api/partner/v1/listings/CONDO-1024 \
-H "Authorization: Bearer pm_live_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"propertyType": "condo",
"listingType": "sale",
"price": 2890000,
"title": "Artisan Ratchada 1 ห้องนอน ชั้น 18",
"projectName": "Artisan Ratchada",
"province": "กรุงเทพมหานคร",
"district": "ห้วยขวาง",
"bedrooms": 1,
"bathrooms": 1,
"sizeSqm": 28.28,
"contactPhone": "0812345678",
"imageUrls": ["https://cdn.example.com/1024/cover.jpg", "https://cdn.example.com/1024/2.jpg"]
}'คำตอบ (200):
{
"created": true,
"listing": {
"externalId": "CONDO-1024",
"id": 1532,
"status": "pending_review",
"url": "https://propertymost.com/properties/1532-artisan-ratchada-1-ห้องนอน-ชั้น-18-ห้วยขวาง",
"price": 2890000,
"images": [{ "url": "https://api.propertymost.com/uploads/....jpg", "sourceUrl": "https://cdn.example.com/1024/cover.jpg", "isCover": true }],
"stats": { "views": 0, "phoneViews": 0 },
...
},
"warnings": [{ "field": "imageUrls[1]", "message": "ข้ามรูปนี้: ดาวน์โหลดไม่สำเร็จ (HTTP 404)" }]
}| ช่อง | รายละเอียด | |
|---|---|---|
| propertyType | จำเป็น | slug จาก GET /property-types เช่น condo, house, townhome, shophouse, land |
| listingType | จำเป็น | sale (ขาย) หรือ rent (เช่า) |
| price | จำเป็น | ตัวเลข บาท (เช่า = บาทต่อเดือน) |
| contactPhone | จำเป็น | เบอร์ที่ผู้สนใจโทรติดต่อ เช่น 0812345678 |
| title | ชื่อประกาศ ไม่เกิน 200 ตัวอักษร | |
| description | รายละเอียด ไม่เกิน 5,000 ตัวอักษร | |
| districtId | id จาก GET /districts (แนะนำ ชัดเจนที่สุด) | |
| district, province | ชื่อเขต/อำเภอ และจังหวัดภาษาไทย ใช้แทน districtId ได้ | |
| projectId / projectName | id จาก GET /projects หรือชื่อโครงการ (ถ้ายังไม่มีในระบบจะสร้างให้) ถ้าไม่ส่งทำเล จะใช้ทำเลของโครงการ | |
| address | ที่อยู่ ไม่เกิน 500 ตัวอักษร | |
| bedrooms, bathrooms | จำนวนเต็ม 0–50 | |
| sizeSqm | พื้นที่ ตร.ม. | |
| contactLineId | LINE ID | |
| imageUrls | array ของ URL รูปแบบ https เรียงตามลำดับ รูปแรกเป็นรูปปก |
รูปภาพ: PropertyMost ดาวน์โหลดและย่อรูปเก็บไว้เอง URL ต้องเป็น https เปิดได้สาธารณะ ไม่ redirect และเป็นไฟล์รูปโดยตรง รูปที่ URL เดิมจะไม่ถูกดาวน์โหลดซ้ำ ถ้ารูปใดดาวน์โหลดไม่ได้ ประกาศยังบันทึกได้ และจะแจ้งใน warnings ดูจำนวนรูปสูงสุดต่อประกาศ (maxImagesPerListing) และขนาดไฟล์รูปต้นฉบับสูงสุด (maxImageSourceMb) ได้จาก GET /me ส่งรูปเกินจำนวน = error 422 ส่วนรูปที่ใหญ่เกินจะถูกข้ามและแจ้งใน warnings
สถานะประกาศ
pending_reviewรอทีมงานตรวจ (ประกาศใหม่ของพาร์ทเนอร์ที่ยังไม่เปิดขึ้นเว็บทันที)activeแสดงบนเว็บ ·pausedพักประกาศ ·soldขายแล้ว ·rentedเช่าแล้วclosedปิดประกาศ ถ้ามีmoderationNoteแปลว่าไม่ผ่านการตรวจ ส่งข้อมูลซ้ำจะไม่เปิดประกาศเอง ให้แก้ไขตามเหตุผลแล้วติดต่อทีมงาน
curl -X PATCH https://api.propertymost.com/api/partner/v1/listings/CONDO-1024/status \
-H "Authorization: Bearer pm_live_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{ "status": "sold" }'ส่งทีละมาก (bulk) และ full sync
ส่งได้ครั้งละไม่เกิน 500 รายการ แต่ละรายการมีช่องเหมือน PUT และเพิ่ม externalId ระบบตอบกลับทันที (202) พร้อม jobId แล้วทำงานเบื้องหลังทีละรายการ มีงานค้างพร้อมกันได้ไม่เกิน 2 งาน
curl -X POST https://api.propertymost.com/api/partner/v1/listings/bulk \
-H "Authorization: Bearer pm_live_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"mode": "upsert",
"listings": [
{ "externalId": "CONDO-1024", "propertyType": "condo", "listingType": "sale", "price": 2890000, "districtId": 1017, "contactPhone": "0812345678" },
{ "externalId": "HOUSE-77", "propertyType": "house", "listingType": "rent", "price": 25000, "district": "บางกะปิ", "province": "กรุงเทพมหานคร", "contactPhone": "0812345678" }
]
}'
# → 202 { "jobId": "job_9f...", "status": "queued", "mode": "upsert", "total": 2 }
curl https://api.propertymost.com/api/partner/v1/jobs/job_9f...?onlyFailed=true -H "Authorization: Bearer pm_live_..."
# → { "status": "completed", "total": 2, "succeeded": 1, "failed": 1,
# "results": [{ "externalId": "HOUSE-77", "ok": false, "error": "ข้อมูลไม่ถูกต้อง", "details": [...] }] }mode: "full_sync" = "นี่คือ stock ทั้งหมดของเรา" ประกาศที่เปิดอยู่แต่ไม่อยู่ในรอบนี้จะถูกปิดให้อัตโนมัติ (และส่ง webhook listing.closed) เพื่อความปลอดภัย ถ้ารอบนั้นส่งมาน้อยกว่าครึ่งของประกาศที่เปิดอยู่ ระบบจะไม่ปิดอะไร และแจ้งเหตุผลใน syncNote ของงาน
Webhook
ระบบส่ง POST เป็น JSON ไปที่ URL ของท่านเมื่อเกิดเหตุการณ์ URL ต้องเป็น https เปิดได้จากอินเทอร์เน็ต และตอบกลับ 2xx ภายใน 10 วินาที
listing.approved/listing.rejectedผลการตรวจประกาศ (มี reason)listing.closedประกาศถูกปิดเพราะไม่อยู่ใน full synclead.createdมีคนกดดูเบอร์หรือเริ่มแชทjob.completedงาน bulk เสร็จหรือล้มเหลว
curl -X PUT https://api.propertymost.com/api/partner/v1/webhook \
-H "Authorization: Bearer pm_live_..." -H "Content-Type: application/json" \
-d '{ "url": "https://crm.example.com/propertymost-hook", "events": ["lead.created", "listing.rejected"] }'
# ครั้งแรกจะได้ "secret": "whsec_..." (แสดงครั้งเดียว) ส่ง "rotateSecret": true เพื่อสร้างใหม่
# สิ่งที่ส่งไป
POST https://crm.example.com/propertymost-hook
X-PropertyMost-Event: lead.created
X-PropertyMost-Event-Id: evt_3c1...
X-PropertyMost-Signature: t=1790000000,v1=5f2a...
{ "id": "evt_3c1...", "event": "lead.created", "createdAt": "2026-10-01T08:00:00.000Z",
"data": { "id": "chat_45", "type": "chat", "externalId": "CONDO-1024", "listingId": 1532, "chatUrl": "https://propertymost.com/messages?c=45" } }ตรวจลายเซ็นทุกครั้ง: คำนวณ HMAC-SHA256 ของ <t>.<body ดิบ> ด้วย secret แล้วเทียบกับ v1 และไม่รับข้อความที่ t เก่ากว่า 5 นาที ใช้ id กันรับซ้ำ
// Node.js
const crypto = require("crypto");
function verify(rawBody, header, secret) {
const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=")));
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}ถ้าปลายทางไม่ตอบ 2xx ระบบลองใหม่อัตโนมัติหลัง 1 นาที, 5 นาที, 30 นาที, 2 ชม. และ 12 ชม. จากนั้นหยุด (ทีมงานส่งซ้ำให้ได้)
Leads (ผู้สนใจ)
รายการคนที่สนใจประกาศของท่าน: phone_view (กดดูเบอร์) และ chat (เริ่มแชท) เรียงจากเก่าไปใหม่ ใช้ nextSince จากคำตอบเป็น since ของรอบถัดไป และใช้ id กันซ้ำ
curl "https://api.propertymost.com/api/partner/v1/leads?since=2026-10-01T00:00:00Z&limit=100" -H "Authorization: Bearer pm_live_..."
# → { "items": [
# { "id": "phone_812", "type": "phone_view", "externalId": "CONDO-1024", "listingId": 1532, "createdAt": "..." },
# { "id": "chat_45", "type": "chat", "externalId": "CONDO-1024", "listingId": 1532, "createdAt": "...", "chatUrl": "https://propertymost.com/messages?c=45" }
# ], "nextSince": "...", "hasMore": false }ข้อมูลส่วนบุคคล: leads ไม่มีชื่อ อีเมล เบอร์โทร หรือข้อความของผู้สนใจ ตอบแชทได้โดยล็อกอินเว็บด้วยบัญชีพาร์ทเนอร์แล้วเปิด chatUrl
Error
ทุก error มีรูปแบบเดียวกัน กรณีข้อมูลไม่ถูกต้อง จะบอกทีละช่องใน details
{
"error": {
"code": "validation_failed",
"message": "ข้อมูลไม่ถูกต้อง",
"details": [
{ "field": "listingType", "message": "ต้องเป็น \"sale\" หรือ \"rent\"" },
{ "field": "district", "message": "ไม่พบ \"ห้วยขวัง\" ในจังหวัด \"กรุงเทพมหานคร\"" }
]
}
}| 400 | invalid_request | รูปแบบคำขอผิด เช่น externalId หรือพารามิเตอร์ไม่ถูกต้อง |
| 401 | unauthorized | ไม่มี API key, key ผิด หรือถูกยกเลิก |
| 403 | forbidden | บัญชีพาร์ทเนอร์ถูกระงับ |
| 404 | not_found | ไม่พบประกาศ externalId นี้ในบัญชีของท่าน |
| 409 | conflict | ประกาศไม่ผ่านการตรวจ เปลี่ยนสถานะไม่ได้ |
| 422 | validation_failed | ข้อมูลไม่ถูกต้อง ดูรายละเอียดทีละช่องใน details |
| 429 | rate_limited | เรียกถี่เกินกำหนด รอตาม header Retry-After (วินาที) |
| 500 | internal_error | ข้อผิดพลาดฝั่ง PropertyMost ลองใหม่ภายหลัง |
ข้อตกลงการใช้งาน
- ส่งเฉพาะทรัพย์ที่ท่านเป็นเจ้าของ หรือได้รับมอบหมายจากเจ้าของให้ประกาศ ข้อมูลและราคาต้องเป็นความจริง
- รูปต้องเป็นรูปทรัพย์จริง และท่านต้องมีสิทธิ์เผยแพร่ ห้ามใช้รูปสต็อกแทนรูปทรัพย์
- เบอร์โทรและ LINE ที่ส่งมาจะแสดงบนประกาศ ท่านต้องได้รับความยินยอมจากเจ้าของข้อมูลแล้ว (PDPA)
- อัปเดตสถานะเมื่อขาย/เช่าแล้ว และปิดประกาศที่ไม่มีอยู่จริง
- แก้ไขประกาศผ่านหน้าเว็บได้ แต่การส่ง PUT ครั้งถัดไปจะเขียนทับข้อมูลที่แก้บนเว็บ ให้แก้ที่ระบบต้นทางเป็นหลัก
- PropertyMost อาจระงับ key หรือบัญชีที่ละเมิด ข้อตกลงการใช้งาน