เอกสาร Public API

คู่มือเชื่อมต่อระบบของคุณเข้ากับประกาศบน Homes ผ่าน API key ของคุณเอง · เวอร์ชัน v1

กลับไปหน้า API ของฉัน

1. เริ่มต้นใช้งาน

Public API ใช้ API key ของคุณเองในการยืนยันตัวตน ก่อนเรียกใช้ต้องผ่าน 3 ขั้นตอนนี้

  1. 1
    ส่งคำขอใช้งานกรอกข้อมูลแอปพลิเคชันในหน้า API ของฉัน แล้วส่งให้เจ้าหน้าที่ตรวจสอบ
  2. 2
    รอการอนุมัติเจ้าหน้าที่จะตรวจสอบและกำหนดสิทธิ์ (scope) ที่คุณได้รับ
  3. 3
    สร้างคีย์แล้วเริ่มเรียกเมื่ออนุมัติแล้วให้สร้างคีย์ในหน้า API ของฉัน คีย์เต็มจะแสดงครั้งเดียวเท่านั้น
กลับไปหน้า API ของฉัน

2. Base URL

Base URL
https://api.homes.in.th/api/public/v1

เวอร์ชันจะเปลี่ยนก็ต่อเมื่อมีการแก้ contract แบบที่ทำให้ระบบเดิมพัง โดยจะแจ้งล่วงหน้า

3. การยืนยันตัวตน

ส่งคีย์ของคุณในส่วนหัว Authorization แบบ Bearer ทุกคำขอ

HTTP header
Authorization: Bearer estk_live_a1b2c3d4e5f6_Xk9mQ2vR7pL4nT8sW1yZ6cB3dF5gH0jK

ทางเลือกสำรอง

หากระบบของคุณใช้ส่วนหัว Authorization ไปแล้ว ส่งคีย์ผ่าน X-Api-Key แทนได้

HTTP header (สำรอง)
X-Api-Key: estk_live_a1b2c3d4e5f6_Xk9mQ2vR7pL4nT8sW1yZ6cB3dF5gH0jK

รูปแบบของคีย์

ส่วนความหมาย
estkคำนำหน้าประจำระบบ ช่วยให้เครื่องมือสแกนความลับตรวจจับได้
liveสภาพแวดล้อมของคีย์
a1b2c3d4e5f6รหัสประจำคีย์ ใช้อ้างอิงเวลาแจ้งปัญหาได้
Xk9m...H0jKส่วนลับ แสดงครั้งเดียวตอนสร้างเท่านั้น
ห้ามใช้คีย์จากฝั่งเบราว์เซอร์

คีย์มีสิทธิ์เขียนประกาศในบัญชีของคุณ ให้เรียก API จากเซิร์ฟเวอร์ของคุณเท่านั้น และเก็บคีย์ใน environment variable ไม่ใส่ในโค้ดหรือ repository

สิทธิ์ (scope)

Scopeใช้ได้กับ
LISTINGS_READGET /properties · /properties/analytics · /favorites
LISTINGS_WRITEPOSTPATCHDELETE /properties · POST /images

4. รูปแบบ Response

ทุก response เป็น JSON ที่มีคีย์ data และ error เสมอ มีเพียงตัวใดตัวหนึ่งที่ไม่เป็น null

สำเร็จ
{
  "data": { "items": {}, "meta": {} },
  "error": null
}
ผิดพลาด
{
  "data": null,
  "error": {
    "code": "E93B08",
    "message": "This API key does not have the required scope"
  }
}
ฟิลด์ชนิดคำอธิบาย
dataobject | nullผลลัพธ์เมื่อสำเร็จ รายการแบบหน้าจะมี items และ meta
data.meta.paginateobjectpage, pageSize, total, totalPages
errorobject | nullมีค่าเมื่อคำขอล้มเหลว
error.codestringรหัสคงที่สำหรับเขียนเงื่อนไขในโค้ด ดูหัวข้อ 9
error.messagestringข้อความอธิบายสำหรับคนอ่าน อาจเปลี่ยนได้โดยไม่แจ้ง

ให้เขียนเงื่อนไขจาก error.code ไม่ใช่จาก message เพราะข้อความอาจถูกปรับคำได้ตลอด ส่วนรหัสจะคงที่

5. ขีดจำกัดการเรียก

60 ครั้งต่อนาที
10,000 ครั้งต่อวัน

นับรวมทุกคีย์ในบัญชีเดียวกัน โควต้ารายวันรีเซ็ตเวลา 07:00 น. ตามเวลาไทย (00:00 UTC) ทุก response จะมีส่วนหัวบอกโควต้าที่เหลือ

