Introduzione

La Partner API del Performance Hub consente alle piattaforme dei partner esterni di integrarsi senza difficoltà con i moduli principali del Performance Hub. L'API supporta computer vision, analisi, registrazione degli accessi dei membri e insight sulle strutture.

Formato delle richieste

L'API accetta corpi di richiesta codificati in JSON e restituisce risposte codificate in JSON.

Limitazione della frequenza

Per garantire un uso equo e la stabilità del sistema, gli account della Partner API partono con questi limiti predefiniti:

  • 5 richieste al secondo per endpoint
  • Consigliato: massimo 1000 elementi per richiesta batch, per prestazioni ottimali
  • Dimensione del payload di massimo 10MB

I limiti di frequenza sono modificabili e possono essere configurati caso per caso dal tuo account manager partner del Performance Hub. Se la tua integrazione ha bisogno di un throughput più elevato per il lancio, le migrazioni, i backfill di report o strutture con volumi elevati, segnalalo durante l'onboarding o prima della finestra di modifica prevista.

URL di base

https://partner-api.performancehub.co/partner/v1/

Autenticazione

L'accesso alla Partner API richiede l'autenticazione con chiavi segrete API. Genera e gestisci le tue chiavi tramite la Partner Console.

Le chiavi API sono le tue credenziali per accedere alle risorse dei partner. Ogni chiave ha un accesso limitato ai dati di organizzazioni specifiche e può essere disattivata all'istante quando necessario.

Gestisci con cura le tue chiavi API: danno accesso completo al tuo account! Non esporre mai queste chiavi in repository pubblici, applicazioni lato client o in qualsiasi altro luogo in cui potrebbero essere compromesse.

Autentica le richieste con HTTP Basic Auth, passando la tua chiave API come nome utente. Lascia vuota la password.

L'API accetta solo connessioni HTTPS sicure. Le richieste HTTP non cifrate vengono rifiutate, così come tutte le richieste prive di credenziali di autenticazione valide.

Esempio di richiesta

curl https://partner-api.performancehub.co/partner/v1/organisations \
  -u sk_live_YOUR_PARTNER_SECRET_KEY:
# The colon prevents curl from asking for a password.

Verificare la chiave segreta

curl https://partner-api.performancehub.co/partner/v1/auth/ping \
  -u sk_live_YOUR_PARTNER_SECRET_KEY:
# Returns { "message": "You are successfully authorised as <PartnerName>" }

Elenco di controllo per il go-live

Usa questo elenco di controllo prima di attivare un'integrazione partner per le strutture in produzione.

Configurazione della Partner Console

  • Il tuo profilo partner è completo.
  • URL del logo, sito web, categoria e descrizione sono corretti.
  • Il metodo di collegamento dei dati è configurato: Direct Link o Linking Identifier.
  • Il collegamento delle strutture è stato testato con almeno una struttura reale.
  • Viene usato il tipo di chiave corretto:
    • Dryrun per testare le scritture senza effetti distruttivi.
    • Read-only per un consumo sicuro dei dati.
    • Live solo quando sei pronto a modificare i dati di produzione.

Autenticazione e gestione delle chiavi

  • Le chiavi segrete sono conservate solo lato server.
  • Le chiavi non sono incorporate in applicazioni lato client, app mobili, repository pubblici o ticket di assistenza.
  • La rotazione e la revoca delle chiavi sono state testate.
  • Il tuo team sa quale chiave viene usata in ciascun ambiente.

Convalida dei dati

  • I campi obbligatori sono presenti per ogni endpoint che chiami.
  • Gli identificatori delle strutture corrispondono al metodo di collegamento configurato.
  • Gli ID del tuo sistema sono stabili e non cambiano tra una sincronizzazione e l'altra.
  • Le importazioni di grandi dimensioni sono suddivise in batch entro i limiti documentati.
  • Gli elementi dei batch non riusciti possono essere identificati e inviati di nuovo.

Test degli endpoint

Prima del lancio, testa ogni endpoint da cui dipende la tua integrazione:

  • Le organizzazioni e le strutture possono essere lette.
  • I membri possono essere salvati e aggiornati.
  • Piani di abbonamento, zone di accesso e orari di accesso si sincronizzano correttamente.
  • I check-in vengono accettati e possono essere ricondotti al tuo sistema.
  • Le istantanee dei report usano il periodo di riferimento e le metriche previsti.
  • I flussi dei Door/Gate Controller sono testati su hardware reale, ove applicabile.

Preparazione per le Access Time Windows

Se l'integrazione fornisce Access Time Windows:

  • Gli esempi assoluti e settimanali superano l'elenco di controllo per la certificazione dei produttori.
  • Gli epoch sono secondi Unix interi senza virgolette; i limiti esatti [from, to) sono stati testati.
  • Sono stati verificati i valori predefiniti UTC, i fusi orari IANA personalizzati dell'integrazione e i relativi passaggi all'ora legale.
  • Un unico flusso di revisioni per membro/fonte, persistente e monotono, coordina aggiornamenti incrementali, riconciliazione e nuovi tentativi.
  • Gli operatori comprendono il comportamento nei casi di campo omesso, sostituzione completa, idempotenza, conflitto, dati obsoleti e [] esplicito.
  • Ogni scope_key, compreso default, ha una mappatura approvata nel Performance Hub; è stato verificato che le chiavi sconosciute neghino l'accesso per impostazione predefinita.
  • La frequenza di aggiornamento prevista dall'integrazione, l'età massima dei dati di origine, il comportamento con dati di origine obsoleti e gli avvisi sono configurati.
  • È stato dimostrato che un errore di recupero a monte non genera un'istantanea vuota o parziale.
  • La convergenza del flusso in staging, l'annullamento/la revoca e i limiti di inizio e fine sulle porte fisiche rispettano gli obiettivi concordati.
  • Le regole ordinarie e le concessioni permanenti sono state verificate come percorsi di riserva, e le finestre non possono aggirare la disattivazione dell'utente, blockAllAccess, la manutenzione o il geofencing.

Preparazione per il controllo degli accessi

Per le integrazioni di controllo degli accessi:

  • Il tuo sistema prende la decisione sull'accesso prima di chiamare il Performance Hub.
  • L'integrazione gestisce device_offline, maintenance_mode_active e unlock_confirmation_timeout.
  • Gli operatori sanno che un timeout significa che lo sblocco non è stato confermato.
  • I tuoi log memorizzano l'event_id e il command_id restituiti.
  • Hai una procedura di riserva manuale per il personale della struttura.

Gestione degli errori e nuovi tentativi

  • Le risposte 400, 401, 403, 404, 409 e 422 vengono segnalate agli operatori o ai team di assistenza invece di essere ripetute alla cieca.
  • Le risposte 429, 500, 502, 503 e 504 usano una logica di nuovi tentativi limitata, con backoff.
  • Gli errori ripetuti generano un avviso nel tuo sistema.
  • L'integrazione non scarta mai in modo silenzioso i record non riusciti.

Osservabilità

  • I tuoi log includono endpoint, timestamp, identificatore della struttura, ID del record di origine, esito della richiesta e corpo della risposta.
  • Il tuo team di assistenza può cercare per ID del membro, ID della struttura, ID del check-in o ID dell'evento di sblocco.
  • Hai un modo per ripetere o riconciliare le sincronizzazioni non riuscite.

Lancio in produzione

  • Il Performance Hub ha confermato il tuo accesso alla produzione.
  • Almeno una struttura in produzione ha attivato la tua integrazione.
  • La tua chiave di produzione è attiva.
  • I tuoi referenti operativi e tecnici sono aggiornati.
  • La tua procedura di assistenza è documentata per i clienti.

Una volta completate queste verifiche, la tua integrazione configurata comparirà nella directory dei partner del Performance Hub, all'interno della piattaforma principale del Performance Hub.

Best practice

Segui questi schemi per mantenere le integrazioni partner prevedibili, osservabili e sicure per le strutture.

Identificare le strutture in modo coerente

Scegli il metodo di collegamento configurato per il tuo account partner e usalo in modo coerente:

  • Direct Link - usa il facility_id del Performance Hub restituito dall'endpoint delle strutture.
  • Linking Identifier - usa il tuo identificatore di sede, ad esempio un ID filiale, un codice di sede o un numero di negozio.

Non inviare entrambi gli identificatori nella stessa richiesta. Il Performance Hub risolve le richieste con il metodo di collegamento configurato per il tuo account partner.

Consulta Metodi di collegamento dei partner per le indicazioni sulla configurazione.

Scritture in batch con attenzione

La Partner API accetta corpi di richiesta JSON ed è progettata, dove documentato, per flussi di sincronizzazione basati su batch. Mantieni i batch di dimensioni limitate e ripetibili.

Indicazioni predefinite:

  • Usa fino a 1000 elementi per richiesta batch per prestazioni ottimali.
  • Mantieni i payload sotto i 10MB.
  • Resta entro 5 richieste al secondo per endpoint.

I limiti di frequenza sono modificabili e possono essere configurati caso per caso dal tuo account manager partner del Performance Hub. Se prevedi importazioni ad alto volume, traffico di lancio o backfill di report, concorda il throughput necessario prima della finestra di modifica.

Se devi sincronizzare un set di dati di grandi dimensioni, suddividilo in blocchi deterministici e registra l'ID di ogni blocco dal tuo lato. In questo modo è più facile analizzare i tentativi non riusciti.

Ripetere i tentativi in sicurezza

Usa un backoff esponenziale per gli errori temporanei, come 429, 500, 502, 503 e 504.

Evita cicli di tentativi ravvicinati. Un buon punto di partenza è:

  1. Riprova dopo 1 secondo.
  2. Riprova dopo 2 secondi.
  3. Riprova dopo 4 secondi.
  4. Interrompi e invia un avviso se l'operazione continua a non riuscire.

Per gli errori di convalida, come 400 o 422, correggi la richiesta prima di riprovare.

Usare l'idempotenza dove supportata

L'endpoint di sblocco del Door/Gate Controller supporta una idempotency_key facoltativa. Riutilizzando la stessa chiave per lo stesso partner, la stessa struttura e la stessa porta si ottiene il risultato esistente, se disponibile.

Usa una chiave stabile per l'azione eseguita, ad esempio un ID di check-in o un ID di evento di accesso del tuo sistema.

Non dare per scontato che ogni endpoint di scrittura supporti l'idempotenza, a meno che non sia documentato per quell'endpoint.

Mantenere puliti i dati di origine

