เอกสารสำหรับนักพัฒนา: API, Webhooks และ SCIM

เชื่อม HomeHQ กับระบบ HR / ERP / Payroll เดิมขององค์กร — ดึงรายชื่อพนักงาน การลงเวลา การลา และสรุปเงินเดือนผ่าน REST API รับแจ้งเหตุการณ์ทันทีด้วย Webhooks และให้ Microsoft Entra ID หรือ Okta เพิ่ม/ระงับพนักงานอัตโนมัติด้วย SCIM 2.0

ภาพรวม

ส่วนแพ็กเกจที่อยู่
REST API (อ่านอย่างเดียว)Business ขึ้นไปhttps://homehqth.com/api/v1
WebhooksBusiness ขึ้นไปHomeHQ ส่ง POST ไปยัง URL ของคุณ
SCIM 2.0 (เพิ่ม/ลบผู้ใช้อัตโนมัติ)Enterprisehttps://homehqth.com/scim/v2

ตั้งค่าทั้งหมดได้ในแอป HomeHQ ที่เมนู ตั้งค่า → API และการเชื่อมต่อ (เฉพาะเจ้าของและผู้ดูแลองค์กร) — รูปแบบข้อมูลเวอร์ชัน 2026-10-01 ส่งกลับในหัว X-HomeHQ-Api-Version และในทุก webhook

ข้อมูลที่ API ไม่ส่ง ไม่ว่าจะมีสิทธิ์ใด: เลขบัตรประชาชน เลขบัญชีธนาคาร อัตราเงินเดือน เบอร์โทร รูปเซลฟี่ พิกัด GPS และเหตุผลการลา (อาจเป็นข้อมูลสุขภาพตาม PDPA) · ทุกคำขอเห็นเฉพาะข้อมูลขององค์กรที่เป็นเจ้าของ key เท่านั้น

เริ่มใช้งานใน 2 นาที

  1. เปิดแอป HomeHQ → ตั้งค่า → API และการเชื่อมต่อ → กด สร้าง API key ตั้งชื่อ (เช่น "ระบบเงินเดือน") แล้วเลือกสิทธิ์เท่าที่จำเป็น
  2. คัดลอก key ที่ขึ้นต้นด้วย hhq_ เก็บในที่ปลอดภัย (เช่น ตัวแปรแวดล้อมของเซิร์ฟเวอร์) — แสดงครั้งเดียว HomeHQ เก็บเฉพาะค่าแฮช
  3. ลองเรียก:
curl https://homehqth.com/api/v1/me \
  -H "Authorization: Bearer $HOMEHQ_API_KEY"
// Node.js 18+ (fetch มีในตัว)
const res = await fetch('https://homehqth.com/api/v1/members?limit=100', {
  headers: { Authorization: `Bearer ${process.env.HOMEHQ_API_KEY}` },
});
if (!res.ok) throw new Error((await res.json()).error.message);
const { data, pagination } = await res.json();
console.log(data.length, pagination.nextCursor);

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

ส่ง API key ในหัว Authorization: Bearer <key> ทุกคำขอ (ผ่าน HTTPS เท่านั้น) · ห้ามใส่ key ในโค้ดฝั่งเว็บเบราว์เซอร์หรือแอปมือถือ · key ไม่มีวันหมดอายุจนกว่าจะกด เพิกถอน — เพิกถอนแล้วใช้ไม่ได้ทันที · องค์กรมี key ที่ใช้งานอยู่ได้สูงสุด 20 อัน (แยก key ต่อระบบ จะได้เพิกถอนทีละระบบได้)

ถ้าองค์กรลดแพ็กเกจต่ำกว่า Business หรือแพ็กเกจหมดอายุ ทุกคำขอจะได้ 402 จนกว่าจะต่ออายุ (key เดิมยังอยู่ ไม่ต้องสร้างใหม่)

สิทธิ์ของ API key (scopes)

ทุก scope เป็นแบบอ่านอย่างเดียว · เรียก endpoint ที่ key ไม่มีสิทธิ์ จะได้ 403 INSUFFICIENT_SCOPE