ส่วนหัวตัวอย่างค่าความหมาย
X-RateLimit-Limit60จำนวนครั้งสูงสุดต่อนาที
X-RateLimit-Remaining57จำนวนครั้งที่เหลือในนาทีนี้
X-RateLimit-Reset<unix-seconds>เวลาที่โควต้าต่อนาทีจะรีเซ็ต
X-RateLimit-Daily-Limit10000จำนวนครั้งสูงสุดต่อวัน
X-RateLimit-Daily-Remaining9843จำนวนครั้งที่เหลือในวันนี้

เมื่อเกินขีดจำกัดจะได้ 429 Too Many Requests พร้อมส่วนหัว Retry-After (วินาที) ให้รอตามค่านั้นก่อนเรียกซ้ำ

6. Endpoints

ทุก path ต่อท้าย Base URL กดที่แต่ละรายการเพื่อดูพารามิเตอร์และตัวอย่าง

GET/api/public/v1/propertiesดึงประกาศของตัวเอง

คืนรายการประกาศทั้งหมดในบัญชีของคีย์ แบ่งหน้า เรียงลำดับ และค้นหาได้ ต้องมี scope LISTINGS_READ

พารามิเตอร์ (query)

ชื่อชนิดจำเป็นคำอธิบาย
pagenumber—หน้าที่ต้องการ ค่าเริ่มต้น 1
limitnumber—จำนวนต่อหน้า ค่าเริ่มต้น 10 สูงสุด 100
orderBystring—ฟิลด์ที่ใช้เรียง ค่าเริ่มต้น createdAt
sortBystring—asc | desc ค่าเริ่มต้น desc
searchTermstring—ค้นหาจากหัวข้อและรหัสประกาศ
propertyTypeenum—RESIDENTIAL | COMMERCIAL | LAND
listingTypeenum—FOR_SALE | FOR_RENT | FOR_LEASE | FOR_NPA
ตัวอย่างคำขอ
GET /api/public/v1/properties?page=1&limit=10&orderBy=createdAt&sortBy=desc&listingType=FOR_SALE
Authorization: Bearer estk_live_…
ตัวอย่าง response · 200
{
  "data": {
    "items": [
      {
        "id": "75099be6-f7eb-4da6-b093-d1243f5c5ecf",
        "shownId": "7814418701",
        "title": "Noble Revolve Ratchada 1bedroom",
        "propertyType": "RESIDENTIAL",
        "listingType": "FOR_SALE",
        "status": "PUBLISHED",
        "price": "2890000",
        "createdAt": "2026-10-19T08:12:44.000Z"
      }
    ],
    "meta": {
      "paginate": { "page": 1, "pageSize": 10, "total": 12, "totalPages": 2 },
      "countInfo": { "published": 9, "draft": 1, "pending": 1, "expired": 1 }
    }
  },
  "error": null
}
GET/api/public/v1/properties/analyticsสถิติประกาศของตัวเอง

สถิติบนเว็บแบบรวมยอดต่อประกาศในบัญชีของคีย์ ได้แก่ การแสดงผล การเข้าชม การคลิก การเริ่มแชต และการกดดูเบอร์โทร / LINE / อีเมล ต้องมี scope LISTINGS_READ

พารามิเตอร์

ไม่มีพารามิเตอร์ — คืนยอดรวมสะสมของทุกประกาศในบัญชี (ไม่แบ่งหน้า ไม่กรองช่วงวันที่)

ตัวอย่างคำขอ
GET /api/public/v1/properties/analytics
Authorization: Bearer estk_live_…
ตัวอย่าง response · 200
{
  "data": {
    "items": [
      {
        "propertyId": "75099be6-f7eb-4da6-b093-d1243f5c5ecf",
        "impression": 18420,
        "view": 1246,
        "click": 388,
        "chatInitiation": 18,
        "phoneView": 41,
        "lineView": 27,
        "emailView": 6,
        "imageView": 92
      }
    ]
  },
  "error": null
}
GET/api/public/v1/favoritesผู้ที่ถูกใจประกาศของตัวเอง

รายชื่อบัญชีที่กดถูกใจประกาศในบัญชีของคีย์ เรียงจากล่าสุด ต้องมี scope LISTINGS_READ

พารามิเตอร์ (query)