Invia, ove possibile, valori stabili e normalizzati:

  • Usa ID coerenti per membri, piani, strutture e check-in provenienti dal tuo sistema di origine.
  • Usa timestamp ISO 8601 per date e orari.
  • Invia i numeri di telefono in formato internazionale, se disponibili.
  • Invia le valute usando i campi documentati per ciascun endpoint.
  • Evita di sovraccaricare i campi di testo libero con dati che appartengono a campi strutturati.

Progettare per sincronizzazioni incrementali e complete

La maggior parte delle integrazioni partner ha bisogno di entrambe:

  • Sincronizzazioni incrementali per le modifiche quotidiane.
  • Sincronizzazioni di riconciliazione complete per correggere eventi mancati, importazioni storiche o disallineamenti dei dati.

La tua integrazione deve essere in grado di inviare di nuovo lo stato attuale di un membro, di un piano di abbonamento o di un'istantanea di report senza dipendere dall'esito positivo di una richiesta precedente.

Pubblicare le Access Time Windows in sicurezza

Tratta il valore access_time_windows di ogni membro come un'istantanea completa con una revisione indipendente:

  • Coordina un unico flusso monotonicamente crescente di access_time_windows_revision tra i worker incrementali e quelli di riconciliazione.
  • Ripeti una consegna incerta o non riuscita temporaneamente con la stessa revisione e lo stesso payload normalizzato.
  • Ometti access_time_windows quando non lo aggiorni.
  • Invia [] solo dopo che un recupero riuscito dalla fonte autorevole dimostra che non restano finestre. Non trasformare mai un timeout a monte, un risultato parziale o un errore di parsing in una revoca.
  • Mantieni stabili external_id e scope_key e certifica ogni mappatura degli ambiti prima della produzione.
  • Monitora l'età dei dati di origine rispetto ai criteri di aggiornamento concordati per quell'integrazione.

Consulta la guida autorevole per i produttori di Access Time Windows per istantanee complete, fusi orari, ora legale, annullamento e vettori di test.

Considerare il controllo degli accessi un aspetto critico per la sicurezza

Per gli sblocchi dei Door/Gate Controller:

  • Il tuo sistema deve decidere se la persona può entrare prima di chiamare il Performance Hub.
  • Il Performance Hub restituisce 200 solo dopo che il controller in loco ha confermato che il relè si è fisicamente sbloccato.
  • La maggior parte delle conferme arriva entro 3-5 secondi.
  • Un timeout è uno sblocco esplicitamente non riuscito, non un successo in background.
  • Ripeti i tentativi solo secondo le tue regole di accesso e di sicurezza.

Registra sempre l'event_id e il command_id restituiti dall'endpoint di sblocco.

Monitorare la tua integrazione

Usa i log delle richieste della Partner Console durante lo sviluppo e il lancio. In produzione, mantieni anche log propri con:

  • Data e ora della richiesta.
  • Endpoint.
  • ID del record di origine.
  • Identificatore della struttura.
  • Codice di stato HTTP.
  • Corpo della risposta o messaggio di errore del Performance Hub.

Questi campi rendono l'assistenza e la riconciliazione molto più rapide quando un cliente chiede cosa è successo.

Organizzazioni

Rappresenta l'entità aziendale di primo livello che gestisce una o più strutture integrate con la piattaforma Performance Hub.

Endpoint

GET /partner/v1/organisations - List all organisations

L'oggetto Organizzazione

Attributi

  • org_id string obbligatorio

    Identificatore univoco dell'organizzazione.

  • name string obbligatorio

    Nome dell'organizzazione.

L'oggetto Organizzazione

{
  "org_id": "00000000-0000-0000-0000-000000000050",
  "name": "Harbourside Group"
}

Elencare tutte le organizzazioni

Restituisce l'elenco delle organizzazioni accessibili al tuo account partner.

Valore restituito

Restituisce un oggetto JSON con una proprietà data che contiene un array di oggetti Organizzazione.

Richiesta

curl https://partner-api.performancehub.co/partner/v1/organisations \
  -u sk_live_YOUR_PARTNER_SECRET_KEY:

Risposta

{
  "data": [
    {
      "org_id": "00000000-0000-0000-0000-000000000050",
      "name": "Harbourside Group"
    },
    {
      "org_id": "6ba7b811-9dad-11d1-80b4-00c04fd430c8",
      "name": "Wellness Studios Network"
    }
  ]
}

Strutture

Rappresenta una sede fisica, come un ufficio, un negozio, un locale, un campus, una clinica o una palestra, in cui i membri possono accedere ai servizi.

Endpoint

GET /partner/v1/facilities - List all facilities

L'oggetto Struttura

Attributi

  • facility_id string obbligatorio

    Identificatore univoco della struttura.

  • org_id string obbligatorio

    Identificatore univoco dell'organizzazione principale.

  • name string obbligatorio

    Nome della struttura.

  • brand string facoltativo

    Nome del brand usato dalla struttura.

  • website_url string facoltativo

    URL del sito web della struttura.

  • place_data object facoltativo

    Dati sulla posizione provenienti dalla Google Places API, con paese, indirizzo formattato, Google Place ID, provincia e città.

  • social_links object facoltativo

    Link ai social media della struttura.

  • timezone string facoltativo

    Identificatore del fuso orario IANA (ad esempio "Australia/Sydney", "America/New_York").

L'oggetto Struttura

{
  "facility_id": "550e8400-e29b-41d4-a716-446655440000",
  "org_id": "00000000-0000-0000-0000-000000000050",
  "name": "Harbourside Central",
  "brand": "Harbourside",
  "website_url": "https://example.com/central",
  "social_links": {
    "instagram": {
      "handle": "@harbourside.central"
    },
    "facebook": {
      "handle": "HarboursideCentral"
    }
  },
  "place_data": {
    "country": {
      "iso_code": "AU",
      "full_name": "Australia"
    },
    "formatted_address": "123 Main Street, Suite 100, Sydney NSW 2000, Australia",
    "google_place_id": "ChIJN1t_tDeuEmsRUsoyG83frY4",
    "province": {
      "abbreviation": "NSW",
      "full_name": "New South Wales"
    },
    "city": {
      "short_name": "Sydney",
      "full_name": "Sydney"
    }
  },
  "timezone": "Australia/Sydney"
}

Elencare tutte le strutture

Restituisce l'elenco delle strutture accessibili al tuo account partner.

Valore restituito

Restituisce un oggetto JSON con una proprietà data che contiene un array di oggetti Struttura.

Richiesta

curl https://partner-api.performancehub.co/partner/v1/facilities \
  -u sk_live_YOUR_PARTNER_SECRET_KEY:

Risposta

{
  "data": [
    {
      "facility_id": "550e8400-e29b-41d4-a716-446655440000",
      "org_id": "00000000-0000-0000-0000-000000000050",
      "name": "Harbourside Central",
      "brand": "Harbourside",
      "website_url": "https://example.com/central",
      "place_data": {
        "country": {
          "iso_code": "AU",
          "full_name": "Australia"
        },
        "formatted_address": "123 Main Street, Sydney NSW 2000, Australia",
        "google_place_id": "ChIJN1t_tDeuEmsRUsoyG83frY4",
        "province": {
          "abbreviation": "NSW",
          "full_name": "New South Wales"
        },
        "city": {
          "short_name": "Sydney",
          "full_name": "Sydney"
        }
      },
      "timezone": "Australia/Sydney"
    }
  ]
}

Piani di abbonamento

Definisce un'offerta acquistabile da un'organizzazione o da una struttura, con servizi, diritti, programmazione e prezzi.

Endpoint

POST /partner/v1/membership-plans - Save a membership plan

L'oggetto Membership Plan

Attributi

  • membership_plan_id string obbligatorio

    Identificatore univoco del piano di abbonamento.

  • facility_id string in alternativaIndica il tipo di identificatore della struttura configurato per la tua integrazione: usa facility_id per le integrazioni con collegamento diretto oppure linking_identifier per le integrazioni con identificatore di collegamento. Non inviarli entrambi: l'API usa il tipo di identificatore configurato per il tuo account partner e ignora l'altro. Scopri di più

    Identificatore univoco della struttura nel Performance Hub.

  • linking_identifier string in alternativaIndica il tipo di identificatore della struttura configurato per la tua integrazione: usa facility_id per le integrazioni con collegamento diretto oppure linking_identifier per le integrazioni con identificatore di collegamento. Non inviarli entrambi: l'API usa il tipo di identificatore configurato per il tuo account partner e ignora l'altro. Scopri di più

    Valore dell'identificatore univoco che il partner usa per ogni sede (ad esempio "Branch ID", "Location Code", "Store Number"). Scopri di più

  • name string obbligatorio

    Nome leggibile del piano (ad esempio "Office tenant – business hours", "Student – term access", "Hotel guest", "10 Class Pack").

  • billing_cycle string facoltativo

    Frequenza di fatturazione. Uno tra weekly, fortnightly, monthly, annually e one_time.

  • price integer facoltativo

    Costo base nella più piccola unità della valuta (centesimi per USD/AUD).

  • currency string facoltativo

    Codice valuta ISO 4217 (ad esempio "AUD", "USD").

  • description string facoltativo

    Descrizione facoltativa, di marketing o interna.

  • active_members integer facoltativo

    Numero di membri attivi che usano questo piano di abbonamento

  • is_recurring boolean facoltativo

    Indica se il piano si rinnova automaticamente.

  • is_trial boolean facoltativo

    Indica se si tratta di un'offerta di prova.

  • visible_to_public boolean facoltativo

    Indica se il piano è disponibile per l'acquisto in autonomia.

  • duration_days integer facoltativo

    Numero di giorni di validità del piano di abbonamento.

  • access_zones array facoltativo

    Array delle zone di accesso incluse nel piano di abbonamento. Ogni zona può definire orari di accesso propri. Consulta Zone di accesso per i dettagli.

  • class_limit integer facoltativo

    Numero massimo di lezioni consentite (null per un numero illimitato).

L'oggetto Membership Plan

Questo esempio usa facility_id. Per un'integrazione con identificatore di collegamento, invia invece "linking_identifier": "branch_downtown".

