ช่วงเวลาการเข้าถึง
Access Time Windows ช่วยให้สมาชิกของพาร์ทเนอร์มีสิทธิ์การเข้าถึงชั่วคราวหรือแบบเกิดซ้ำที่ส่งมาจากระบบภายนอก หน้านี้เป็นคู่มือผู้ส่งข้อมูลฉบับทางการสำหรับ access_time_windows และ access_time_windows_revision
Access Time Windows เป็นสิทธิ์แบบเพิ่มเติมที่ใช้อนุญาตเท่านั้น ช่วงเวลาที่ใช้งานอยู่สามารถอนุญาตการเข้าถึงได้ แต่ช่วงเวลาที่ไม่ได้ใช้งาน หมดอายุ ข้อมูลเก่า หรือไม่ได้จับคู่ไว้ จะไม่ปฏิเสธการเข้าถึงที่กฎปกติหรือสิทธิ์แบบถาวรอนุญาตไว้แล้ว การปิดใช้งานผู้ใช้ การบล็อกประตูอย่างชัดเจน โหมดบำรุงรักษา Geofence การจำกัดอัตรา และความพร้อมใช้งานของตัวควบคุมยังคงมีผลอยู่
การพัฒนาสำหรับระบบต้นทางแต่ละระบบเป็นอะแดปเตอร์ที่แยกจากกัน อะแดปเตอร์ต้องแปลงข้อมูลต้นทางให้เป็นไปตามข้อตกลงที่ไม่ผูกกับผู้ให้บริการรายใดนี้ โดยไม่เปลี่ยนความหมายของฟิลด์
ฟิลด์สแนปช็อตของสมาชิก
-
access_time_windows
arrayไม่บังคับสแนปช็อต Access Time Window ที่สมบูรณ์สำหรับสมาชิกและแหล่งข้อมูลของพาร์ทเนอร์รายนี้ สแนปช็อตหนึ่งสามารถมีทั้งช่วงเวลาแบบ
absoluteและweeklyผสมกัน เว้นฟิลด์นี้ไว้เพื่อให้สแนปช็อตที่จัดเก็บไว้ไม่เปลี่ยนแปลง หรือส่ง[]เพื่อเพิกถอนทุกช่วงเวลาที่แหล่งข้อมูลนี้เป็นเจ้าของ -
access_time_windows_revision
integerจำเป็นเมื่อมี access_time_windowsจำนวนเต็มที่ไม่ติดลบ ปลอดภัยสำหรับ JSON และเพิ่มขึ้นทางเดียว สำหรับสตรีมเวอร์ชันของสมาชิก/แหล่งข้อมูลนี้ จำเป็นทุกครั้งที่มี
access_time_windowsและต้องไม่เกิน9007199254740991
แต่ละสแนปช็อตรองรับช่วงเวลาได้สูงสุด 50 รายการ external_id, scope_key และ label รองรับได้สูงสุด 120 อักขระ ช่วงเวลาแบบกำหนดวันเวลาแน่นอนครอบคลุมได้สูงสุด 90 วัน แต่ละวันในช่วงเวลาแบบรายสัปดาห์รองรับบล็อกที่ไม่ทับซ้อนกันได้สูงสุดแปดบล็อก ข้อมูลที่ไม่ถูกต้องจะถูกปฏิเสธ แทนที่จะถูกตัดทอนหรือคาดเดา
รูปแบบของช่วงเวลา
ช่วงเวลาแบบกำหนดวันเวลาแน่นอน (absolute) ระบุช่วงเวลาที่แน่นอนหนึ่งช่วง:
{
"external_id": "access-4b1782",
"kind": "absolute",
"from": 1792053000,
"to": 1792058400,
"timezone": "Australia/Perth",
"scope_key": "after_hours_entry",
"label": "Temporary site access"
}
ฟิลด์ที่จำเป็นคือ external_id, kind, from และ to ส่วน timezone, scope_key และ label ไม่บังคับ
ช่วงเวลาแบบรายสัปดาห์ (weekly) ระบุช่วงเวลาตามนาฬิกาท้องถิ่นที่เกิดซ้ำ ซึ่งอาจกำหนดขอบเขตด้วยเวลา UTC ได้:
{
"external_id": "weekly-early-access",
"kind": "weekly",
"timezone": "America/New_York",
"access_hours": {
"sun": [],
"mon": [["06:00", "08:30"]],
"tue": [["06:00", "08:30"]],
"wed": [["06:00", "08:30"]],
"thu": [["06:00", "08:30"]],
"fri": [["06:00", "08:30"]],
"sat": []
},
"active_from": 1790812800,
"active_until": 1796083200,
"scope_key": "main_entry",
"label": "Weekday early access"
}
ฟิลด์ที่จำเป็นคือ external_id, kind และ access_hours ส่วน timezone, active_from, active_until, scope_key และ label ไม่บังคับ
ตัวอย่างคำขอแบบผสมที่สมบูรณ์
คำขอนี้จะแทนที่สแนปช็อตเดิมของสมาชิกที่แหล่งข้อมูลเป็นเจ้าของ ด้วยช่วงเวลาแบบกำหนดวันเวลาแน่นอนหนึ่งช่วงและแบบรายสัปดาห์หนึ่งช่วง:
curl -X POST https://partner-api.performancehub.co/partner/v1/members \
-u sk_live_YOUR_PARTNER_SECRET_KEY: \
-H "Content-Type: application/json" \
-d '{
"members": [
{
"member_id": "member_11111",
"facility_id": "550e8400-e29b-41d4-a716-446655440000",
"first_name": "John",
"last_name": "Smith",
"access_time_windows_revision": 1842,
"access_time_windows": [
{
"external_id": "access-4b1782",
"kind": "absolute",
"from": 1792053000,
"to": 1792058400,
"timezone": "Australia/Perth",
"scope_key": "after_hours_entry",
"label": "Temporary site access"
},
{
"external_id": "weekly-early-access",
"kind": "weekly",
"timezone": "America/New_York",
"access_hours": {
"sun": [],
"mon": [["06:00", "08:30"]],
"tue": [["06:00", "08:30"]],
"wed": [["06:00", "08:30"]],
"thu": [["06:00", "08:30"]],
"fri": [["06:00", "08:30"]],
"sat": []
},
"active_from": 1790812800,
"active_until": 1796083200,
"scope_key": "main_entry",
"label": "Weekday early access"
}
]
}
]
}'
ใช้ facility_id หรือ linking_identifier อย่างใดอย่างหนึ่งตามวิธีการเชื่อมโยงที่คุณกำหนดค่าไว้ อย่าส่งทั้งสองค่า
กฎเกี่ยวกับเวลาและขอบเขต
from, to, active_from และ active_until เป็นจำนวนเต็มวินาที Unix แบบ JSON ที่ระบุเวลา UTC:
- ส่งเป็นจำนวนเต็ม JSON ที่ไม่มีเครื่องหมายคำพูด สตริงตัวเลข ทศนิยม สตริง RFC 3339 และมิลลิวินาที Unix จะถูกปฏิเสธ
- ทุกช่วงเวลาเป็นแบบครึ่งเปิด:
[from, to)การเข้าถึงเริ่มต้นได้ตรงเวลาfromพอดี และสิ้นสุดการใช้งานตรงเวลาtoพอดี fromต้องน้อยกว่าtoเมื่อมีขอบเขตรายสัปดาห์ทั้งสองค่าactive_fromต้องน้อยกว่าactive_until- อย่าคำนวณ epoch จากวันที่/เวลาท้องถิ่นที่ไม่มีเขตเวลา ให้แปลงเวลาต้นทางเป็นเวลา UTC ก่อน แล้วจึงหารมิลลิวินาที Unix ด้วย 1000 และตรวจสอบว่าผลลัพธ์เป็นจำนวนเต็ม
การแปลง epoch
2026-10-15T08:30:00Z แปลงเป็น 1792053000:
UTC instant Unix milliseconds Unix seconds sent
2026-10-15T08:30:00Z 1792053000000 1792053000
การแปลงที่ไม่ขึ้นกับภาษาโปรแกรม:
instant = parse_source_timestamp_with_explicit_zone(source_timestamp)
milliseconds = instant.to_unix_milliseconds()
assert milliseconds modulo 1000 equals 0
seconds = milliseconds / 1000
assert seconds is a JSON-safe nonnegative integer
หากแหล่งข้อมูลมีความละเอียดต่ำกว่าวินาที ให้กำหนดนโยบายการปัดเศษเวลาเริ่มต้น/สิ้นสุดอย่างชัดเจนก่อนการทดสอบการผสานรวม อย่าส่งเป็นมิลลิวินาทีแล้วพึ่งพาให้ API อนุมานหน่วยเอง
เขตเวลาและเวลาออมแสง
timezone ต้องเป็นเขตเวลา IANA ที่ถูกต้อง เช่น UTC, Australia/Perth หรือ America/New_York หากเว้นไว้ ค่าเริ่มต้นคือ UTC
- ช่วงเวลาแบบกำหนดวันเวลาแน่นอน:
fromและtoระบุเวลา UTC ที่แน่นอนอยู่แล้วtimezoneเป็นเพียงข้อมูลเมตาสำหรับการแสดงผลและการตรวจสอบ การเปลี่ยนค่านี้จะไม่เลื่อนเวลาใดเวลาหนึ่ง - ช่วงเวลาแบบรายสัปดาห์:
timezoneกำหนดนาฬิกาท้องถิ่นและกฎเวลาออมแสงที่ใช้ประเมินaccess_hoursอย่าแปลงบล็อกรายสัปดาห์เป็น UTC ล่วงหน้า - ระหว่างการปรับเวลาเดินหน้า เวลาท้องถิ่นที่เขตเวลาข้ามไปจะไม่เกิดขึ้น
- ระหว่างการปรับเวลาถอยหลัง เวลาจริงทั้งสองช่วงที่มีเวลาท้องถิ่นซ้ำกันจะตรงกับบล็อกรายสัปดาห์
active_fromและactive_untilยังคงเป็นเวลา UTC แม้ช่วงเวลาแบบรายสัปดาห์จะใช้เขตเวลาที่ไม่ใช่ UTC
access_hours ใช้ค่าตัวพิมพ์เล็ก sun ถึง sat แต่ละค่าเป็นอาร์เรย์ของคู่ [start, end] ในรูปแบบ HH:mm แบบ 24 ชั่วโมงที่เติมศูนย์ข้างหน้า บล็อกต้องไม่ว่าง เรียงลำดับ และไม่ทับซ้อนกัน end ไม่รวมอยู่ในช่วง บล็อกไม่สามารถข้ามเที่ยงคืนได้ ให้แยกช่วงเวลาข้ามคืนของต้นทางเป็นบล็อกช่วงดึกในวันแรกและบล็อกช่วงเช้าในวันถัดไป
ID ที่คงที่และการจับคู่ขอบเขต
external_id ต้องคงที่ตลอดอายุของช่วงเวลาเชิงตรรกะ และไม่ซ้ำกันภายในสแนปช็อตของสมาชิก รักษาค่าให้คงที่เมื่อเวลาหรือป้ายกำกับเปลี่ยนแปลง เพื่อให้ผู้ปฏิบัติงานและบันทึกการตรวจสอบเชื่อมโยงเวอร์ชันต่าง ๆ ได้ อย่านำกลับมาใช้กับช่วงเวลาที่ไม่เกี่ยวข้อง
scope_key คือเป้าหมายการเข้าถึงเชิงตรรกะที่คงที่ของคุณ ค่าเริ่มต้นคือ default ผู้ดูแลระบบของสถานที่จะจับคู่คีย์ที่อนุญาตแต่ละรายการกับเป้าหมายใน Performance Hub ได้แก่ ทั้งสถานที่ ประตู หรือขอบเขตการเข้าถึง:
Partner scope_key Performance Hub mapping
default Facility's configured default target
main_entry Access Scope "Main entrances"
after_hours_entry Doors approved for after-hours entry
พาร์ทเนอร์ไม่ต้องส่ง ID ของสถานที่ ประตู หรือขอบเขตการเข้าถึงของ Performance Hub ภายในช่วงเวลา scope_key ที่ไม่รู้จัก ถูกปิดใช้งาน หรือไม่ได้จับคู่ไว้จะไม่ให้สิทธิ์เข้าถึง สำหรับช่วงเวลานั้น และจะไม่ขยายสิทธิ์การเข้าถึง ตกลงและทดสอบการจับคู่ก่อนเปิดตัว
สแนปช็อตที่สมบูรณ์และเวอร์ชัน
ให้ถือว่าฟิลด์ทั้งสองเป็นพาร์ทิชันที่กำหนดเวอร์ชันแยกต่างหากภายใน upsert ของสมาชิก:
| ข้อมูลนำเข้า | ผลลัพธ์ |
|---|---|
เว้น access_time_windows ไว้ | สแนปช็อตที่มีอยู่ไม่เปลี่ยนแปลง ไม่ต้องระบุเวอร์ชัน |
| มีค่าพร้อมเวอร์ชันที่ใหม่กว่า | สแนปช็อตที่จัดเก็บไว้ทั้งหมดของสมาชิก/แหล่งข้อมูลนี้ถูกแทนที่ |
| เวอร์ชันเดิมและเพย์โหลดที่ปรับให้เป็นมาตรฐานแล้วเหมือนเดิม | การส่งซ้ำแบบ Idempotent สแนปช็อตไม่เปลี่ยนแปลง |
| เวอร์ชันเดิมแต่เพย์โหลดที่ปรับให้เป็นมาตรฐานแล้วต่างกัน | ความขัดแย้ง ให้จัดสรรเวอร์ชันใหม่หลังจากกระทบยอด |
| เวอร์ชันที่เก่ากว่า | สแนปช็อตเก่าจะถูกข้าม และไม่สามารถเขียนทับสถานะที่ใหม่กว่าได้ |
access_time_windows: [] พร้อมเวอร์ชันที่ใหม่กว่า | เพิกถอนช่วงเวลาทั้งหมดที่แหล่งข้อมูลเป็นเจ้าของอย่างชัดเจน |
สแนปช็อตเป็นข้อมูลที่สมบูรณ์ ไม่ใช่การแก้ไขบางส่วน หากเวอร์ชัน 1842 มีช่วงเวลา A และ B แล้วเวอร์ชัน 1843 มีเพียง B ช่วงเวลา A จะถูกนำออก
ดูแลสตรีมเวอร์ชันที่ประสานกันเพียงสตรีมเดียวต่อพาร์ทเนอร์/สมาชิก ครอบคลุมเวิร์กเกอร์ webhook การโพล การส่งซ้ำ และการกระทบยอดแบบเต็ม แนะนำให้ใช้ลำดับเลขในฐานข้อมูลที่คงทน ค่ามิลลิวินาที Unix ใช้เป็นเวอร์ชันได้ก็ต่อเมื่อผู้เขียนทุกรายประสานงานกันและรับประกันลำดับและความไม่ซ้ำกันอย่างเคร่งครัดเท่านั้น ค่านี้เป็นค่าเวอร์ชัน ไม่ใช่ฟิลด์ epoch
เก็บคำขอและเวอร์ชันที่แน่นอนไว้จนกว่าจะทราบผลการตอบกลับของ API ลองส่งสแนปช็อตที่ปรับให้เป็นมาตรฐานเดิมซ้ำด้วยเวอร์ชันเดิมหลังจากหมดเวลาหรือเกิดข้อผิดพลาดชั่วคราว อย่าจัดสรรเวอร์ชันใหม่เพียงเพราะไม่แน่ใจว่าการรับส่งข้อมูลสำเร็จหรือไม่
การยกเลิก การหมดอายุ และความล้มเหลวของต้นทาง
- ยกเลิกช่วงเวลาหนึ่งช่วง: ดึงสถานะจากแหล่งข้อมูลที่เชื่อถือได้ให้สำเร็จ นำช่วงเวลานั้นออก แล้วส่งสแนปช็อตที่สมบูรณ์ซึ่งเหลืออยู่พร้อมเวอร์ชันที่ใหม่กว่า
- ยกเลิกทุกช่วงเวลา: ส่ง
access_time_windows: []พร้อมเวอร์ชันที่ใหม่กว่า - ปล่อยให้ช่วงเวลาแบบกำหนดวันเวลาแน่นอนหมดอายุ: ช่วงเวลาจะหยุดอนุญาตที่
toให้ส่งการกระทบยอดในภายหลังโดยไม่มีรายการที่หมดอายุ เพื่อให้สแนปช็อตสะอาด - สิ้นสุดช่วงเวลาแบบรายสัปดาห์: นำออกในสแนปช็อตที่ใหม่กว่า หรือใช้
active_untilเมื่อแหล่งข้อมูลทราบเวลาสิ้นสุดที่แน่นอน - การดึงข้อมูลจากต้นทางล้มเหลวหรือไม่ครบถ้วน: อย่าส่ง
[]และอย่าเผยแพร่สแนปช็อตที่ไม่ครบถ้วน ให้แจ้งเตือนและลองดึงข้อมูลใหม่ การเปลี่ยนความล้มเหลวของต้นทางให้เป็นสแนปช็อตว่างคือการเพิกถอนสิทธิ์การเข้าถึงโดยไม่ตั้งใจ - คำขอ Partner API ไม่ผ่านการตรวจสอบความถูกต้อง: แก้ไขข้อมูลและส่งเวอร์ชันที่ใหม่กว่าเฉพาะเมื่อสแนปช็อตที่ปรับให้เป็นมาตรฐานเปลี่ยนแปลงเท่านั้น ลองใหม่สำหรับความล้มเหลวชั่วคราวด้วยเวอร์ชันเดิม
ความเป็นปัจจุบันของแหล่งข้อมูลกำหนดค่าแยกตามการผสานรวม ตามรอบการส่งข้อมูลและการกระทบยอดที่สัญญาไว้ ก่อนเปิดใช้งาน ให้ตกลงเรื่องอายุสูงสุดของข้อมูลต้นทาง สิ่งที่จะเกิดขึ้นเมื่อเกินอายุนั้น เกณฑ์การแจ้งเตือน และผู้ปฏิบัติงานจะรับทราบการพึ่งพาเพียงขอบเขตของแต่ละช่วงเวลาได้หรือไม่ ช่วงเวลาจากแหล่งข้อมูลที่เก่าจะไม่กลายเป็นกฎการปฏิเสธ กฎปกติและสิทธิ์แบบถาวรยังคงเป็นเส้นทางสำรอง
อัลกอริทึมของผู้ส่งข้อมูล
ใช้ขั้นตอนการทำงานที่ไม่ขึ้นกับภาษาโปรแกรมนี้สำหรับการอัปเดตสมาชิกทุกครั้ง:
function publish_member(member_key):
source_result = fetch_authoritative_access_state(member_key)
if source_result.failed or source_result.incomplete:
record_failure(member_key)
schedule_retry(member_key)
return without sending access_time_windows
windows = []
for source_window in source_result.current_windows:
if source_window.is_absolute:
windows.append({
external_id: stable_window_id(source_window),
kind: "absolute",
from: to_integer_unix_seconds(source_window.start_instant),
to: to_integer_unix_seconds(source_window.end_instant),
timezone: source_window.display_timezone or "UTC",
scope_key: stable_scope_key(source_window) or "default",
label: safe_label(source_window)
})
else:
windows.append({
external_id: stable_window_id(source_window),
kind: "weekly",
timezone: valid_iana_zone(source_window.timezone) or "UTC",
access_hours: split_validate_and_sort_weekly_blocks(source_window),
active_from: optional_integer_unix_seconds(source_window.active_start),
active_until: optional_integer_unix_seconds(source_window.active_end),
scope_key: stable_scope_key(source_window) or "default",
label: safe_label(source_window)
})
normalized_snapshot = validate_sort_and_deduplicate(windows)
revision = next_durable_member_revision(member_key)
request = member_upsert_with(normalized_snapshot, revision)
persist_for_retry(member_key, request)
response = post_request(request)
if response.is_transient_or_unknown:
retry_exact_request_with_same_revision(request)
else if response.is_revision_conflict:
reconcile_with_latest_committed_source_state(member_key)
else if response.is_stale_skip:
stop_replaying_this_revision_and_reconcile(member_key)
รายการตรวจสอบการรับรอง
ทำการตรวจสอบเหล่านี้ให้ครบในสถานที่ระดับ stage โดยใช้การจับคู่ scope_key ฉบับสุดท้าย:
- ช่วงเวลาแบบกำหนดวันเวลาแน่นอนที่ไม่ระบุเขตเวลาได้รับการยอมรับและประเมินเป็น UTC
- ช่วงเวลาแบบกำหนดวันเวลาแน่นอนที่ใช้เขตเวลา IANA แบบกำหนดเองคงเวลา
from/toเดิมไว้ - ช่วงเวลาแบบรายสัปดาห์ที่ใช้เขตเวลา IANA แบบกำหนดเองเป็นไปตามเวลานาฬิกาท้องถิ่นตลอดการปรับเวลาเดินหน้าและถอยหลัง
- สแนปช็อตแบบผสมระหว่างกำหนดวันเวลาแน่นอน/รายสัปดาห์แทนที่สแนปช็อตก่อนหน้าทั้งหมด
- การเข้าถึงเริ่มต้นตรงเวลา
fromพอดีและหยุดตรงเวลาtoพอดี และเวลาสิ้นสุดของบล็อกรายสัปดาห์ก็ไม่รวมอยู่ในช่วงเช่นกัน - การอัปเดตเวลาภายใต้
external_idเดิมพร้อมเวอร์ชันที่ใหม่กว่ามีผล - การเว้น
access_time_windowsไว้จะเปลี่ยนฟิลด์อื่นของสมาชิกโดยไม่เปลี่ยนช่วงเวลา - การส่งเวอร์ชัน/เพย์โหลดเดิมซ้ำเป็นแบบ Idempotent
- เวอร์ชันเดิม/เพย์โหลดต่างกันจะส่งคืนความขัดแย้งและไม่เปลี่ยนสแนปช็อต
- เวอร์ชันที่เก่ากว่าซึ่งมาไม่ตามลำดับจะถูกรายงานว่าเก่า และไม่สามารถย้อนสถานะกลับได้
-
[]ที่ใหม่กว่าจะเพิกถอนช่วงเวลาที่แหล่งข้อมูลเป็นเจ้าของ ส่วนความล้มเหลวในการดึงข้อมูลจากต้นทางจะไม่ส่งสิ่งใดออกไป -
scope_keyที่ไม่รู้จักหรือไม่ได้จับคู่ไว้จะไม่ให้สิทธิ์เข้าถึง และสร้างคำเตือนที่ผู้ปฏิบัติงานมองเห็นได้ - การแจ้งเตือนอายุของข้อมูลต้นทางและนโยบายแหล่งข้อมูลเก่าที่กำหนดค่าไว้ทำงานตามเกณฑ์ที่ตกลงไว้
- เส้นทาง webhook และการกระทบยอดแบบเต็มบรรจบกันที่สแนปช็อตและลำดับเวอร์ชันเดียวกัน
- การส่งข้อมูลผ่านสตรีมไปถึง Door & Gate Access ภายในเป้าหมายที่ตกลงไว้
- ช่วงเวลาที่ใช้งานอยู่สามารถอนุญาตประตูจริงที่จับคู่ไว้ได้ แต่ไม่สามารถข้ามการปิดใช้งานผู้ใช้
blockAllAccessการบำรุงรักษา หรือ Geofence ได้ - ก่อน นอก และหลังช่วงเวลา กฎปกติและสิทธิ์แบบถาวรยังคงอนุญาตผู้ใช้ที่มีคุณสมบัติตามปกติ
เวกเตอร์ทดสอบขั้นต่ำ
[
{
"name": "absolute-half-open",
"window": {
"external_id": "tv-absolute",
"kind": "absolute",
"from": 1792053000,
"to": 1792058400
},
"expect": {
"1792052999": "inactive",
"1792053000": "active",
"1792058399": "active",
"1792058400": "inactive"
}
},
{
"name": "weekly-dst",
"window": {
"external_id": "tv-weekly-dst",
"kind": "weekly",
"timezone": "America/New_York",
"access_hours": {
"sun": [["01:00", "03:30"]],
"mon": [],
"tue": [],
"wed": [],
"thu": [],
"fri": [],
"sat": []
}
},
"expect": "Evaluate local wall time: skipped times do not occur; both repeated 01:30 instants qualify."
}
]
ส่งเวกเตอร์เชิงลบสำหรับมิลลิวินาที Unix สตริงตัวเลข ทศนิยม เขตเวลา IANA ที่ไม่ถูกต้อง from >= to external_id ที่ซ้ำกัน บล็อกที่ทับซ้อนกัน บล็อกข้ามคืน บล็อกมากกว่าแปดบล็อกในหนึ่งวัน ช่วงเวลามากกว่า 50 รายการ และคีย์ขอบเขตที่ไม่ได้จับคู่ไว้ด้วย