Scopeใช้กับข้อมูลที่ได้
org:readโครงสร้างองค์กรบริษัท สาขา แผนก และตำแหน่ง
members:readรายชื่อพนักงานชื่อ อีเมล รหัสพนักงาน แผนก สาขา ตำแหน่ง สถานะการจ้างงาน (ไม่มีเลขบัตร/บัญชีธนาคาร/เงินเดือน)
attendance:readการลงเวลาเวลาเข้า-ออกงานรายวันตามช่วงวันที่ (ไม่มีรูปเซลฟี่/พิกัด)
leave:readการลางานใบลา ประเภท วันที่ จำนวนวัน และสถานะอนุมัติ
payroll:readสรุปเงินเดือนสรุปงวดเงินเดือนและยอดรวมสลิปรายคน (เฉพาะงวดที่ล็อก/จ่ายแล้ว · ไม่มีเลขบัญชีธนาคาร)

รายการ Endpoint

ที่อยู่หลัก https://homehqth.com/api/v1 · ตอบเป็น JSON (UTF-8) · วันที่ใช้รูปแบบ YYYY-MM-DD ตามเวลาประเทศไทย · เวลาเป็น ISO 8601 (UTC) · เงินเป็น สตางค์ (จำนวนเต็ม เช่น 2500000 = 25,000.00 บาท)

Method / PathScopeคำอธิบาย
GET/me—องค์กรและสิทธิ์ของ key นี้ (ใช้ทดสอบการเชื่อมต่อ)
GET/orgorg:readบริษัท สาขา แผนก ตำแหน่ง
GET/membersmembers:readรายชื่อพนักงาน (กรอง: status, departmentId, branchId, companyId, email)
GET/members/{id}members:readพนักงานหนึ่งคน
GET/attendanceattendance:readการลงเวลา — ต้องมี from, to (ช่วงไม่เกิน 93 วัน) · กรอง memberId
GET/leave-requestsleave:readใบลาที่คาบเกี่ยวช่วง from–to · กรอง status, memberId
GET/payroll/runspayroll:readงวดเงินเดือน + ยอดรวม (กรอง status, month=YYYY-MM)
GET/payroll/runs/{id}payroll:readงวดเงินเดือนหนึ่งงวด
GET/payroll/runs/{id}/payslipspayroll:readยอดรวมสลิปรายคน — เฉพาะงวดที่ล็อกหรือจ่ายแล้ว (ไม่งั้น 409 RUN_NOT_FINAL)
API เวอร์ชันนี้อ่านอย่างเดียว — ยื่นลา อนุมัติ หรือแก้ข้อมูลพนักงานทำในแอป HomeHQ (หรือผ่าน SCIM สำหรับรายชื่อพนักงาน) เพื่อให้ผ่านขั้นตอนอนุมัติและบันทึกประวัติครบ

พนักงาน — GET /members

พารามิเตอร์คำอธิบาย
statusactive · suspended · all (ค่าเริ่มต้น = ทุกคนที่ยังอยู่ในองค์กร) — คนที่ลาออกแล้วไม่อยู่ในรายการ (รับแจ้งผ่าน webhook member.left)
departmentId branchId companyIdกรองตามหน่วยงาน
emailหาจากอีเมล (ไม่สนตัวพิมพ์)
limit cursorดู การแบ่งหน้า
{
  "data": [
    {
      "id": "3f2a9c1e-…",
      "employeeCode": "EMP-0012",
      "name": "สมชาย ใจดี",
      "nickname": "ชาย",
      "email": "somchai@acme.co.th",
      "role": "member",
      "employmentStatus": "active",
      "resignEffectiveDate": null,
      "seatType": "full",
      "hasAccount": true,
      "company": {
        "id": "c-…",
        "name": "บริษัท เอซีเอ็มอี จำกัด"
      },
      "branch": {
        "id": "b-…",
        "name": "สำนักงานใหญ่"
      },
      "department": {
        "id": "d-…",
        "name": "บัญชี"
      },
      "position": {
        "id": "p-…",
        "title": "นักบัญชี"
      },
      "managerId": "m-…",
      "joinedAt": "2026-03-01T02:00:00.000Z"
    }
  ],
  "pagination": {
    "limit": 50,
    "hasMore": true,
    "nextCursor": "WyIyMDI2LTAzLTAxIDA5OjAwOjAwKzAwIiwiM2YyYTljMWUiXQ"
  }
}