{
  "membership_plan_id": "plan_99999",
  "facility_id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "Office tenant – business hours",
  "description": "Weekday access to the level 3 tenancy and the end-of-trip facilities",
  "billing_cycle": "monthly",
  "price": 8900,
  "currency": "AUD",
  "duration_days": 30,
  "is_recurring": true,
  "is_trial": false,
  "visible_to_public": false,
  "active_members": 245,
  "access_zones": [
    {
      "name": "Level 3 Tenancy",
      "description": "Lift lobby, offices and meeting rooms on level 3",
      "access_hours": {
        "mon": [["07:00", "19:00"]],
        "tue": [["07:00", "19:00"]],
        "wed": [["07:00", "19:00"]],
        "thu": [["07:00", "19:00"]],
        "fri": [["07:00", "19:00"]]
      }
    },
    {
      "name": "End-of-trip Facilities",
      "description": "Bike storage, lockers and showers",
      "access_hours": {
        "mon": [["06:00", "20:00"]],
        "tue": [["06:00", "20:00"]],
        "wed": [["06:00", "20:00"]],
        "thu": [["06:00", "20:00"]],
        "fri": [["06:00", "20:00"]]
      }
    }
  ],
  "class_limit": null
}

Zone di accesso

Le zone di accesso definiscono le aree specifiche di una struttura a cui un piano di abbonamento dà accesso. Ogni zona può avere orari di accesso propri, così da consentire limitazioni orarie diverse per area.

Struttura dei dati

Ogni zona di accesso include:

  • name string obbligatorio

    Il nome della zona (ad esempio "Level 3 Tenancy", "Library", "Guest Floors", "Main Gym Floor").

  • description string facoltativo

    Descrizione di ciò che è incluso nella zona.

  • access_hours object facoltativo

    Orari di accesso specifici di questa zona. Consulta Orari di accesso per il formato degli intervalli di tempo.

Esempio

Un edificio per uffici con una palestra per i propri inquilini: accesso agli spazi in affitto durante l'orario lavorativo e alla palestra dalla mattina presto alla sera tardi.

{
  "access_zones": [
    {
      "name": "Level 3 Tenancy",
      "description": "Lift lobby, offices and meeting rooms on level 3",
      "access_hours": {
        "mon": [["07:00", "19:00"]],
        "tue": [["07:00", "19:00"]],
        "wed": [["07:00", "19:00"]],
        "thu": [["07:00", "19:00"]],
        "fri": [["07:00", "19:00"]]
      }
    },
    {
      "name": "Tenant Gym",
      "description": "Ground-floor gym and change rooms for building tenants",
      "access_hours": {
        "mon": [["05:00", "22:00"]],
        "tue": [["05:00", "22:00"]],
        "wed": [["05:00", "22:00"]],
        "thu": [["05:00", "22:00"]],
        "fri": [["05:00", "22:00"]],
        "sat": [["07:00", "18:00"]],
        "sun": [["07:00", "18:00"]]
      }
    }
  ]
}

Orari di accesso

Gli orari di accesso indicano quando i membri possono accedere a una zona specifica in ciascun giorno della settimana. Gli orari di accesso sono definiti per ogni zona di accesso, così da consentire limitazioni orarie diverse per le diverse aree di una struttura.

Struttura dei dati

{
  "mon": [["start_time", "end_time"]],
  "tue": [["start_time", "end_time"]],
  "wed": [["start_time", "end_time"]],
  "thu": [["start_time", "end_time"]],
  "fri": [["start_time", "end_time"]],
  "sat": [["start_time", "end_time"]],
  "sun": [["start_time", "end_time"]]
}

Ogni giorno è un array di intervalli di tempo nel formato HH:MM (orologio a 24 ore). Un array vuoto [] significa nessun accesso in quel giorno. I giorni omessi vengono trattati come un array vuoto.

Esempi di casi d'uso

Inquilino di un ufficio – orario lavorativo: accesso durante l'orario lavorativo, solo nei giorni feriali.

{
  "access_hours": {
    "mon": [["07:00", "19:00"]],
    "tue": [["07:00", "19:00"]],
    "wed": [["07:00", "19:00"]],
    "thu": [["07:00", "19:00"]],
    "fri": [["07:00", "19:00"]]
  }
}

Studente – accesso durante il periodo di lezione: una biblioteca universitaria aperta nei giorni feriali, con una pausa a metà giornata, e il sabato mattina.

{
  "access_hours": {
    "mon": [["08:00", "12:30"], ["13:30", "21:00"]],
    "tue": [["08:00", "12:30"], ["13:30", "21:00"]],
    "wed": [["08:00", "12:30"], ["13:30", "21:00"]],
    "thu": [["08:00", "12:30"], ["13:30", "21:00"]],
    "fri": [["08:00", "12:30"], ["13:30", "17:00"]],
    "sat": [["09:00", "13:00"]]
  }
}

Palestra – mattinieri: accesso solo al mattino nei giorni feriali.

{
  "access_hours": {
    "mon": [["04:00", "12:00"]],
    "tue": [["04:00", "12:00"]],
    "wed": [["04:00", "12:00"]],
    "thu": [["04:00", "12:00"]],
    "fri": [["04:00", "12:00"]]
  }
}

Ospite di un hotel – 24/7: accesso sempre attivo, il caso d'uso più comune.

{
  "access_hours": {
    "mon": [["00:00", "23:59"]],
    "tue": [["00:00", "23:59"]],
    "wed": [["00:00", "23:59"]],
    "thu": [["00:00", "23:59"]],
    "fri": [["00:00", "23:59"]],
    "sat": [["00:00", "23:59"]],
    "sun": [["00:00", "23:59"]]
  }
}

Esempio per zona

Un piano per gli ospiti di un hotel con accesso 24 ore su 24 ai piani delle camere e orari più ridotti per la piscina:

{
  "access_zones": [
    {
      "name": "Guest Floors",
      "description": "Lifts and corridors on the guest room levels",
      "access_hours": {
        "mon": [["00:00", "23:59"]],
        "tue": [["00:00", "23:59"]],
        "wed": [["00:00", "23:59"]],
        "thu": [["00:00", "23:59"]],
        "fri": [["00:00", "23:59"]],
        "sat": [["00:00", "23:59"]],
        "sun": [["00:00", "23:59"]]
      }
    },
    {
      "name": "Swimming Pool",
      "description": "Access to the swimming pool and change rooms",
      "access_hours": {
        "mon": [["06:00", "20:00"]],
        "tue": [["06:00", "20:00"]],
        "wed": [["06:00", "20:00"]],
        "thu": [["06:00", "20:00"]],
        "fri": [["06:00", "20:00"]],
        "sat": [["08:00", "18:00"]],
        "sun": [["08:00", "18:00"]]
      }
    }
  ]
}

Salvare un piano di abbonamento

Crea o aggiorna i record dei piani di abbonamento. L'API stabilisce se creare o aggiornare in base al membership_plan_id.

Parametri

  • membership_plans array obbligatorio

    Array di oggetti Membership Plan da salvare. Massimo consigliato: 1000 elementi per richiesta, per prestazioni ottimali. L'API suddivide automaticamente gli elementi in batch per l'elaborazione. Ogni elemento deve includere facility_id (obbligatorio se non usi linking_identifier) oppure linking_identifier (obbligatorio se non usi facility_id).

Valore restituito

Restituisce un semplice messaggio di conferma dell'operazione di sincronizzazione.

Richiesta

Questo esempio usa facility_id. Per un'integrazione con identificatore di collegamento, invia invece "linking_identifier": "branch_downtown".

curl -X POST https://partner-api.performancehub.co/partner/v1/membership-plans \
  -u sk_live_YOUR_PARTNER_SECRET_KEY: \
  -H "Content-Type: application/json" \
  -d '{
    "membership_plans": [
      {
        "membership_plan_id": "plan_99999",
        "facility_id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "Student – term access",
        "description": "Library and student hub access for one teaching term",
        "billing_cycle": "one_time",
        "price": 4500,
        "currency": "AUD",
        "duration_days": 84,
        "is_recurring": false,
        "is_trial": false,
        "visible_to_public": true,
        "active_members": 245,
        "access_zones": [
          {
            "name": "Library",
            "description": "Reading rooms, study spaces and bookable rooms",
            "access_hours": {
              "mon": [["08:00", "21:00"]],
              "tue": [["08:00", "21:00"]],
              "wed": [["08:00", "21:00"]],
              "thu": [["08:00", "21:00"]],
              "fri": [["08:00", "17:00"]],
              "sat": [["09:00", "13:00"]]
            }
          },
          {
            "name": "Student Hub",
            "description": "Common room, kitchen and lockers",
            "access_hours": {
              "mon": [["07:00", "22:00"]],
              "tue": [["07:00", "22:00"]],
              "wed": [["07:00", "22:00"]],
              "thu": [["07:00", "22:00"]],
              "fri": [["07:00", "22:00"]]
            }
          }
        ],
        "class_limit": null
      }
    ]
  }'

Risposta

Restituisce un messaggio di esito positivo con i metadati dell'operazione di sincronizzazione.

{
  "message": "Membership plan sync successful.",
  "metadata": {
    "success": 98,
    "skipped": 2,
    "skipped_items": [
      {
        "membership_plan_id": "plan_456",
        "facility_id": null,
        "reason": "Missing facility_id"
      }
    ]
  }
}

Campi dei metadati:

  • success - Numero di piani di abbonamento elaborati correttamente
  • skipped - Numero di piani saltati (se presenti)
  • skipped_items - Array dei piani saltati con i relativi motivi (se presenti)
  • dry-run - Flag booleano presente se usi il tipo di chiave dryrun (se applicabile)

Membri

Rappresenta un singolo cliente di una struttura. Può essere un lead, un potenziale cliente, un cliente ricorrente, un membro scaduto o un utente bloccato.

Gli upsert dei membri possono includere anche un'istantanea access_time_windows completa e con revisione, che contiene accessi assoluti e settimanali ricorrenti. Consulta Access Time Windows prima di produrre questi campi. Si tratta di autorizzazioni aggiuntive, che non sostituiscono le regole ordinarie o le concessioni permanenti della struttura.

Endpoint

POST /partner/v1/members - Save a member

L'oggetto Member