ชื่อชนิดจำเป็นคำอธิบาย
pagenumber—หน้าที่ต้องการ ค่าเริ่มต้น 1
limitnumber—จำนวนต่อหน้า ค่าเริ่มต้น 10 สูงสุด 100
ตัวอย่างคำขอ
GET /api/public/v1/favorites?page=1&limit=10
Authorization: Bearer estk_live_…
ตัวอย่าง response · 200
{
  "data": {
    "items": [
      {
        "id": "c3e4f5a6-7d8e-4f9a-0b1c-2d3e4f5a6b7c",
        "favoritedAt": "2026-10-20T13:05:12.000Z",
        "account": { "id": "a1c2e3f4-5b6d-4e7f-8a9b-0c1d2e3f4a5b", "displayName": "ผู้ใช้ Homes A", "firstName": null, "lastName": null, "countryCode": "+66", "profileImg": null },
        "property": { "id": "75099be6-f7eb-4da6-b093-d1243f5c5ecf", "title": "Noble Revolve Ratchada 1bedroom" }
      }
    ],
    "meta": { "paginate": { "page": 1, "pageSize": 10, "total": 37, "totalPages": 4 } }
  },
  "error": null
}
POST/api/public/v1/propertiesสร้างประกาศ

สร้างประกาศและเผยแพร่ทันทีเมื่อโควต้าเผยแพร่ของแพ็กเกจยังเหลือ หากโควต้าเต็มระบบจะเก็บเป็นฉบับร่างและคืนสถานะ DRAFT ต้องมี scope LISTINGS_WRITE และต้องส่งส่วนหัว Idempotency-Key ทุกครั้ง (ดูหัวข้อ 7)

ส่วนหัว

ชื่อจำเป็นคำอธิบาย
Idempotency-Keyจำเป็นสตริงไม่ซ้ำต่อคำขอ เช่น UUID v4 ความยาว 16–128 ตัวอักษร
Content-Typeจำเป็นapplication/json

Body

ฟิลด์ชนิดจำเป็นคำอธิบาย
propertyobjectจำเป็นข้อมูลหลักของประกาศ
property.titlestringจำเป็นหัวข้อประกาศ
property.descriptionstringจำเป็นรายละเอียด
property.propertyTypeenumจำเป็นRESIDENTIAL | COMMERCIAL | LAND
property.listingTypeenumจำเป็นFOR_SALE | FOR_RENT | FOR_LEASE
property.announcerStatusenumจำเป็นOWNER | AGENT
property.pricestring—ราคาเป็นสตริงตัวเลข หน่วยบาท
addressobjectจำเป็นที่อยู่และตำแหน่ง
address.streetAddressstringจำเป็นเลขที่ ซอย ถนน
address.latitude / longitudenumberจำเป็นพิกัดหมุด
address.subDistrictIdnumberจำเป็นรหัสแขวง/ตำบล
address.postalCodeIdnumberจำเป็นรหัสไปรษณีย์ (id)
propertyImageobject—{ "images": [{ "imageUrl", "fileName", "order" }] } จากผลของ POST /images
residential | commercial | landobject—รายละเอียดตามประเภททรัพย์ ส่งเพียงก้อนเดียวที่ตรงกับ propertyType
ตัวอย่างคำขอ
POST /api/public/v1/properties
Authorization: Bearer estk_live_…
Idempotency-Key: 7f3c1b2e-9a4d-4e8f-b6c0-2d5a8e1f9c7b
Content-Type: application/json

{
  "property": {
    "title": "คอนโด 1 ห้องนอน สุขุมวิท 21 ใกล้ MRT สุขุมวิท",
    "description": "ห้องมุม ชั้น 12 วิวเมือง ตกแต่งครบ พร้อมเข้าอยู่",
    "propertyType": "RESIDENTIAL",
    "listingType": "FOR_SALE",
    "announcerStatus": "AGENT",
    "price": "4500000",
    "propertyCondition": "SECOND_HAND",
    "ownership": "FREEHOLD"
  },
  "address": {
    "streetAddress": "ซอยสุขุมวิท 21 (อโศก) ถนนสุขุมวิท",
    "latitude": 13.7372,
    "longitude": 100.5611,
    "subDistrictId": 100402,
    "postalCodeId": 10110
  },
  "residential": {
    "residentialType": "CONDO",
    "usableArea": 35,
    "floor": 12,
    "bedroom": 1,
    "bathroom": 1,
    "parking": 1
  },
  "propertyImage": {
    "images": [
      { "imageUrl": "https://cdn.homes.in.th/u/8f2c…/living.jpg", "fileName": "living.jpg", "order": 1 }
    ]
  }
}
ตัวอย่าง response · 201
{
  "data": {
    "id": "4f2b1c7e-9d3a-4e6b-8c21-5a7d9e0f1b23",
    "shownId": "7814418712",
    "status": "PUBLISHED",
    "createdAt": "2026-10-21T04:31:09.000Z"
  },
  "error": null
}
PATCH/api/public/v1/properties/{id}แก้ไขประกาศ