การลงเวลา — GET /attendance?from=2026-10-01&to=2026-10-31

{
  "data": [
    {
      "id": "a-…",
      "memberId": "m-…",
      "workDate": "2026-10-01",
      "checkIn": "2026-10-01T01:58:12.000Z",
      "checkOut": "2026-10-01T11:03:40.000Z",
      "mode": "office",
      "branchId": "b-…",
      "edited": false
    }
  ],
  "pagination": {
    "limit": 100,
    "hasMore": false,
    "nextCursor": null
  }
}

mode: office เข้าออฟฟิศ · wfh ทำงานที่บ้าน · onsite นอกสถานที่ · edited = ฝ่ายบุคคลแก้ไขหรือเพิ่มให้ (มีประวัติในแอป)

การลา — GET /leave-requests?from=2026-10-01&to=2026-12-31&status=approved

คืนใบลาที่ช่วงวันลาคาบเกี่ยวกับ from–to · type เป็นรหัสประเภท (เช่น sick personal vacation หรือรหัส c_… ของประเภทที่องค์กรเพิ่มเอง) · portion: full morning afternoon · status: pending, approved, rejected, cancelled

เงินเดือน — GET /payroll/runs และ /payroll/runs/{id}/payslips

{
  "data": [
    {
      "id": "r-…",
      "companyId": "c-…",
      "month": "2026-09",
      "periodStart": "2026-09-01",
      "periodEnd": "2026-09-30",
      "payDate": "2026-09-30",
      "status": "paid",
      "lockedAt": "…",
      "paidAt": "…",
      "publishedAt": "…",
      "totals": {
        "headcount": 42,
        "incomeSatang": 128450000,
        "deductionSatang": 9800000,
        "netSatang": 118650000,
        "taxSatang": 3200000,
        "ssoEmployeeSatang": 3675000,
        "ssoEmployerSatang": 3675000
      }
    }
  ],
  "pagination": {
    "limit": 50,
    "hasMore": false,
    "nextCursor": null
  }
}

สลิปรายคนให้เฉพาะยอดรวม: รายได้ รายการหัก สุทธิ ภาษี ประกันสังคม กองทุนสำรองเลี้ยงชีพ พร้อมชื่อ/รหัส/แผนก ณ งวดนั้น — ไม่มีเลขบัญชีธนาคารและเลขบัตรประชาชน (ไฟล์โอนธนาคารสร้างในแอปเท่านั้น)

โครงสร้างองค์กร — GET /org

คืน companies branches departments positions ทั้งหมดในครั้งเดียว ใช้จับคู่ id กับระบบของคุณ

การแบ่งหน้า

รายการทุกชนิดใช้ cursor: ส่ง limit (1–200 ค่าเริ่มต้น 50 หรือ 100 สำหรับการลงเวลา/สลิป) แล้วเรียกหน้าถัดไปด้วย cursor=<pagination.nextCursor> จนกว่า hasMore เป็น false · cursor เป็นค่าทึบ อย่าแก้หรือประกอบเอง