Attributi

  • member_id string obbligatorio

    Identificatore univoco del membro.

  • facility_id string in alternativaIndica il tipo di identificatore della struttura configurato per la tua integrazione: usa facility_id per le integrazioni con collegamento diretto oppure linking_identifier per le integrazioni con identificatore di collegamento. Non inviarli entrambi: l'API usa il tipo di identificatore configurato per il tuo account partner e ignora l'altro. Scopri di più

    Identificatore univoco della struttura nel Performance Hub.

  • linking_identifier string in alternativaIndica il tipo di identificatore della struttura configurato per la tua integrazione: usa facility_id per le integrazioni con collegamento diretto oppure linking_identifier per le integrazioni con identificatore di collegamento. Non inviarli entrambi: l'API usa il tipo di identificatore configurato per il tuo account partner e ignora l'altro. Scopri di più

    Valore dell'identificatore univoco che il partner usa per ogni sede (ad esempio "Branch ID", "Location Code", "Store Number"). Scopri di più

  • first_name string obbligatorio

    Nome del membro.

  • last_name string obbligatorio

    Cognome del membro.

  • email string facoltativo

    Indirizzo email.

  • mobile_phone string facoltativo

    Numero di cellulare in formato E.123 (ad esempio "+1 415 555 2671").

  • address object facoltativo

    Oggetto indirizzo fisico con le seguenti proprietà:

    • address_line_1 (string) - Indirizzo principale (via e numero civico)
    • address_line_2 (string, optional) - Riga aggiuntiva dell'indirizzo
    • city (string) - Nome della città
    • state (string) - Codice dello stato/della provincia
    • postal_code (string) - Codice postale/CAP
    • country (string) - Codice paese ISO 3166-1 alpha-2 (ad esempio "AU", "US")
    • country_name (string, optional) - Nome completo del paese
  • date_of_birth string facoltativo

    Data di nascita nel formato YYYY-MM-DD.

  • gender string facoltativo

    Uno tra male, female, non_binary, prefer_not_to_say e unknown.

  • type string facoltativo

    Tipo di membro (ad esempio staff, member, prospect).

  • tags array facoltativo

    Brevi stringhe o testi di supporto per classificare e identificare membri specifici (ad esempio ["vip", "personal-training", "student"]).

  • membership_status string facoltativo

    Stato attuale dell'abbonamento (ad esempio active, expired, on_hold).

  • membership_plans array facoltativo

    Array dei piani di abbonamento associati al membro.

  • profile_picture string facoltativo

    Immagine del profilo codificata in Base64 (facoltativa).

  • created string facoltativo

    Timestamp ISO 8601 della creazione del membro.

  • updated string facoltativo

    Timestamp ISO 8601 dell'ultimo aggiornamento del membro.

  • access_time_windows array facoltativo

    Istantanea completa, di proprietà della fonte, delle Access Time Windows assolute e/o settimanali ricorrenti. Ometti il campo per lasciare invariata l'istantanea; invia un array vuoto con una revisione più recente per revocarla. Consulta Access Time Windows per le forme, la convalida, la mappatura degli ambiti e la semantica di sostituzione.

  • access_time_windows_revision integer obbligatorio con access_time_windows

    Intero non negativo, sicuro per JSON e monotonicamente crescente per questo flusso membro/fonte. Obbligatorio ogni volta che è presente access_time_windows.

L'oggetto Member

{
  "member_id": "member_11111",
  "facility_id": "550e8400-e29b-41d4-a716-446655440000",
  // "linking_identifier": "branch_downtown",  // If using linking identifier
  "first_name": "John",
  "last_name": "Smith",
  "email": "john.smith@example.com",
  "mobile_phone": "+61 412 345 678",
  "date_of_birth": "1985-06-15",
  "gender": "male",
  "type": "member",
  "tags": ["vip", "personal-training"],
  "profile_picture": "/9j/4AAQSkZJRgABAQAAAQ...",
  "membership_status": "current",
  "created": "2024-01-15T10:30:00Z",
  "updated": "2024-01-20T14:45:00Z",
  "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"
    }
  ],
  "address": {
    "address_line_1": "456 Bourke Street",
    "address_line_2": "Apt 12",
    "city": "Melbourne",
    "state": "VIC",
    "postal_code": "3000",
    "country": "AU",
    "country_name": "Australia"
  },
  "membership_plans": [
    {
      "membership_plan_id": "plan_99999",
      "name": "Unlimited Monthly",
      "start_date": "2024-01-01T00:00:00Z",
      "status": "current",
      "is_current": true,
      "end_date": null
    }
  ]
}

Finestre temporali di accesso

Le Access Time Windows consentono a un Partner Member di avere un accesso temporaneo o ricorrente fornito da un sistema esterno. Questa pagina è la guida autorevole per i produttori di access_time_windows e access_time_windows_revision.

Le Access Time Windows sono autorizzazioni aggiuntive che possono solo consentire l'accesso. Una finestra attiva può consentire l'accesso, ma una finestra inattiva, scaduta, obsoleta o non mappata non nega un accesso già consentito da una regola ordinaria o da una concessione permanente. Restano comunque validi la disattivazione dell'utente, il blocco esplicito delle porte, la modalità di manutenzione, il geofencing, i limiti di frequenza e la disponibilità del controller.

Le implementazioni per specifici sistemi a monte sono adattatori separati. Devono convertire i propri dati di origine in questo contratto indipendente dal fornitore, senza modificare il significato dei campi.

Campi dell'istantanea del membro

  • access_time_windows array facoltativo

    L'istantanea completa delle Access Time Windows per questo membro e questa fonte partner. Un'istantanea può combinare finestre absolute e weekly. Ometti il campo per lasciare invariata l'istantanea salvata; invia [] per revocare tutte le finestre di proprietà di questa fonte.

  • access_time_windows_revision integer obbligatorio con access_time_windows

    Un intero non negativo, sicuro per JSON e monotonicamente crescente per questo flusso di revisioni membro/fonte. È obbligatorio ogni volta che è presente access_time_windows e non deve superare 9007199254740991.

Ogni istantanea accetta al massimo 50 finestre. external_id, scope_key e label accettano al massimo 120 caratteri. Le finestre assolute possono coprire al massimo 90 giorni. Un giorno settimanale accetta al massimo otto blocchi non sovrapposti. I dati non validi vengono rifiutati, anziché troncati o interpretati per ipotesi.

Forme delle finestre

Una finestra assoluta identifica un unico intervallo esatto:

Richiesta mista completa

Questa richiesta sostituisce la precedente istantanea di proprietà della fonte per il membro con una finestra assoluta e una settimanale:

Regole su orari e limiti

from, to, active_from e active_until sono secondi Unix espressi come interi JSON che identificano istanti UTC:

  • Invia un intero JSON senza virgolette. Stringhe numeriche, numeri in virgola mobile, stringhe RFC 3339 e millisecondi Unix vengono rifiutati.
  • Ogni intervallo è semiaperto: [from, to). L'accesso può iniziare esattamente a from e non è più attivo esattamente a to.
  • from deve essere minore di to. Quando sono presenti entrambi i limiti settimanali, active_from deve essere minore di active_until.
  • Non ricavare gli epoch da una data/ora locale senza fuso orario. Prima converti l'orario di origine in un istante UTC, poi dividi i millisecondi Unix per 1000 e verifica che il risultato sia un intero.

Fusi orari e ora legale

timezone deve essere un fuso orario IANA valido, come UTC, Australia/Perth o America/New_York. Se omesso, il valore predefinito è UTC.

  • Finestre assolute: from e to identificano già istanti UTC esatti. timezone è solo un metadato di visualizzazione e audit; modificarlo non sposta mai nessuno dei due istanti.
  • Finestre settimanali: timezone definisce l'ora locale e le regole dell'ora legale usate per valutare access_hours. Non convertire in anticipo i blocchi settimanali in UTC.
  • Durante il passaggio all'ora legale, un'ora locale saltata dal fuso orario non si verifica mai.
  • Durante il ritorno all'ora solare, entrambi gli istanti reali che corrispondono all'ora locale ripetuta rientrano nel blocco settimanale.
  • active_from e active_until restano istanti UTC anche quando una finestra settimanale usa un fuso orario diverso da UTC.

access_hours usa le chiavi minuscole da sun a sat. Ogni valore è un array di coppie [start, end] nel formato HH:mm a 24 ore con zeri iniziali. I blocchi devono essere non vuoti, ordinati e non sovrapposti. end è escluso. Un blocco non può attraversare la mezzanotte: suddividi un intervallo notturno di origine in un blocco serale il primo giorno e un blocco mattutino il giorno successivo.

ID stabili e mappatura degli ambiti

external_id deve restare stabile per tutta la durata di una finestra logica ed essere univoco all'interno dell'istantanea del membro. Mantienilo stabile quando cambiano orari o etichette, in modo che operatori e record di audit possano correlare le revisioni. Non riutilizzarlo per una finestra non correlata.

scope_key è la tua destinazione di accesso logica stabile. Il valore predefinito è default. Un amministratore della struttura mappa ogni chiave consentita a destinazioni del Performance Hub valide per l'intera struttura, per una porta o per un Ambito di accesso:

Istantanee complete e revisioni

Tratta i due campi come una partizione con versioni separate all'interno dell'upsert del Member:

Input Risultato
access_time_windows omesso L'istantanea esistente resta invariata; non è richiesta alcuna revisione
Presente con una revisione più recente L'intera istantanea salvata per questo membro/fonte viene sostituita
Stessa revisione e stesso payload normalizzato Ripetizione idempotente; l'istantanea non cambia
Stessa revisione e payload normalizzato diverso Conflitto; assegna una nuova revisione dopo la riconciliazione
Revisione più vecchia L'istantanea obsoleta viene saltata; non può sovrascrivere uno stato più recente
access_time_windows: [] con una revisione più recente Revoca esplicitamente tutte le finestre di proprietà della fonte

Un'istantanea è completa, non una modifica parziale. Se la revisione 1842 contiene le finestre A e B, la revisione 1843 che contiene solo B rimuove A.

Mantieni un unico flusso di revisioni coordinato per partner/membro tra worker dei webhook, polling, ripetizioni e riconciliazione completa. È preferibile una sequenza persistente in un database. Un valore in millisecondi Unix può essere usato come revisione solo se tutti i writer si coordinano e garantiscono ordinamento e univocità rigorosi; si tratta di un valore di revisione, non di un campo epoch.

Conserva la richiesta e la revisione esatte finché non conosci la risposta dell'API. Dopo un timeout o un errore temporaneo, riprova con la stessa istantanea normalizzata e la stessa revisione. Non assegnare una nuova revisione solo perché la consegna è incerta.

