Toegangstijdvensters
Met Access Time Windows kan een Partner Member tijdelijke of terugkerende toegang meekrijgen die door een extern systeem wordt aangeleverd. Deze pagina is de gezaghebbende handleiding voor producenten van access_time_windows en access_time_windows_revision.
Access Time Windows zijn aanvullende rechten die alleen toegang kunnen toestaan. Een actief venster kan toegang toestaan, maar een inactief, verlopen, verouderd of niet-toegewezen venster weigert geen toegang die een reguliere regel of een permanent toegangsrecht al toestaat. Het uitschakelen van gebruikers, expliciete deurblokkering, de onderhoudsmodus, geofencing, snelheidslimieten en de beschikbaarheid van controllers blijven van toepassing.
Implementaties voor specifieke upstream systemen zijn afzonderlijke adapters. Ze moeten hun brongegevens vertalen naar dit leverancierneutrale contract zonder de betekenis van de velden te veranderen.
Velden van de momentopname van een lid
-
access_time_windows
arrayoptioneelDe volledige momentopname van Access Time Windows voor dit lid en deze partnerbron. Een momentopname kan
absolute- enweekly-vensters combineren. Laat het veld weg om de opgeslagen momentopname ongewijzigd te laten; stuur[]om elk venster van deze bron in te trekken. -
access_time_windows_revision
integerverplicht met access_time_windowsEen monotoon oplopend, niet-negatief JSON-veilig geheel getal voor de revisiereeks van dit lid/deze bron. Het is verplicht wanneer
access_time_windowsaanwezig is en mag niet groter zijn dan9007199254740991.
Elke momentopname accepteert maximaal 50 vensters. external_id, scope_key en label accepteren maximaal 120 tekens. Absolute vensters kunnen maximaal 90 dagen beslaan. Een weekdag accepteert maximaal acht niet-overlappende blokken. Ongeldige gegevens worden geweigerd in plaats van ingekort of geraden.
Vormen van vensters
Een absoluut venster geeft één exact interval aan:
{
"external_id": "access-4b1782",
"kind": "absolute",
"from": 1792053000,
"to": 1792058400,
"timezone": "Australia/Perth",
"scope_key": "after_hours_entry",
"label": "Temporary site access"
}
Verplichte velden zijn external_id, kind, from en to. timezone, scope_key en label zijn optioneel.
Een wekelijks venster geeft terugkerende intervallen in lokale kloktijd aan, eventueel begrensd door UTC-tijdstippen:
{
"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"
}
Verplichte velden zijn external_id, kind en access_hours. timezone, active_from, active_until, scope_key en label zijn optioneel.
Volledig gecombineerd verzoek
Dit verzoek vervangt de vorige momentopname van de bron voor het lid door één absoluut en één wekelijks venster:
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"
}
]
}
]
}'
Gebruik facility_id of linking_identifier, afhankelijk van je geconfigureerde koppelmethode. Stuur niet beide.
Regels voor tijden en grenzen
from, to, active_from en active_until zijn JSON-gehele getallen in Unix-seconden die UTC-tijdstippen aangeven:
- Stuur een JSON-geheel getal zonder aanhalingstekens. Numerieke tekenreeksen, drijvendekommagetallen, RFC 3339-tekenreeksen en Unix-milliseconden worden geweigerd.
- Elk interval is halfopen:
[from, to). Toegang kan precies opfrombeginnen; precies optois die niet meer actief. frommoet kleiner zijn danto. Als beide wekelijkse grenzen aanwezig zijn, moetactive_fromkleiner zijn danactive_until.- Leid epochs niet af van een lokale datum/tijd zonder tijdzone. Zet de brontijd eerst om naar een UTC-tijdstip, deel daarna de Unix-milliseconden door 1000 en controleer of het resultaat een geheel getal is.
Epochconversie
2026-10-15T08:30:00Z wordt omgezet naar 1792053000:
UTC instant Unix milliseconds Unix seconds sent
2026-10-15T08:30:00Z 1792053000000 1792053000
Taalonafhankelijke conversie:
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
Als de bron een precisie onder de seconde heeft, leg dan vóór het testen van de integratie bewust een afrondingsbeleid voor begin en einde vast. Geef nooit milliseconden door in de verwachting dat de API de eenheid zelf afleidt.
Tijdzones en zomertijd
timezone moet een geldige IANA-tijdzone zijn, zoals UTC, Australia/Perth of America/New_York. Als dit veld wordt weggelaten, is de standaardwaarde UTC.
- Absolute vensters:
fromentogeven al exacte UTC-tijdstippen aan.timezoneis alleen metadata voor weergave en audit; een wijziging ervan verschuift geen van beide tijdstippen. - Wekelijkse vensters:
timezonebepaalt de lokale kloktijd en de zomertijdregels waarmeeaccess_hourswordt geëvalueerd. Zet wekelijkse blokken niet vooraf om naar UTC. - Bij de overgang naar zomertijd komt een lokale tijd die de tijdzone overslaat nooit voor.
- Bij de overgang naar wintertijd vallen beide echte tijdstippen met de herhaalde lokale tijd binnen het wekelijkse blok.
active_fromenactive_untilblijven UTC-tijdstippen, ook wanneer een wekelijks venster een andere tijdzone dan UTC gebruikt.
access_hours gebruikt sun tot en met sat in kleine letters. Elke waarde is een array van [start, end]-paren in 24-uursnotatie HH:mm met voorloopnullen. Blokken mogen niet leeg zijn, moeten op volgorde staan en mogen niet overlappen. end is exclusief. Een blok kan niet over middernacht heen lopen; splits een nachtelijk broninterval in een laat blok op de eerste dag en een vroeg blok op de volgende dag.
Stabiele ID's en scopetoewijzing
external_id moet stabiel zijn gedurende de levensduur van een logisch venster en uniek binnen de momentopname van het lid. Houd het stabiel wanneer tijden of labels veranderen, zodat beheerders en auditrecords revisies aan elkaar kunnen koppelen. Gebruik het niet opnieuw voor een venster dat er niets mee te maken heeft.
scope_key is je stabiele logische toegangsdoel. De standaardwaarde is default. Een beheerder van de faciliteit wijst elke toegestane sleutel toe aan doelen in Performance Hub: de hele faciliteit, een deur of een Toegangsbereik:
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
Partners sturen binnen een venster geen ID's van faciliteiten, deuren of Toegangsbereiken in Performance Hub mee. Een onbekende, uitgeschakelde of niet-toegewezen scope_key leidt voor dat venster tot weigering (fail-closed); de toegang wordt er niet ruimer door. Spreek toewijzingen af en test ze vóór de lancering.
Volledige momentopnamen en revisies
Behandel de twee velden als een afzonderlijk geversioneerde partitie binnen de upsert van een lid:
| Invoer | Resultaat |
|---|---|
access_time_windows weggelaten | Bestaande momentopname blijft ongewijzigd; er is geen revisie nodig |
| Aanwezig met een nieuwere revisie | De volledige opgeslagen momentopname voor dit lid/deze bron wordt vervangen |
| Dezelfde revisie en dezelfde genormaliseerde payload | Idempotente herhaling; de momentopname verandert niet |
| Dezelfde revisie en een andere genormaliseerde payload | Conflict; ken na reconciliatie een nieuwe revisie toe |
| Oudere revisie | Verouderde momentopname wordt overgeslagen; deze kan een nieuwere status niet overschrijven |
access_time_windows: [] met een nieuwere revisie | Trekt expliciet alle vensters van de bron in |
Een momentopname is volledig, geen patch. Als revisie 1842 de vensters A en B bevat, verwijdert revisie 1843 met alleen B het venster A.
Houd per partner/lid één gecoördineerde revisiereeks bij over webhookworkers, polling, herhaling en volledige reconciliatie heen. Een duurzame databasesequentie heeft de voorkeur. Een waarde in Unix-milliseconden kan alleen als revisie worden gebruikt wanneer alle schrijvers zich coördineren en een strikte volgorde en uniciteit garanderen; het is een revisiewaarde, geen epochveld.
Bewaar het exacte verzoek en de revisie totdat de API-response bekend is. Probeer na een time-out of tijdelijke fout dezelfde genormaliseerde momentopname opnieuw met dezelfde revisie. Ken geen nieuwe revisie toe alleen omdat de aflevering onzeker is.
Annulering, verloop en upstream fouten
- Eén venster annuleren: haal met succes de gezaghebbende status bij de bron op, verwijder dat venster en stuur de resterende volledige momentopname met een nieuwere revisie.
- Alle vensters annuleren: stuur
access_time_windows: []met een nieuwere revisie. - Een absoluut venster laten verlopen: het staat vanaf
togeen toegang meer toe; stuur later een reconciliatie zonder het verlopen item om momentopnamen schoon te houden. - Een wekelijks venster beëindigen: verwijder het in een nieuwere momentopname, of gebruik
active_untilwanneer de bron een bekend eindtijdstip heeft. - Ophalen bij de bron mislukt of is onvolledig: stuur geen
[]en publiceer geen gedeeltelijke momentopname. Geef een waarschuwing en probeer het ophalen opnieuw. Een upstream fout omzetten in een lege momentopname betekent een onbedoelde intrekking van toegang. - Verzoek aan de Partner API mislukt bij validatie: corrigeer de gegevens en stuur alleen een nieuwere revisie als de genormaliseerde momentopname verandert. Probeer tijdelijke fouten opnieuw met de oorspronkelijke revisie.
De actualiteit van de bron wordt per integratie geconfigureerd op basis van de toegezegde frequentie van aflevering en reconciliatie. Spreek vóór activering af wat de maximale leeftijd van de brongegevens is, wat er gebeurt als die wordt overschreden, wat de drempels voor waarschuwingen zijn en of beheerders mogen bevestigen dat alleen op de eigen grenzen van elk venster wordt vertrouwd. Een verouderd bronvenster wordt nooit een weigeringsregel; reguliere regels en permanente toegangsrechten blijven terugvalroutes.
Algoritme voor producenten
Gebruik dit taalonafhankelijke proces voor elke update van een lid:
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)
Certificeringschecklist
Voer deze controles uit in een testfaciliteit met de definitieve scope_key-toewijzing:
- Een absoluut venster zonder tijdzone wordt geaccepteerd en als UTC geëvalueerd.
- Een absoluut venster met een aangepaste IANA-tijdzone behoudt dezelfde
from/to-tijdstippen. - Een wekelijks venster met een aangepaste IANA-tijdzone volgt de lokale kloktijd bij de overgangen naar zomer- en wintertijd.
- Een gecombineerde absolute/wekelijkse momentopname vervangt de vorige momentopname volledig.
- Toegang begint precies op
fromen stopt precies opto; de einden van wekelijkse blokken zijn ook exclusief. - Het bijwerken van tijden onder dezelfde
external_idmet een nieuwere revisie wordt van kracht. - Het weglaten van
access_time_windowswijzigt andere velden van het lid zonder de vensters te wijzigen. - Het herhalen van dezelfde revisie/payload is idempotent.
- Dezelfde revisie met een andere payload geeft een conflict en wijzigt de momentopname niet.
- Een oudere revisie die in de verkeerde volgorde binnenkomt, wordt als verouderd gemeld en kan de status niet terugdraaien.
- Een nieuwere
[]trekt de vensters van de bron in; bij een mislukte upstream ophaalactie wordt niets verzonden. - Een onbekende of niet-toegewezen
scope_keyleidt tot weigering (fail-closed) en geeft een waarschuwing die beheerders kunnen zien. - Waarschuwingen over de leeftijd van brongegevens en het geconfigureerde beleid voor verouderde bronnen werken bij de afgesproken drempel.
- De webhookroute en de route voor volledige reconciliatie komen uit op dezelfde momentopname en revisievolgorde.
- Aflevering van de reeks bereikt Door & Gate Access binnen het afgesproken doel.
- Een actief venster kan toegang geven tot de toegewezen fysieke deur, maar kan het uitschakelen van gebruikers,
blockAllAccess, onderhoud of geofencing niet omzeilen. - Vóór, buiten en na een venster geven reguliere regels en permanente toegangsrechten nog steeds toegang aan gebruikers die daar anders recht op hebben.
Minimale testvectoren
[
{
"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."
}
]
Lever ook negatieve vectoren aan voor Unix-milliseconden, numerieke tekenreeksen, drijvendekommagetallen, ongeldige IANA-zones, from >= to, dubbele external_id, overlappende blokken, nachtelijke blokken, meer dan acht blokken op een dag, meer dan 50 vensters en niet-toegewezen scopesleutels.