חלונות זמן גישה
Access Time Windows מאפשרים לחבר שמגיע משותף (Partner Member) לשאת גישה זמנית או חוזרת שסופקה על ידי מערכת חיצונית. דף זה הוא המדריך המוסמך ליצרנים עבור access_time_windows ו-access_time_windows_revision.
Access Time Windows הם הרשאות שמתווספות לקיימות ומתירות בלבד. חלון פעיל יכול להתיר גישה, אבל חלון לא פעיל, שפג תוקפו, שאינו עדכני או שאינו ממופה אינו שולל גישה שכלל רגיל או הרשאה קבועה כבר מתירים. השבתת משתמש, חסימת דלת מפורשת, מצב תחזוקה, גידור גאוגרפי, מגבלות קצב וזמינות הבקר עדיין חלים.
מימושים עבור מערכות מקור מסוימות הם מתאמים נפרדים. עליהם לתרגם את נתוני המקור שלהם לחוזה זה, הבלתי תלוי בספק, בלי לשנות את המשמעות של השדות שלו.
שדות תמונת המצב של החבר
-
access_time_windows
arrayאופציונליתמונת המצב המלאה של Access Time Windows עבור החבר ומקור השותף הזה. תמונת מצב יכולה לשלב חלונות
absoluteו-weekly. השמיטו את השדה כדי להשאיר את תמונת המצב השמורה ללא שינוי; שלחו[]כדי לשלול כל חלון ששייך למקור הזה. -
access_time_windows_revision
integerחובה עם access_time_windowsמספר שלם אי-שלילי, בטוח לשימוש ב-JSON, שעולה באופן מונוטוני בזרם הגרסאות של החבר/המקור הזה. הוא חובה בכל פעם ש-
access_time_windowsקיים, ואסור שיעלה על9007199254740991.
כל תמונת מצב מקבלת 50 חלונות לכל היותר. external_id, scope_key ו-label מקבלים 120 תווים לכל היותר. חלונות מוחלטים יכולים להשתרע על 90 ימים לכל היותר. יום שבועי מקבל שמונה מקטעים לא חופפים לכל היותר. נתונים לא תקינים נדחים, ולא נקטעים או מנוחשים.
מבני החלונות
חלון מוחלט מזהה מרווח מדויק אחד:
{
"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 הם אופציונליים.
חלון שבועי מזהה מרווחים חוזרים לפי שעון הקיר המקומי, ובאופן אופציונלי מוגבל בנקודות זמן של 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 אינו כלול. מקטע אינו יכול לחצות את חצות; פצלו מרווח לילי מהמקור למקטע מאוחר ביום הראשון ולמקטע מוקדם ביום שלמחרת.
מזהים יציבים ומיפוי טווחים
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
שותפים אינם שולחים בתוך חלון מזהים של מתקן, דלת או טווח גישה של Performance Hub. scope_key לא מוכר, מושבת או לא ממופה גורם לכך שהחלון הזה אינו מעניק גישה; הוא אינו מרחיב את הגישה. סכמו על המיפויים ובדקו אותם לפני ההשקה.
תמונות מצב מלאות וגרסאות
התייחסו לשני השדות כאל מחיצה עם ניהול גרסאות נפרד בתוך פעולת ה-upsert של החבר:
| קלט | תוצאה |
|---|---|
access_time_windows מושמט | תמונת המצב הקיימת נשארת ללא שינוי; אין צורך בגרסה |
| קיים עם גרסה חדשה יותר | כל תמונת המצב השמורה של החבר/המקור הזה מוחלפת |
| אותה גרסה ואותו מטען מנורמל | שליחה חוזרת אידמפוטנטית; אין שינוי בתמונת המצב |
| אותה גרסה ומטען מנורמל שונה | התנגשות; הקצו גרסה חדשה לאחר ביצוע התאמה |
| גרסה ישנה יותר | תמונת המצב הישנה מדולגת; היא אינה יכולה לדרוס מצב חדש יותר |
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משנה שדות אחרים של החבר בלי לשנות את החלונות. - שליחה חוזרת של אותה גרסה/אותו מטען היא אידמפוטנטית.
- אותה גרסה/מטען שונה מחזירה התנגשות ואינה משנה את תמונת המצב.
- גרסה ישנה יותר שמגיעה שלא לפי הסדר מדווחת כלא עדכנית ואינה יכולה להחזיר את המצב לאחור.
-
[]חדש יותר שולל את החלונות ששייכים למקור; כשל בשליפה ממערכת המקור אינו שולח דבר. -
scope_keyלא מוכר או לא ממופה אינו מעניק גישה, ויוצר אזהרה שגלויה למפעילים. - התראות על גיל נתוני המקור ומדיניות המקור הלא עדכני שהוגדרה פועלות בסף שסוכם.
- נתיבי ה-webhook וההתאמה המלאה מתכנסים לאותה תמונת מצב ולאותו סדר גרסאות.
- המסירה בזרם מגיעה ל-Door & Gate Access בתוך היעד שסוכם.
- חלון פעיל יכול להתיר גישה לדלת הפיזית הממופה, אבל אינו יכול לעקוף השבתת משתמש,
blockAllAccess, תחזוקה או גידור גאוגרפי. - לפני חלון, מחוצה לו ואחריו, כללים רגילים והרשאות קבועות עדיין מתירים גישה למשתמשים שעומדים בתנאים בדרך אחרת.
וקטורי בדיקה מינימליים
[
{
"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 חלונות ומפתחות טווח לא ממופים.