Annullamento, scadenza ed errori a monte

  • Annullare una finestra: recupera correttamente lo stato autorevole dalla fonte, rimuovi quella finestra e invia l'istantanea completa rimanente con una revisione più recente.
  • Annullare tutte le finestre: invia access_time_windows: [] con una revisione più recente.
  • Lasciare scadere una finestra assoluta: smette di consentire l'accesso a to; invia una riconciliazione successiva senza la voce scaduta per mantenere pulite le istantanee.
  • Terminare una finestra settimanale: rimuovila in un'istantanea più recente oppure usa active_until quando la fonte ha un istante di fine noto.
  • Il recupero dalla fonte non riesce o è incompleto: non inviare [] e non pubblicare un'istantanea parziale. Invia un avviso e riprova il recupero. Trasformare un errore a monte in un'istantanea vuota significa revocare l'accesso involontariamente.
  • La richiesta alla Partner API non supera la convalida: correggi i dati e invia una revisione più recente solo se l'istantanea normalizzata cambia. Riprova gli errori temporanei con la revisione originale.

L'aggiornamento dei dati di origine si configura per ogni integrazione in base alla frequenza di consegna e di riconciliazione promessa. Prima dell'attivazione, concorda l'età massima dei dati di origine, cosa succede quando viene superata, le soglie di avviso e se gli operatori possono accettare di affidarsi solo ai limiti di ciascuna finestra. Una finestra con dati di origine obsoleti non diventa mai una regola di negazione; le regole ordinarie e le concessioni permanenti restano percorsi di riserva.

Algoritmo del produttore

Usa questo flusso indipendente dal linguaggio per ogni aggiornamento di un membro:

Elenco di controllo per la certificazione

Completa queste verifiche in una struttura di staging usando la mappatura scope_key definitiva:

  • Una finestra assoluta viene accettata con il fuso orario omesso e viene valutata in UTC.
  • Una finestra assoluta con fuso orario IANA personalizzato mantiene gli stessi istanti from/to.
  • Una finestra settimanale con fuso orario IANA personalizzato segue l'ora locale durante il passaggio all'ora legale e il ritorno all'ora solare.
  • Un'istantanea mista assoluta/settimanale sostituisce completamente l'istantanea precedente.
  • L'accesso inizia esattamente a from e termina esattamente a to; anche le fini dei blocchi settimanali sono escluse.
  • L'aggiornamento degli orari con lo stesso external_id e una revisione più recente ha effetto.
  • L'omissione di access_time_windows modifica gli altri campi del Member senza modificare le finestre.
  • La ripetizione della stessa revisione/dello stesso payload è idempotente.
  • La stessa revisione con un payload diverso restituisce un conflitto e non modifica l'istantanea.
  • Una revisione più vecchia arrivata fuori ordine viene segnalata come obsoleta e non può riportare indietro lo stato.
  • Un [] più recente revoca le finestre di proprietà della fonte; un errore di recupero a monte non invia nulla.
  • Uno scope_key sconosciuto o non mappato nega l'accesso e genera un avviso visibile agli operatori.
  • Gli avvisi sull'età dei dati di origine e i criteri configurati per i dati obsoleti funzionano alla soglia concordata.
  • I percorsi del webhook e della riconciliazione completa convergono sulla stessa istantanea e sullo stesso ordine delle revisioni.
  • La consegna del flusso raggiunge Door & Gate Access entro l'obiettivo concordato.
  • Una finestra attiva può consentire l'accesso alla porta fisica mappata, ma non può aggirare la disattivazione dell'utente, blockAllAccess, la manutenzione o il geofencing.
  • Prima, al di fuori e dopo una finestra, le regole ordinarie e le concessioni permanenti continuano a consentire l'accesso agli utenti che ne hanno comunque diritto.

Indicazioni correlate

{
  "external_id": "access-4b1782",
  "kind": "absolute",
  "from": 1792053000,
  "to": 1792058400,
  "timezone": "Australia/Perth",
  "scope_key": "after_hours_entry",
  "label": "Temporary site access"
}

I campi obbligatori sono external_id, kind, from e to. timezone, scope_key e label sono facoltativi.

Una finestra settimanale identifica intervalli ricorrenti in ora locale, eventualmente delimitati da istanti 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"
}

I campi obbligatori sono external_id, kind e access_hours. timezone, active_from, active_until, scope_key e label sono facoltativi.

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"
          }
        ]
      }
    ]
  }'

Usa facility_id oppure linking_identifier in base al metodo di collegamento configurato. Non inviarli entrambi.

Conversione in epoch

2026-10-15T08:30:00Z diventa 1792053000:

UTC instant                 Unix milliseconds   Unix seconds sent
2026-10-15T08:30:00Z        1792053000000        1792053000

Conversione indipendente dal linguaggio:

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

Se la fonte ha una precisione inferiore al secondo, definisci una regola di arrotondamento intenzionale per inizio e fine prima dei test di integrazione. Non passare mai millisecondi affidandoti all'API per dedurre l'unità.

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

I partner non inviano ID di strutture, porte o Ambiti di accesso del Performance Hub all'interno di una finestra. Uno scope_key sconosciuto, disattivato o non mappato nega l'accesso per quella finestra; non amplia l'accesso. Concorda e testa le mappature prima del lancio.

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)

Vettori di test minimi

[
  {
    "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."
  }
]

Invia anche vettori negativi per millisecondi Unix, stringhe numeriche, numeri in virgola mobile, fusi IANA non validi, from >= to, external_id duplicati, blocchi sovrapposti, blocchi notturni, più di otto blocchi in un giorno, più di 50 finestre e chiavi di ambito non mappate.

Salvare un membro

Crea o aggiorna i record dei membri. L'API stabilisce se creare o aggiornare in base al member_id.

Parametri

  • members array obbligatorio

    Array di oggetti Member da salvare. Massimo consigliato: 1000 elementi per richiesta, per prestazioni ottimali. L'API suddivide automaticamente gli elementi in batch per l'elaborazione. Ogni elemento deve includere facility_id (obbligatorio se non usi linking_identifier) oppure linking_identifier (obbligatorio se non usi facility_id).

    Quando un membro include access_time_windows, deve includere anche access_time_windows_revision. L'array è un'istantanea completa della fonte, non una modifica parziale. Omettilo per mantenere l'istantanea esistente oppure invia [] con una revisione più recente per revocare tutte le finestre di proprietà della fonte. Leggi la guida alle Access Time Windows prima di attivare questo campo.

Valore restituito

Restituisce un semplice messaggio di conferma dell'operazione di sincronizzazione.

I campi del profilo del membro restano normali upsert anche quando un'istantanea delle finestre viene segnalata come ripetizione idempotente o come obsoleta e saltata. Un'istantanea in conflitto, con la stessa revisione e un payload diverso, non può essere ripetuta senza modifiche: riconcilia lo stato della fonte e invia una revisione più recente.

Richiesta

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",
        // "linking_identifier": "branch_downtown",  // If using linking identifier
        "first_name": "John",
        "last_name": "Smith",
        "email": "john.smith@example.com",
        "mobile_phone": "+61 412 345 678",
        "date_of_birth": "1985-06-15",
        "gender": "male",
        "type": "member",
        "tags": ["vip", "personal-training"],
        "profile_picture": "/9j/4AAQSkZJRgABAQAAAQ...",
        "membership_status": "current",
        "created": "2024-01-15T10:30:00Z",
        "updated": "2024-01-20T14:45:00Z",
        "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"
          }
        ],
        "address": {
          "address_line_1": "456 Bourke Street",
          "address_line_2": "Apt 12",
          "city": "Melbourne",
          "state": "VIC",
          "postal_code": "3000",
          "country": "AU",
          "country_name": "Australia"
        },
        "membership_plans": [
          {
            "membership_plan_id": "plan_99999",
            "name": "Unlimited Monthly",
            "start_date": "2024-01-01T00:00:00Z",
            "status": "current",
            "is_current": true,
            "end_date": null
          }
        ]
      }
    ]
  }'

Risposta

Restituisce un messaggio di esito positivo con i metadati dell'operazione di sincronizzazione.

{
  "message": "Member sync successful.",
  "metadata": {
    "success": 245,
    "skipped": 5,
    "skipped_items": [
      {
        "member_id": "member_123",
        "facility_id": null,
        "reason": "Facility integration is disabled in facility-partner-config"
      }
    ]
  }
}

Campi dei metadati:

  • success - Numero di membri elaborati correttamente
  • skipped - Numero di membri saltati (se presenti)
  • skipped_items - Array dei membri saltati con i relativi motivi (se presenti)
  • dry-run - Flag booleano presente se usi il tipo di chiave dryrun (se applicabile)

Check-in

Rappresenta la registrazione della presenza di una persona in una struttura, a una lezione o a un'attività. Viene usato per monitorare le presenze, per le analisi di utilizzo e per migliorare l'accuratezza del rilevamento visivo.

Endpoint

POST /partner/v1/check-ins - Save check-ins

L'oggetto Check-In

Attributi

  • check_in_id string facoltativo

    Identificatore univoco del check-in. Facoltativo: se non viene fornito, viene generato automaticamente dalla coppia member_id e timestamp.

  • member_id string obbligatorio

    Identificatore univoco del membro.

  • facility_id string in alternativaIndica il tipo di identificatore della struttura configurato per la tua integrazione: usa facility_id per le integrazioni con collegamento diretto oppure linking_identifier per le integrazioni con identificatore di collegamento. Non inviarli entrambi: l'API usa il tipo di identificatore configurato per il tuo account partner e ignora l'altro. Scopri di più

    Identificatore univoco della struttura nel Performance Hub.

  • linking_identifier string in alternativaIndica il tipo di identificatore della struttura configurato per la tua integrazione: usa facility_id per le integrazioni con collegamento diretto oppure linking_identifier per le integrazioni con identificatore di collegamento. Non inviarli entrambi: l'API usa il tipo di identificatore configurato per il tuo account partner e ignora l'altro. Scopri di più

    Valore dell'identificatore univoco che il partner usa per ogni sede (ad esempio "Branch ID", "Location Code", "Store Number"). Scopri di più

  • check_in_type string facoltativo

    Tipo di visita. Uno tra member, class, staff, guest e trial.

  • source string facoltativo

    Modalità di acquisizione del check-in. I valori comuni includono manual, tag, rfid, kiosk, app. Si possono usare anche altri valori, come door_reader o booking.

  • class_id string facoltativo

    Facoltativo. Da usare se il check-in è legato a una prenotazione o alla presenza a una lezione.

  • timestamp string obbligatorio

    Timestamp in formato ISO 8601 del momento in cui è avvenuto il check-in.

L'oggetto Check-In