async function all(path) {
  const out = [];
  let cursor = '';
  do {
    const url = new URL('https://homehqth.com/api/v1' + path);
    url.searchParams.set('limit', '200');
    if (cursor) url.searchParams.set('cursor', cursor);
    const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.HOMEHQ_API_KEY}` } });
    const body = await res.json();
    if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
    out.push(...body.data);
    cursor = body.pagination.nextCursor ?? '';
  } while (cursor);
  return out;
}

ข้อผิดพลาด

ทุกข้อผิดพลาดใช้รูปแบบเดียวกัน ข้อความเป็นภาษาอังกฤษ ให้ตัดสินจาก error.code (คงที่) ไม่ใช่ข้อความ และแนบ requestId เมื่อติดต่อทีมงาน

{
  "error": {
    "code": "INSUFFICIENT_SCOPE",
    "message": "This API key lacks the \"payroll:read\" scope",
    "requiredScope": "payroll:read"
  },
  "requestId": "6c1b…"
}
HTTPcodeความหมาย
400INVALID_REQUESTพารามิเตอร์ผิด (ดู error.param)
401UNAUTHORIZED / INVALID_API_KEYไม่ได้ส่ง key หรือ key ผิด/ถูกเพิกถอน
402PLAN_FEATURE / ORG_LOCKEDแพ็กเกจต่ำกว่า Business หรือแพ็กเกจหมดอายุ/องค์กรถูกระงับ
403INSUFFICIENT_SCOPEkey ไม่มีสิทธิ์ endpoint นี้ (ดู error.requiredScope)
404NOT_FOUNDไม่พบข้อมูล หรือเป็นข้อมูลขององค์กรอื่น
409RUN_NOT_FINALงวดเงินเดือนยังไม่ล็อก/จ่าย
429RATE_LIMITEDเรียกถี่เกินไป — รอตามหัว Retry-After
500SERVER_ERRORข้อผิดพลาดฝั่ง HomeHQ — ลองใหม่ภายหลัง

จำกัดความถี่

120 คำขอต่อนาทีต่อ API key · ทุกคำตอบมีหัว X-RateLimit-Limit X-RateLimit-Remaining X-RateLimit-Reset (unix วินาที) · เกินแล้วได้ 429 พร้อม Retry-After · ซิงก์ข้อมูลทั้งหมดวันละครั้ง + ใช้ webhook รับการเปลี่ยนแปลงระหว่างวัน จะไม่ชนเพดาน

Webhooks Business+

เพิ่มปลายทางที่ ตั้งค่า → API และการเชื่อมต่อ → Webhooks ใส่ URL (https เท่านั้น) เลือกเหตุการณ์ แล้วคัดลอก signing secret (whsec_… แสดงครั้งเดียว — หมุนใหม่ได้ทุกเมื่อ) · กด ส่งเหตุการณ์ทดสอบ เพื่อดูว่าระบบของคุณรับได้ และดูประวัติการส่ง (สถานะ HTTP เวลาที่ใช้ ข้อผิดพลาดล่าสุด) ได้ทันที

HomeHQ ส่ง POST แบบ JSON พร้อมหัวต่อไปนี้:

หัวค่า
X-HomeHQ-Signaturet=<unix>,v1=<hex> — ดู การตรวจลายเซ็น
X-HomeHQ-Eventชื่อเหตุการณ์ เช่น leave.approved
X-HomeHQ-Event-Idid ของเหตุการณ์ (คงเดิมทุกครั้งที่ส่งซ้ำ) — ใช้กันประมวลผลซ้ำ
X-HomeHQ-Deliveryid ของการส่งครั้งนี้
X-HomeHQ-Attemptครั้งที่ส่ง (1–5)
{
  "id": "evt_8mQ2vX…",
  "type": "leave.approved",
  "apiVersion": "2026-10-01",
  "createdAt": "2026-10-11T03:15:20.000Z",
  "orgId": "o-…",
  "data": {
    "leave": {
      "id": "l-…",
      "memberId": "m-…",
      "type": "vacation",
      "startDate": "2026-10-20",
      "endDate": "2026-10-21",
      "portion": "full",
      "days": 2,
      "status": "approved",
      "approverId": "m-…",
      "decidedAt": "2026-10-11T03:15:19.000Z",
      "createdAt": "2026-10-10T09:00:00.000Z"
    },
    "member": {
      "id": "m-…",
      "name": "สมชาย ใจดี",
      "employeeCode": "EMP-0012",
      "email": "somchai@acme.co.th"
    }
  }
}
ตอบ 2xx ภายใน 10 วินาที (ควรรับไว้ในคิวแล้วตอบทันที ค่อยประมวลผลทีหลัง) · HomeHQ ไม่ตามการเปลี่ยนเส้นทาง (3xx = ไม่สำเร็จ) · อ่านคำตอบไม่เกิน 64 KB · ปลายทางต้องเป็นที่อยู่สาธารณะ — localhost เครือข่ายภายใน (10.x, 192.168.x ฯลฯ) และที่อยู่ metadata ของคลาวด์ถูกปฏิเสธ

เหตุการณ์

เหตุการณ์เกิดเมื่อdata
member.joinedพนักงานเข้าร่วมองค์กร{ member }
member.leftพนักงานออกจากองค์กร (ลาออก/นำออก){ member, reason, terminationType, effectiveDate, lastWorkDate }
member.suspendedระงับการใช้งานพนักงาน{ member }
member.reactivatedเปิดใช้งานพนักงานอีกครั้ง{ member }
attendance.checked_inลงเวลาเข้างาน{ attendance, member }
attendance.checked_outลงเวลาออกงาน{ attendance, member }
leave.requestedยื่นใบลา{ leave, member }
leave.approvedอนุมัติใบลา{ leave, member }
leave.rejectedไม่อนุมัติใบลา{ leave, member }
request.approvedอนุมัติคำขอ (ลืมลงเวลา/OT/เบิกเงิน ฯลฯ){ request, member }
payroll.publishedเผยแพร่สลิปเงินเดือน{ run } (ยอดรวมทั้งงวด ไม่มียอดรายคน)
announcement.publishedประกาศใหม่{ announcement }

member ในเหตุการณ์ member.* มีรูปแบบเดียวกับ GET /members/{id} · ในเหตุการณ์อื่นเป็นข้อมูลย่อ { id, name, employeeCode, email } · member.joined เกิดเมื่อมีรายชื่อใหม่ในองค์กร (ผู้ดูแลเพิ่ม, SCIM, หรือพนักงานเข้าร่วมด้วยรหัสเชิญ) · ปุ่มทดสอบส่งเหตุการณ์ webhook.test

ตรวจลายเซ็น (สำคัญ)

ลายเซ็น = HMAC-SHA256 ของข้อความ <t>.<body ดิบ> ด้วย signing secret แล้วเข้ารหัสเป็น hex · ต้องคิดจาก body ดิบก่อนแปลง JSON · ปฏิเสธลายเซ็นที่ t ห่างจากเวลาปัจจุบันเกิน 5 นาที (กันการส่งซ้ำ) · เทียบแบบเวลาคงที่

// Node.js + Express
import crypto from 'node:crypto';
import express from 'express';

const app = express();
const SECRET = process.env.HOMEHQ_WEBHOOK_SECRET; // whsec_...
const seen = new Set(); // ใช้ฐานข้อมูลจริงในระบบของคุณ

app.post('/homehq/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const header = req.get('X-HomeHQ-Signature') || '';
  const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
  const t = Number(parts.t);
  const expected = crypto.createHmac('sha256', SECRET).update(`${t}.${req.body}`).digest('hex');
  const given = Buffer.from(parts.v1 || '', 'hex');
  const ok = given.length === 32 && crypto.timingSafeEqual(given, Buffer.from(expected, 'hex'))
    && Math.abs(Date.now() / 1000 - t) < 300;
  if (!ok) return res.status(400).send('bad signature');

  const event = JSON.parse(req.body);
  if (seen.has(event.id)) return res.sendStatus(200); // ส่งซ้ำ — ทำไปแล้ว
  seen.add(event.id);
  queue.push(event); // ประมวลผลทีหลัง
  res.sendStatus(200);
});
<?php // PHP
$secret = getenv("HOMEHQ_WEBHOOK_SECRET");
$body = file_get_contents("php://input");
parse_str(str_replace(",", "&", $_SERVER["HTTP_X_HOMEHQ_SIGNATURE"] ?? ""), $sig);
$expected = hash_hmac("sha256", $sig["t"] . "." . $body, $secret);
if (!hash_equals($expected, $sig["v1"] ?? "") || abs(time() - (int)$sig["t"]) > 300) {
  http_response_code(400); exit;
}
$event = json_decode($body, true);

หมุน secret ใหม่แล้ว secret เดิมใช้ไม่ได้ทันที — อัปเดตค่าในระบบของคุณก่อนกดหมุน หรือรับได้ทั้งสองค่าช่วงสั้น ๆ

การส่งซ้ำและการปิดอัตโนมัติ

ไม่ได้ 2xx (รวมหมดเวลา/ต่อไม่ได้) → ส่งซ้ำหลัง 1 นาที, 5 นาที, 30 นาที และ 2 ชั่วโมง (รวม 5 ครั้ง) ด้วย event id เดิม · ล้มเหลวครบทุกครั้งติดกัน 10 เหตุการณ์ → ปิดปลายทางอัตโนมัติและแจ้งผู้ดูแลในแอป แก้ระบบแล้วเปิดใหม่ได้ และกด ส่งอีกครั้ง ในประวัติการส่งได้ · เก็บประวัติการส่ง 30 วัน · ลำดับการมาถึงไม่รับประกัน ให้ใช้ createdAt เรียงเอง

SCIM 2.0 Enterprise

ให้ IdP ขององค์กรสร้างพนักงานใหม่ อัปเดตข้อมูล และระงับคนที่ออกจากบริษัทใน HomeHQ อัตโนมัติ · สร้าง token ที่ ตั้งค่า → API และการเชื่อมต่อ → SCIM (เฉพาะเจ้าของระบบ · ขึ้นต้นด้วย hhqscim_ แสดงครั้งเดียว องค์กรละ 1 token — สร้างใหม่แล้ว token เดิมใช้ไม่ได้ทันที)

รายการค่า
Tenant / Base URLhttps://homehqth.com/scim/v2
AuthenticationHTTP Header — Bearer token
Resources/Users /Groups /ServiceProviderConfig /ResourceTypes /Schemas
รองรับGET (filter: eq, ne, co, sw, ew, gt, lt, pr, and/or/not · startIndex/count) · POST · PUT · PATCH · DELETE
ไม่รองรับBulk, sort, ETag, เปลี่ยนรหัสผ่าน (พนักงานเข้าระบบด้วย Google/Microsoft หรืออีเมลของตัวเอง)
SCIM attributeHomeHQ
userNameอีเมล (แนะนำ — ใช้ผูกบัญชีตอนพนักงานเข้าระบบ) หรือชื่อผู้ใช้อื่น เช่น รหัสพนักงาน แล้วส่งอีเมลใน emails · ไม่มีอีเมลเลย = สร้างเป็นพนักงานที่ยังเข้าสู่ระบบไม่ได้
name.givenName name.familyName / displayNameชื่อ-นามสกุล
activefalse = ระงับการใช้งาน (เก็บประวัติลงเวลา/ลา/เงินเดือนครบ ไม่นับที่นั่ง) · true = เปิดใช้อีกครั้ง (ต้องมีที่นั่งว่าง)
titleตำแหน่ง (ไม่มีชื่อนี้ = สร้างให้ · ตำแหน่งในแผนกฝ่ายบุคคล = 400)
…enterprise:2.0:User:departmentแผนก (ไม่มี = สร้างให้ · แผนกฝ่ายบุคคล = 400)
…enterprise:2.0:User:employeeNumberรหัสพนักงาน
…enterprise:2.0:User:managerหัวหน้า (id ของ User ใน HomeHQ)
phoneNumbers nickName externalIdเบอร์โทร ชื่อเล่น รหัสจาก IdP
Groupแผนก — เพิ่มสมาชิกเข้ากลุ่ม = ย้ายเข้าแผนกนั้น (คนหนึ่งอยู่ได้แผนกเดียว) · แผนกที่สร้างในแอป: เพิ่ม/ถอดทีละคนได้ แต่เปลี่ยนชื่อ/แทนที่สมาชิกทั้งชุดไม่ได้
พฤติกรรมสำคัญ: POST สร้างรายชื่อพนักงาน (บทบาทพนักงานเสมอ — ตั้งผู้ดูแล/ฝ่ายบุคคลในแอป) และส่งอีเมลเชิญให้อัตโนมัติ พนักงานเข้าด้วยบัญชี Google/Microsoft หรืออีเมลเดียวกันแล้วได้รายชื่อนี้ · DELETE = ระงับการใช้งานและซ่อนจาก SCIM โดยไม่ลบประวัติ (กฎหมายแรงงานกำหนดให้เก็บเอกสารการจ้างอย่างน้อย 2 ปี) — ฝ่ายบุคคลตั้งวันลาออก/คำนวณค่าชดเชยต่อในแอป · ที่นั่งเต็มได้ 409 · สร้างซ้ำพร้อมกัน (IdP ส่งซ้ำ) ได้ 409 uniqueness เพียงคำขอเดียวที่สำเร็จ · POST ด้วย userName ของคนที่ลบไปแล้วจะฟื้นรายชื่อเดิมเฉพาะเมื่ออีเมลหรือ externalId ตรงกัน (ตรงแค่ userName = 409)
ขอบเขตสิทธิ์ของ SCIM (ตอบ 403 mutability): เจ้าของและผู้ดูแล อ่านได้ แต่แก้ไข ระงับ ลบ หรือย้ายแผนกไม่ได้ (ส่งค่าเดิมซ้ำได้ · ตั้ง externalId ได้) · ฝ่ายบุคคล — SCIM เพิ่มคนเข้า/ย้ายคนออกจากแผนกฝ่ายบุคคล และเปลี่ยนชื่อหรือสมาชิกของกลุ่มที่เป็นแผนกฝ่ายบุคคลไม่ได้ (department/title ที่ตรงกับแผนก/ตำแหน่งฝ่ายบุคคล = 400) · อีเมล ของหัวหน้างานหรือฝ่ายบุคคลที่ยังไม่เคยเข้าสู่ระบบเปลี่ยนผ่าน SCIM ไม่ได้ · PATCH มี Operations ได้ไม่เกิน 100 รายการ และ path ยาวไม่เกิน 512 ตัวอักษร — จัดการเรื่องเหล่านี้ในแอป HomeHQ

Microsoft Entra ID (Azure AD)

  1. Entra admin center → Enterprise applications → New application → Create your own application → ตั้งชื่อ "HomeHQ" เลือก Integrate any other application you don't find in the gallery (Non-gallery)
  2. เมนู Provisioning → Get started → Provisioning Mode = Automatic
  3. Tenant URL = https://homehqth.com/scim/v2 · Secret Token = SCIM token จาก HomeHQ → กด Test Connection แล้ว Save
  4. Mappings: ตรวจว่า userPrincipalName หรือ mail → userName (แนะนำอีเมลจริงที่พนักงานใช้ · ถ้าเป็นรหัสพนักงาน ให้ map mail → emails[type eq "work"].value ด้วย), Switch([IsSoftDeleted]…) → active, department → …:department, jobTitle → title — ลบ mapping ที่ไม่ใช้ได้
  5. Users and groups → เพิ่มคน/กลุ่มที่จะใช้ HomeHQ → กลับไปที่ Provisioning ตั้ง Provisioning Status = On (Entra ซิงก์ทุก ~40 นาที หรือกด Provision on demand เพื่อทดสอบทีละคน)

Okta

  1. Okta Admin → Applications → Create App Integration → SWA หรือ SAML 2.0 (ใช้เฉพาะเพื่อ provisioning ก็ได้) → แท็บ General → App Settings → Provisioning = SCIM
  2. แท็บ Provisioning → Integration: SCIM connector base URL = https://homehqth.com/scim/v2 · Unique identifier field = userName · เลือก Push New Users, Push Profile Updates, Push Groups · Authentication Mode = HTTP Header แล้ววาง token → Test Connector Configuration
  3. To App → เปิด Create Users, Update User Attributes, Deactivate Users
  4. แท็บ Assignments เพิ่มคน/กลุ่ม · แท็บ Push Groups เพื่อสร้างแผนกจากกลุ่ม Okta

Google Workspace

Google Workspace ไม่มีการส่ง SCIM ไปยังแอปที่ตั้งค่าเอง (auto-provisioning ของ Google ใช้ได้เฉพาะแอปในแคตตาล็อกที่ Google ทำไว้ล่วงหน้า และ HomeHQ ยังไม่อยู่ในรายการนั้น) — ทางที่ใช้ได้ตอนนี้: เปิด เข้าสู่ระบบด้วยบัญชีบริษัท (SSO) ด้วย Google Workspace (แพ็กเกจ Business+) ให้พนักงานเข้าด้วยบัญชีบริษัท ปิดบัญชีที่ Google แล้วใช้ HomeHQ ต่อไม่ได้ภายใน 24 ชั่วโมง ร่วมกับนำเข้ารายชื่อจาก Excel หรือใช้ REST API/สคริปต์ของคุณเองซิงก์รายชื่อ (Google Admin SDK → SCIM ของ HomeHQ) · ถ้าใช้ Entra ID หรือ Okta เชื่อม Google Workspace อยู่แล้ว ให้ตั้ง SCIM จาก Entra/Okta ตามด้านบน

ต้องการความช่วยเหลือในการเชื่อมระบบ?

ทีมงานช่วยวางแผนการเชื่อม API/SCIM กับระบบเดิมได้ — ลูกค้า Enterprise มีผู้ดูแลบัญชีเฉพาะองค์กร

ติดต่อทีมงาน