แก้ไขเฉพาะฟิลด์ที่ส่งมา ฟิลด์ที่ไม่ส่งจะคงค่าเดิม ประกาศต้องเป็นของบัญชีคีย์เท่านั้น มิฉะนั้นจะได้ 403 E30B15 ต้องมี scope LISTINGS_WRITE

พารามิเตอร์ (path)

ชื่อชนิดจำเป็นคำอธิบาย
idstring (UUID)จำเป็นรหัสประกาศ (id จาก GET /properties — ไม่ใช่ shownId)

Body (บางส่วน)

ฟิลด์ชนิดคำอธิบาย
property · address · residential…objectโครงสร้างเดียวกับตอนสร้าง ส่งเฉพาะที่ต้องการแก้
propertyImage.createImagesarrayรูปใหม่ที่จะเพิ่ม [{ imageUrl, fileName, order }]
propertyImage.updateImagesarrayแก้ลำดับรูปเดิม [{ id, order }]
propertyImage.removeIdsarrayรหัสรูปที่จะลบ
ตัวอย่างคำขอ
PATCH /api/public/v1/properties/4f2b1c7e-9d3a-4e6b-8c21-5a7d9e0f1b23
Authorization: Bearer estk_live_…
Content-Type: application/json

{
  "property": { "price": "4390000" },
  "propertyImage": {
    "removeIds": ["img_01JAD7R1…"],
    "updateImages": [{ "id": "img_01JAD7R2…", "order": 1 }]
  }
}
ตัวอย่าง response · 200
{
  "data": { "id": "4f2b1c7e-9d3a-4e6b-8c21-5a7d9e0f1b23", "shownId": "7814418712", "status": "PUBLISHED", "updatedAt": "2026-10-21T05:02:51.000Z" },
  "error": null
}
DELETE/api/public/v1/properties/{id}ลบประกาศ

ลบประกาศออกจากบัญชี การลบย้อนกลับไม่ได้ สำเร็จจะได้ 204 No Content โดยไม่มี body ต้องมี scope LISTINGS_WRITE

พารามิเตอร์ (path)

ชื่อชนิดจำเป็นคำอธิบาย
idstringจำเป็นรหัสประกาศ
ตัวอย่างคำขอ
DELETE /api/public/v1/properties/4f2b1c7e-9d3a-4e6b-8c21-5a7d9e0f1b23
Authorization: Bearer estk_live_…
ตัวอย่าง response · 204
(ไม่มีเนื้อหาใน response)
POST/api/public/v1/imagesอัปโหลดรูปภาพ

อัปโหลดรูปก่อน แล้วนำ imageUrl ที่ได้ไปใส่ใน propertyImage ตอนสร้างหรือแก้ไขประกาศ ต้องมี scope LISTINGS_WRITE

Body (multipart/form-data)

ฟิลด์ชนิดจำเป็นคำอธิบาย
filesfile[]จำเป็นสูงสุด 20 ไฟล์ต่อครั้ง ชนิด JPEG, PNG, WebP ไฟล์ละไม่เกิน 10 MB
ตัวอย่างคำขอ
POST /api/public/v1/images
Authorization: Bearer estk_live_…
Content-Type: multipart/form-data; boundary=----homes

------homes
Content-Disposition: form-data; name="files"; filename="living.jpg"
Content-Type: image/jpeg

(binary)
------homes--
ตัวอย่าง response · 201
{
  "data": [
    { "imageUrl": "https://cdn.homes.in.th/u/8f2c…/living.jpg", "fileName": "living.jpg" },
    { "imageUrl": "https://cdn.homes.in.th/u/8f2c…/bedroom.jpg", "fileName": "bedroom.jpg" }
  ],
  "error": null
}

7. การเรียกซ้ำของ POST

การสร้างประกาศต้องส่งส่วนหัว Idempotency-Key เพื่อป้องกันประกาศซ้ำเมื่อระบบของคุณ retry ระบบจะจำคีย์พร้อม body ไว้ 24 ชั่วโมง

สถานการณ์ผลลัพธ์
เรียกครั้งแรกด้วยคีย์ใหม่สร้างประกาศตามปกติ คืน 201
เรียกซ้ำด้วยคีย์เดิมและ body เดิมคืนผลลัพธ์เดิม (ประกาศเดิม) ไม่สร้างซ้ำ
เรียกพร้อมกันด้วยคีย์เดิมขณะคำขอแรกยังไม่เสร็จ409 E93B24 ให้รอแล้วเรียกใหม่
คีย์เดิมแต่ body ต่างกัน409 E93B23 ต้องใช้คีย์ใหม่
ไม่ส่งส่วนหัว400 E93B22
เรียกซ้ำหลังคำขอแรกล้มเหลวคืน error เดิมซ้ำ (ไม่ประมวลผลใหม่) หากต้องการลองใหม่ให้ใช้คีย์ใหม่
อายุของคีย์เก็บไว้ 24 ชั่วโมง หลังจากนั้นถือเป็นคำขอใหม่