{
  // "check_in_id": "checkin_abc123",  // Optional - auto-generated from member_id + timestamp if not provided
  "member_id": "mem_12345",
  "facility_id": "550e8400-e29b-41d4-a716-446655440000",
  // "linking_identifier": "branch_downtown",  // If using linking identifier
  "check_in_type": "member",
  "source": "rfid",
  "timestamp": "2025-01-20T08:45:30Z"
}

Salvare i check-in

Crea record di check-in. L'API rimuove automaticamente i duplicati in base a membro, struttura e timestamp.

Parametri

  • check_ins array obbligatorio

    Array di oggetti Check-In da salvare. Massimo consigliato: 1000 elementi per richiesta, per prestazioni ottimali. L'API suddivide automaticamente gli elementi in batch per l'elaborazione. Ogni elemento deve includere facility_id (obbligatorio se non usi linking_identifier) oppure linking_identifier (obbligatorio se non usi facility_id).

Valore restituito

Restituisce un semplice messaggio di conferma dell'operazione di sincronizzazione.

Richiesta

curl -X POST https://partner-api.performancehub.co/partner/v1/check-ins \
  -u sk_live_YOUR_PARTNER_SECRET_KEY: \
  -H "Content-Type: application/json" \
  -d '{
    "check_ins": [
      {
        // "check_in_id": "checkin_abc123",  // Optional - auto-generated from member_id + timestamp if not provided
        "member_id": "mem_12345",
        "facility_id": "550e8400-e29b-41d4-a716-446655440000",
        // "linking_identifier": "branch_downtown",  // If using linking identifier
        "check_in_type": "member",
        "source": "rfid",
        "timestamp": "2025-01-20T08:45:30Z"
      }
    ]
  }'

Risposta

Restituisce un messaggio di esito positivo con i metadati dell'operazione di sincronizzazione.

{
  "message": "Check-in sync successful.",
  "metadata": {
    "success": 523,
    "skipped": 3,
    "skipped_items": [
      {
        "member_id": "member_789",
        "facility_id": null,
        "reason": "No matching facility_id for the linking_identifier"
      }
    ]
  }
}

Campi dei metadati:

  • success - Numero di check-in elaborati correttamente
  • skipped - Numero di check-in saltati (se presenti)
  • skipped_items - Array dei check-in saltati con i relativi motivi (se presenti)
  • dry-run - Flag booleano presente se usi il tipo di chiave dryrun (se applicabile)

Controllo degli accessi

La Partner API può attivare l'hardware Door/Gate Controller del Performance Hub nelle strutture in cui la tua integrazione è attivata.

Usa questa API quando il tuo sistema di gestione dei membri ha già deciso che una persona può entrare. Il Performance Hub non valuta lo stato dell'abbonamento, gli orari di accesso, le regole delle zone delle porte, i controlli antifrode o la logica di sospensione. Il tuo sistema resta l'autorità per queste decisioni.

La richiesta di sblocco è sincrona. Il Performance Hub invia il comando al controller in loco in tempo reale e restituisce 200 solo dopo che il dispositivo ha confermato che il relè si è fisicamente sbloccato. La maggior parte delle conferme dovrebbe arrivare entro 3-5 secondi. Se non riceve alcuna conferma entro il tempo limite, l'API restituisce un errore esplicito.

Puoi anche registrare un tentativo di accesso o un rifiuto che non ha mai raggiunto il controller. Questa chiamata non sblocca la porta, ma scrive un evento nei Registri di accesso di Door & Gate Access.

Endpoint

GET /partner/v1/access-control/doors - List available Door/Gate Controllers
GET /partner/v1/access-control/doors/{door_id} - Get Door/Gate Controller status
POST /partner/v1/access-control/doors/{door_id}/unlock - Unlock a Door/Gate Controller
POST /partner/v1/access-control/doors/{door_id}/access-events - Record an access attempt or denial

L'oggetto Door/Gate Controller

Attributi

  • door_id string obbligatorio

    Identificatore univoco del Door/Gate Controller. Salvalo nel tuo sistema dopo il rilevamento e usalo quando chiami l'endpoint di sblocco.

  • facility_id string obbligatorio

    ID della struttura nel Performance Hub.

  • linking_identifier string facoltativo

    Identificatore della struttura del partner, quando la tua integrazione usa gli identificatori di collegamento. Scopri di più

  • name string obbligatorio

    Nome leggibile del dispositivo configurato nel Performance Hub.

  • zone string facoltativo

    Zona o posizione della porta, ad esempio Entrance.

  • status string obbligatorio

    online o offline.

  • relay_state string facoltativo

    Ultimo stato noto del relè, ad esempio locked o unlocked.

  • maintenance_mode string obbligatorio

    Modalità di manutenzione attuale. Uno tra off, force-open e force-closed.

  • hold_time_seconds integer obbligatorio

    Tempo di mantenimento predefinito dello sblocco configurato per la porta.

  • last_seen string facoltativo

    Timestamp ISO dell'ultimo aggiornamento dei metadati del dispositivo.

L'oggetto Door/Gate Controller

{
  "door_id": "00000000000000000000000000000007",
  "facility_id": "550e8400-e29b-41d4-a716-446655440000",
  "linking_identifier": "branch_downtown",
  "name": "Front Door",
  "zone": "Entrance",
  "status": "online",
  "online": true,
  "relay_state": "locked",
  "maintenance_mode": "off",
  "hold_time_seconds": 10,
  "last_seen": "2026-05-01T04:30:00.000Z"
}

Elencare i Door/Gate Controller

Restituisce i Door/Gate Controller disponibili per la tua integrazione.

Se non viene fornito né facility_id né linking_identifier, l'API restituisce i Door/Gate Controller di tutte le strutture collegate al tuo account partner.

Recommended: Include a facility identifier whenever possible. Requests without `facility_id` or `linking_identifier` may take longer to load for partners with hundreds or thousands of Door/Gate Controllers.

Parametri

  • facility_id string facoltativo in alternativaIndica il tipo di identificatore della struttura configurato per la tua integrazione: usa facility_id per le integrazioni con collegamento diretto oppure linking_identifier per le integrazioni con identificatore di collegamento. Non inviarli entrambi: l'API usa il tipo di identificatore configurato per il tuo account partner e ignora l'altro. Scopri di più

    ID della struttura nel Performance Hub. Usalo per le integrazioni con collegamento diretto.

  • linking_identifier string facoltativo in alternativaIndica il tipo di identificatore della struttura configurato per la tua integrazione: usa facility_id per le integrazioni con collegamento diretto oppure linking_identifier per le integrazioni con identificatore di collegamento. Non inviarli entrambi: l'API usa il tipo di identificatore configurato per il tuo account partner e ignora l'altro. Scopri di più

    Il tuo identificatore di struttura/sede. Usalo quando la tua integrazione è configurata per gli identificatori di collegamento.

Valore restituito

Restituisce un array di oggetti Door/Gate Controller.

Richiesta

curl -X GET "https://partner-api.performancehub.co/partner/v1/access-control/doors?facility_id=550e8400-e29b-41d4-a716-446655440000" \
  -u sk_live_YOUR_PARTNER_SECRET_KEY:

Risposta

{
  "data": [
    {
      "door_id": "00000000000000000000000000000007",
      "facility_id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "Front Door",
      "zone": "Entrance",
      "status": "online",
      "relay_state": "locked",
      "maintenance_mode": "off",
      "hold_time_seconds": 10,
      "last_seen": "2026-05-01T04:30:00.000Z"
    }
  ]
}

Ottenere lo stato di un Door/Gate Controller

Recupera l'ultimo stato noto e la configurazione di base di un singolo Door/Gate Controller.

Indica un identificatore della struttura, in modo che il Performance Hub possa verificare che la porta appartenga a una struttura a cui la tua integrazione ha accesso.

Parametri

  • door_id string obbligatorio

    ID del Door/Gate Controller restituito dall'endpoint di elenco.

  • facility_id string in alternativaIndica il tipo di identificatore della struttura configurato per la tua integrazione: usa facility_id per le integrazioni con collegamento diretto oppure linking_identifier per le integrazioni con identificatore di collegamento. Non inviarli entrambi: l'API usa il tipo di identificatore configurato per il tuo account partner e ignora l'altro. Scopri di più

    ID della struttura nel Performance Hub. Obbligatorio per le integrazioni con collegamento diretto.

  • linking_identifier string in alternativaIndica il tipo di identificatore della struttura configurato per la tua integrazione: usa facility_id per le integrazioni con collegamento diretto oppure linking_identifier per le integrazioni con identificatore di collegamento. Non inviarli entrambi: l'API usa il tipo di identificatore configurato per il tuo account partner e ignora l'altro. Scopri di più

    Identificatore della struttura del partner. Obbligatorio per le integrazioni con identificatore di collegamento.

Valore restituito

Restituisce un oggetto Door/Gate Controller.

Richiesta

curl -X GET "https://partner-api.performancehub.co/partner/v1/access-control/doors/00000000000000000000000000000007?facility_id=550e8400-e29b-41d4-a716-446655440000" \
  -u sk_live_YOUR_PARTNER_SECRET_KEY:

Risposta

{
  "data": {
    "door_id": "00000000000000000000000000000007",
    "facility_id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "Front Door",
    "zone": "Entrance",
    "status": "online",
    "relay_state": "locked",
    "maintenance_mode": "off",
    "hold_time_seconds": 10,
    "last_seen": "2026-05-01T04:30:00.000Z"
  }
}

Sbloccare un Door/Gate Controller

Invia un comando di sblocco al Door/Gate Controller e attende che il relè fisico confermi lo sblocco.

Il tuo sistema deve decidere se la persona è autorizzata prima di chiamare questo endpoint. Il Performance Hub verifica solo la chiave partner, l'accesso alla struttura, l'appartenenza della porta e lo stato del dispositivo.

Parametri

  • door_id string obbligatorio

    ID del Door/Gate Controller restituito dall'endpoint di elenco.

  • facility_id string in alternativaIndica il tipo di identificatore della struttura configurato per la tua integrazione: usa facility_id per le integrazioni con collegamento diretto oppure linking_identifier per le integrazioni con identificatore di collegamento. Non inviarli entrambi: l'API usa il tipo di identificatore configurato per il tuo account partner e ignora l'altro. Scopri di più

    ID della struttura nel Performance Hub. Obbligatorio per le integrazioni con collegamento diretto.

  • linking_identifier string in alternativaIndica il tipo di identificatore della struttura configurato per la tua integrazione: usa facility_id per le integrazioni con collegamento diretto oppure linking_identifier per le integrazioni con identificatore di collegamento. Non inviarli entrambi: l'API usa il tipo di identificatore configurato per il tuo account partner e ignora l'altro. Scopri di più

    Identificatore della struttura del partner. Obbligatorio per le integrazioni con identificatore di collegamento.

  • member_id string obbligatorio

    ID del membro nel sistema del partner. Viene usato per la registrazione di audit e per il successivo collegamento dei dati.

  • first_name string obbligatorio

    Nome della persona che apre la porta.

  • last_name string obbligatorio

    Cognome della persona che apre la porta.

  • full_name string facoltativo

    Facoltativo. Se omesso, il Performance Hub combina first_name e last_name.

  • check_in_id string facoltativo

    ID facoltativo del check-in nel tuo sistema, per la correlazione.

  • idempotency_key string facoltativo

    Chiave facoltativa di protezione dalla ripetizione. Riutilizzando la stessa chiave per lo stesso partner, la stessa struttura e la stessa porta si ottiene il risultato esistente, se disponibile.

Valore restituito

Restituisce 200 solo quando il dispositivo conferma che il relè si è fisicamente sbloccato. La porta usa il tempo di mantenimento configurato in Gestione dei dispositivi del Performance Hub; i partner non possono modificare i tempi del relè per singola richiesta. La maggior parte delle conferme dovrebbe arrivare entro 3-5 secondi. Considera il timeout documentato come uno sblocco esplicitamente non riuscito e ripeti il tentativo solo secondo le tue regole di sicurezza.

Errori comuni:

  • 403 integration_not_enabled - la tua integrazione non è attivata per la struttura.
  • 409 maintenance_mode_active - il personale della struttura ha attivato la modalità di manutenzione per la porta.
  • 503 device_offline - il Door/Gate Controller è offline o non aggiornato.
  • 504 unlock_confirmation_timeout - il comando è stato inviato, ma non è stata ricevuta alcuna conferma corrispondente prima del timeout.

Richiesta

curl -X POST https://partner-api.performancehub.co/partner/v1/access-control/doors/00000000000000000000000000000007/unlock \
  -u sk_live_YOUR_PARTNER_SECRET_KEY: \
  -H "Content-Type: application/json" \
  -d '{
    "facility_id": "550e8400-e29b-41d4-a716-446655440000",
    "member_id": "mem_12345",
    "first_name": "Jane",
    "last_name": "S.",
    "full_name": "Jane S.",
    "source": "door_reader",
    "idempotency_key": "unlock_20260501_0001"
  }'

Risposta

{
  "status": "unlocked",
  "door_id": "00000000000000000000000000000007",
  "facility_id": "550e8400-e29b-41d4-a716-446655440000",
  "event_id": "00000000-0000-0000-0000-000000000045",
  "command_id": "00000000-0000-0000-0000-000000000049",
  "hold_time_seconds": 10,
  "confirmed_at": "2026-05-01T04:30:00.000Z"
}

Risposta di errore

{
  "status": "failed",
  "reason": "device_offline",
  "door_id": "00000000000000000000000000000007",
  "facility_id": "550e8400-e29b-41d4-a716-446655440000",
  "event_id": "00000000-0000-0000-0000-000000000045"
}

Registrare un tentativo di accesso o un rifiuto

Registra un tentativo di accesso o un rifiuto già deciso dal tuo sistema. Il Door/Gate Controller non viene contattato e la porta non si sblocca.

Usa questa chiamata quando il tuo sistema rifiuta l'ingresso o quando un tentativo deve comparire nei Registri di accesso di Door & Gate Access senza uno sblocco. Il Performance Hub non valuta lo stato dell'abbonamento, gli orari di accesso o altre regole di accesso.

Un evento rifiutato compare nei Registri di accesso di Door & Gate Access con l'esito Denied, il nome del tuo partner, la porta, l'identificatore del membro se lo invii e il codice del motivo in forma leggibile. Ad esempio, membership_expired viene mostrato come "Membership Expired". reason_display_text e user_email vengono salvati con l'evento.

Parametri

  • door_id string obbligatorio

    ID del Door/Gate Controller restituito dall'endpoint di elenco.

  • facility_id string in alternativaIndica il tipo di identificatore della struttura configurato per la tua integrazione: usa facility_id per le integrazioni con collegamento diretto oppure linking_identifier per le integrazioni con identificatore di collegamento. Non inviarli entrambi: l'API usa il tipo di identificatore configurato per il tuo account partner e ignora l'altro. Scopri di più

    ID della struttura nel Performance Hub. Obbligatorio per le integrazioni con collegamento diretto.

  • linking_identifier string in alternativaIndica il tipo di identificatore della struttura configurato per la tua integrazione: usa facility_id per le integrazioni con collegamento diretto oppure linking_identifier per le integrazioni con identificatore di collegamento. Non inviarli entrambi: l'API usa il tipo di identificatore configurato per il tuo account partner e ignora l'altro. Scopri di più

    Identificatore della struttura del partner. Obbligatorio per le integrazioni con identificatore di collegamento.

  • outcome string obbligatorio

    denied o attempted.

  • reason string facoltativo

    Codice del motivo in snake_case minuscolo, fino a 64 caratteri. Obbligatorio quando outcome è denied. Esempio: membership_expired.

  • reason_display_text string facoltativo

    Motivo in forma leggibile, fino a 256 caratteri. Esempio: Membership expired on 2026-04-01.

  • member_id string facoltativo

    ID del membro nel sistema del partner. Omettilo quando la credenziale non corrisponde a nessun membro, ad esempio nel caso di una tessera sconosciuta.

  • user_email string facoltativo

    Email della persona che ha tentato l'accesso.

  • timestamp string facoltativo

    Momento in cui è avvenuto il tentativo, in formato ISO 8601 con fuso orario. Esempio: 2026-05-18T10:15:30Z. Il valore predefinito è l'ora di ricezione della richiesta. Non può essere più di 5 minuti nel futuro né più vecchio di 30 giorni.

  • idempotency_key string facoltativo

    Chiave di protezione dalla ripetizione, fino a 128 caratteri. Riutilizzando la stessa chiave per lo stesso partner, la stessa struttura e la stessa porta si ottiene il risultato originale.

Valore restituito

Restituisce 201 quando l'evento viene registrato. Ripetendo la richiesta con la stessa idempotency_key si ottiene 200 con idempotent impostato su true e non viene creato un altro evento.

Una chiave dry-run restituisce 200 con dry_run impostato su true. Non viene registrato nulla.

Errori comuni:

  • 400 - il corpo non è valido, un rifiuto non ha un reason, il timestamp è fuori intervallo oppure facility_id / linking_identifier non corrisponde a una struttura collegata.
  • 403 - la chiave è di sola lettura.
  • 403 integration_not_enabled - la tua integrazione non è attivata per la struttura. message indica il motivo.
  • 404 - il Door/Gate Controller non è stato trovato per la struttura collegata.

Richiesta

curl -X POST https://partner-api.performancehub.co/partner/v1/access-control/doors/00000000000000000000000000000007/access-events \
  -u sk_live_YOUR_PARTNER_SECRET_KEY: \
  -H "Content-Type: application/json" \
  -d '{
    "facility_id": "550e8400-e29b-41d4-a716-446655440000",
    "outcome": "denied",
    "reason": "membership_expired",
    "reason_display_text": "Membership expired on 2026-04-01",
    "member_id": "mem_12345",
    "user_email": "member@example.com",
    "timestamp": "2026-05-18T10:15:30Z",
    "idempotency_key": "evt_abc12345"
  }'

Risposta

{
  "status": "recorded",
  "event_id": "00000000-0000-0000-0000-000000000045",
  "outcome": "denied",
  "door_id": "00000000000000000000000000000007",
  "facility_id": "550e8400-e29b-41d4-a716-446655440000",
  "timestamp": "2026-05-18T10:15:30.000Z"
}

Ripetizione idempotente

{
  "status": "recorded",
  "event_id": "00000000-0000-0000-0000-000000000045",
  "outcome": "denied",
  "door_id": "00000000000000000000000000000007",
  "facility_id": "550e8400-e29b-41d4-a716-446655440000",
  "timestamp": "2026-05-18T10:15:30.000Z",
  "idempotent": true
}

Report delle strutture

Un record puntuale che raccoglie le principali metriche operative e finanziarie di una struttura in un periodo specifico.

Endpoint

POST /partner/v1/report-snapshots - Save report snapshots

L'oggetto Report Snapshot

Attributi

  • facility_id string in alternativaIndica il tipo di identificatore della struttura configurato per la tua integrazione: usa facility_id per le integrazioni con collegamento diretto oppure linking_identifier per le integrazioni con identificatore di collegamento. Non inviarli entrambi: l'API usa il tipo di identificatore configurato per il tuo account partner e ignora l'altro. Scopri di più

    Identificatore univoco della struttura nel Performance Hub.

  • linking_identifier string in alternativaIndica il tipo di identificatore della struttura configurato per la tua integrazione: usa facility_id per le integrazioni con collegamento diretto oppure linking_identifier per le integrazioni con identificatore di collegamento. Non inviarli entrambi: l'API usa il tipo di identificatore configurato per il tuo account partner e ignora l'altro. Scopri di più

    Valore dell'identificatore univoco che il partner usa per ogni sede (ad esempio "Branch ID", "Location Code", "Store Number"). Scopri di più

  • start_date string obbligatorio

    Data di inizio del periodo dell'istantanea nel formato YYYY-MM-DD.

  • end_date string obbligatorio

    Data di fine del periodo dell'istantanea nel formato YYYY-MM-DD.

  • metrics object obbligatorio

    Oggetto delle metriche, con i dati sui membri e sui ricavi del periodo.

L'oggetto Report Snapshot

{
  "facility_id": "550e8400-e29b-41d4-a716-446655440000",
  // "linking_identifier": "branch_downtown",  // If using linking identifier
  "start_date": "2025-01-01",
  "end_date": "2025-01-31",
  "metrics": {
    "members": {
      "active": 1200,
      "new": 45,
      "cancelled": 12
    },
    "revenue": {
      "total_payments": 289000.00,
      "total_payments_count": 1200,
      "currency": "AUD"
    }
  }
}

Salvare le istantanee dei report

Invia le metriche operative e finanziarie di una struttura per un periodo specifico.

Parametri

  • snapshots array obbligatorio

    Array di oggetti Report Snapshot da salvare. Massimo 25 elementi per richiesta. Ogni elemento deve includere facility_id (obbligatorio se non usi linking_identifier) oppure linking_identifier (obbligatorio se non usi facility_id).