8. ทดลองยิง API

วางคีย์ของคุณแล้วกดส่งได้จากหน้านี้เลย คำขอถูกส่งจากเบราว์เซอร์ไปยัง https://api.homes.in.th/api/public/v1 โดยตรง (ในเครื่องพัฒนาผ่าน proxy /api) ระบบไม่เก็บคีย์ของคุณ และหมดเวลาใน 15 วินาที

ยิงกับข้อมูลจริง

คำขอที่ส่งจากหน้านี้มีผลกับประกาศจริงในบัญชีของคุณ การสร้าง แก้ไข หรือลบจะเกิดขึ้นทันที

ระบบไม่ได้เก็บคีย์ไว้ ใช้ส่งต่อครั้งนี้ครั้งเดียวแล้วหายไปเมื่อปิดหน้า

9. รหัสข้อผิดพลาด

รหัสHTTPความหมาย
E93B01401ไม่พบส่วนหัว Authorization หรือ X-Api-Key
E93B02401รูปแบบคีย์ไม่ถูกต้อง
E93B03401ไม่พบคีย์นี้ในระบบ
E93B07401คีย์หมดอายุหรือถูกเพิกถอนแล้ว
E93B04403คำขอใช้งาน API ยังไม่ได้รับอนุมัติ
E93B05403คำขอใช้งาน API ถูกระงับ
E93B08403คีย์ไม่มี scope ที่จำเป็น
E93B09429เกินขีดจำกัดต่อนาที ดู Retry-After
E93B10429เกินขีดจำกัดต่อวัน รีเซ็ต 07:00 น.
E93B22400ไม่ส่งส่วนหัว Idempotency-Key
E93B23409Idempotency-Key ซ้ำแต่ body ต่างกัน
E93B24409คำขอด้วย Idempotency-Key เดิมกำลังประมวลผลอยู่
VALIDATION_FAILED400ข้อมูลใน body ไม่ผ่านการตรวจสอบ ดูรายละเอียดใน error.details
E30B03404ไม่พบประกาศ
E30B08400ประเภททรัพย์กับก้อนข้อมูล (residential/commercial/land) ไม่ตรงกัน
E30B09400ที่อยู่ไม่ครบหรือรหัสพื้นที่ไม่ถูกต้อง
E30B17400รูปภาพไม่ถูกต้องหรืออ้างอิง imageUrl ที่ไม่ได้อัปโหลดผ่าน /images
E30B15403ประกาศนี้ไม่ใช่ของบัญชีคีย์
E40B03403โควต้าเผยแพร่ของแพ็กเกจเต็ม
E40B04403โควต้าจำนวนประกาศของแพ็กเกจเต็ม

10. ตัวอย่างโค้ด

ตัวอย่างอ่านคีย์จาก environment variable ชื่อ HOMES_API_KEY แล้วดึงรายการประกาศและสร้างประกาศใหม่พร้อม Idempotency-Key

cURL · ดึงรายการประกาศ
curl -s "https://api.homes.in.th/api/public/v1/properties?page=1&limit=10&listingType=FOR_SALE" \
  -H "Authorization: Bearer $HOMES_API_KEY"
cURL · สร้างประกาศ
curl -s -X POST "https://api.homes.in.th/api/public/v1/properties" \
  -H "Authorization: Bearer $HOMES_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "property": {
      "title": "คอนโด 1 ห้องนอน สุขุมวิท 21 ใกล้ MRT สุขุมวิท",
      "description": "ห้องมุม ชั้น 12 วิวเมือง ตกแต่งครบ พร้อมเข้าอยู่",
      "propertyType": "RESIDENTIAL",
      "listingType": "FOR_SALE",
      "announcerStatus": "AGENT",
      "price": "4500000"
    },
    "address": {
      "streetAddress": "ซอยสุขุมวิท 21 (อโศก) ถนนสุขุมวิท",
      "latitude": 13.7372, "longitude": 100.5611,
      "subDistrictId": 100402, "postalCodeId": 10110
    },
    "residential": { "residentialType": "CONDO", "usableArea": 35, "floor": 12, "bedroom": 1, "bathroom": 1 }
  }'