Valore restituito

Restituisce un semplice messaggio di conferma dell'operazione di sincronizzazione.

Richiesta

curl -X POST https://partner-api.performancehub.co/partner/v1/report-snapshots \
  -u sk_live_YOUR_PARTNER_SECRET_KEY: \
  -H "Content-Type: application/json" \
  -d '{
    "snapshots": [
      {
        "facility_id": "550e8400-e29b-41d4-a716-446655440000",
        // "linking_identifier": "branch_downtown",  // If using linking identifier
        "start_date": "2025-01-01",
        "end_date": "2025-01-31",
        "metrics": {
          "members": {
            "active": 1200,
            "new": 45,
            "cancelled": 12
          },
          "revenue": {
            "total_payments": 289000.00,
            "currency": "AUD"
          }
        }
      }
    ]
  }'

Risposta

{
  "message": "Report snapshot sync successful."
}

Errori

La Partner API usa codici di stato HTTP standard e corpi di risposta JSON per spiegare perché una richiesta non è riuscita.

Struttura della risposta di errore

La maggior parte degli errori dell'API restituisce un corpo JSON con un messaggio e, dove disponibili, dettagli strutturati.

Codici di stato

Errori delle Access Time Windows

La convalida delle finestre non riesce prima che l'istantanea non valida venga scritta. Le cause comuni per cui non ha senso riprovare includono:

  • access_time_windows_revision mancante quando access_time_windows è presente.
  • Valori epoch di tipo stringa, a virgola mobile o probabilmente espressi in millisecondi.
  • Un fuso orario IANA non valido, un intervallo invertito, un external_id duplicato, blocchi settimanali sovrapposti o un blocco notturno non suddiviso.
  • Un valore al di fuori dei limiti documentati di numero, lunghezza o durata.

Una revisione ripetuta con un contenuto normalizzato diverso genera un 409 Conflict. Esegui la riconciliazione con lo stato autorevole più recente e assegna una revisione più nuova; non continuare a riprovare la coppia in conflitto. Una revisione più vecchia viene segnalata come istantanea obsoleta saltata, invece di poter sovrascrivere uno stato più recente. Uno scope_key sconosciuto o non mappato nega l'autorizzazione per impostazione predefinita e va trattato come un avviso di configurazione.

Se la consegna va in timeout o riceve un 5xx temporaneo, riprova con la stessa identica istantanea normalizzata e la stessa revisione. Se il recupero dalla fonte a monte non è riuscito, ometti completamente il campo delle finestre; non sostituirlo mai con un array vuoto.

Indicazioni sui nuovi tentativi

Riprova questi errori con un backoff esponenziale e un numero limitato di tentativi:

  • 429
  • 500
  • 502
  • 503
  • 504

Non riprovare questi errori alla cieca:

  • 400
  • 401
  • 403
  • 404
  • 409
  • 422

Per il controllo degli accessi, considera sempre le risposte di timeout e offline come sblocchi non riusciti, a meno che le tue regole di accesso e i tuoi processi di sicurezza non stabiliscano diversamente.

Dettagli da includere per l'assistenza

Quando contatti l'assistenza, includi:

  • Endpoint e metodo HTTP.
  • Data, ora e fuso orario.
  • ID della chiave partner, non la chiave segreta.
  • Identificatore della struttura usato.
  • ID del record di origine nel tuo sistema.
  • Stato e corpo della risposta.
  • event_id o command_id, se disponibili.
{
  "success": false,
  "message": "Request body.members[0].member_id is required"
}

Alcuni endpoint specifici di un dominio restituiscono uno stato e un motivo espliciti. Ad esempio, gli errori del controllo degli accessi includono campi come reason, door_id, facility_id ed event_id.

{
  "status": "failed",
  "reason": "device_offline",
  "door_id": "00000000000000000000000000000007",
  "facility_id": "550e8400-e29b-41d4-a716-446655440000",
  "event_id": "00000000-0000-0000-0000-000000000045"
}

400 Bad Request

La richiesta non è formata correttamente o mancano campi obbligatori. Correggi la richiesta prima di riprovare.

401 Unauthorized

L'autenticazione non è riuscita. Verifica di usare HTTP Basic Auth con la tua chiave segreta API come nome utente e una password vuota.

403 Forbidden

La chiave è valida, ma l'operazione non è consentita. Le cause comuni includono l'uso di una chiave di sola lettura per un'operazione di scrittura o il tentativo di accedere a una struttura in cui la tua integrazione non è attivata.

404 Not Found

La risorsa richiesta non è stata trovata o non è disponibile per la tua integrazione.

409 Conflict

La richiesta è in conflitto con lo stato attuale della risorsa. Nel controllo degli accessi, ad esempio, un Door/Gate Controller può trovarsi in modalità di manutenzione.

422 Unprocessable Entity

La richiesta è un JSON valido, ma non supera la convalida semantica. Correggi i dati prima di riprovare.

429 Too Many Requests

L'integrazione ha superato il limite di frequenza documentato. Riprova con un backoff esponenziale.

500 Internal Server Error

Il Performance Hub non è riuscito a completare la richiesta a causa di un errore interno. Riprova con un backoff. Se il problema persiste, contatta l'assistenza indicando l'endpoint, il timestamp e il corpo della risposta.

503 Service Unavailable

Un servizio o un dispositivo da cui dipende la richiesta non è disponibile. Per gli sblocchi dei Door/Gate Controller, può significare che il controller è offline.

504 Gateway Timeout

L'operazione è scaduta. Per gli sblocchi dei Door/Gate Controller, significa che lo sblocco non è stato confermato entro il tempo limite.

Controllo delle versioni

La versione della Partner API è indicata nell'URL. La versione attuale è:

Criteri per le modifiche

Il Performance Hub cerca di apportare, ove possibile, modifiche aggiuntive e retrocompatibili.

Esempi di modifiche retrocompatibili:

  • Aggiunta di un nuovo campo facoltativo a una richiesta.
  • Aggiunta di un nuovo campo a una risposta.
  • Aggiunta di un nuovo endpoint.
  • Aggiunta di un nuovo valore enum, quando ci si aspetta che i client gestiscano valori sconosciuti.
  • Miglioramento dei messaggi di convalida senza modificare il contratto dei codici di stato.

access_time_windows e access_time_windows_revision sono campi aggiuntivi della richiesta Member. I client esistenti che li omettono lasciano invariata l'istantanea delle Access Time Windows salvata. Questa regola sull'omissione preserva la compatibilità con gli upsert parziali; omettere i campi non equivale a inviare un array vuoto.

Esempi di modifiche non retrocompatibili:

  • Rimozione o ridenominazione di un campo.
  • Modifica del tipo di un campo.
  • Trasformazione di un campo facoltativo della richiesta in obbligatorio.
  • Rimozione di un endpoint.
  • Modifica del significato di un codice di stato esistente o di un reason specifico di un dominio.

Deprecazioni

Quando è necessaria una modifica non retrocompatibile, il Performance Hub eviterà, ove possibile, di modificare direttamente la versione esistente. Introdurremo invece una nuova versione o un percorso di migrazione e comunicheremo la modifica ai partner interessati.

Gli avvisi di deprecazione possono includere:

  • Una voce nel registro delle modifiche.
  • Comunicazioni dirette ai partner.
  • Note nella Partner Console.
  • Indicazioni per la migrazione nella documentazione.

Consigli per i client

Crea client che tollerino le modifiche aggiuntive:

  • Ignora i campi della risposta che non usi.
  • Tratta i valori enum sconosciuti come non supportati, invece di generare un arresto anomalo.
  • Evita controlli rigorosi di uguaglianza sulle risposte.
  • Registra i valori non riconosciuti, così da poter aggiornare la tua integrazione in modo consapevole.

Per le partizioni Member con revisioni, come le Access Time Windows, conserva la revisione inviata e il payload normalizzato finché non conosci l'esito. Riutilizzare una revisione per un contenuto modificato genera un conflitto, mentre ripetere lo stesso contenuto è idempotente. Consulta Access Time Windows.

Specifiche OpenAPI

Usa le specifiche OpenAPI pubblicate per generare client, convalidare le richieste e monitorare nel tempo le modifiche alla struttura dell'API.

Consulta Specifiche OpenAPI.

https://partner-api.performancehub.co/partner/v1/

Registro delle modifiche

Questo registro delle modifiche riporta le modifiche rilevanti alla Partner API e alla Partner Console che influiscono sul comportamento delle integrazioni.

2026-09-09

2026-05-06

2026-05-01

Categorie di modifica

Le voci future usano queste categorie:

  • Aggiunte - nuovo endpoint, campo, guida o funzionalità.
  • Modifiche - comportamento o documentazione modificati senza rimuovere il supporto.
  • Deprecazioni - la funzionalità resta disponibile, ma è previsto un percorso di migrazione.
  • Rimozioni - funzionalità o endpoint rimossi.
  • Correzioni - correzione di bug o della documentazione.
  • Sicurezza - modifiche ad autenticazione, autorizzazione, gestione dei dati o gestione delle chiavi.

Aggiunte

  • Aggiunte le istantanee access_time_windows dei membri, indipendenti dal fornitore, con finestre assolute e settimanali ricorrenti combinate.
  • Aggiunta la semantica di ordinamento tramite access_time_windows_revision, ripetizione idempotente, conflitto, salto dei dati obsoleti e revoca esplicita.
  • Aggiunte le indicazioni su fusi orari IANA, ora legale, mappatura logica di scope_key, aggiornamento dei dati di origine, implementazione per i produttori e certificazione.

Aggiunte

  • Aggiunta la documentazione del programma partner, che copre tipi di partner, onboarding, best practice, preparazione al go-live, errori, controllo delle versioni e assistenza.
  • Aggiunto un flusso dedicato di richiesta Become a Partner per i potenziali partner tecnici e commerciali.
  • Aggiunta la documentazione su come le integrazioni partner approvate compaiono nella directory dei partner del Performance Hub, all'interno della piattaforma principale del Performance Hub.

Aggiunte

  • Aggiunta la documentazione sul controllo degli accessi dei Door/Gate Controller, comprese le operazioni di elenco, stato e sblocco.
  • Aggiunta la documentazione sul comportamento dello sblocco sincrono: l'API restituisce un esito positivo solo dopo che il controller in loco ha confermato che il relè si è fisicamente sbloccato.
  • Aggiunta la documentazione sul supporto della idempotency_key facoltativa per le richieste di sblocco dei Door/Gate Controller.