Introduction
La Partner API de Performance Hub permet aux plateformes de partenaires externes de s'intégrer facilement aux modules principaux de Performance Hub. L'API prend en charge la vision par ordinateur, l'analyse, la journalisation des accès des membres et les informations sur les installations.
Format des requêtes
L'API accepte des corps de requête encodés en JSON et renvoie des réponses encodées en JSON.
Limitation du débit
Pour garantir une utilisation équitable et la stabilité du système, les comptes Partner API démarrent avec les limites par défaut suivantes :
- 5 requêtes par seconde par endpoint
- Recommandé : 1000 éléments maximum par requête par lot pour des performances optimales
- Taille de charge utile de 10MB maximum
Les limites de débit sont ajustables et peuvent être configurées au cas par cas par votre responsable de compte partenaire Performance Hub. Si votre intégration nécessite un débit plus élevé pour un lancement, des migrations, des importations rétroactives de données de reporting ou des installations à fort volume, signalez-le lors de l'intégration ou avant la fenêtre de modification prévue.
URL de base
https://partner-api.performancehub.co/partner/v1/
Authentification
L'accès à la Partner API nécessite une authentification au moyen de clés secrètes API. Générez et gérez vos clés depuis la Partner Console.
Les clés API constituent vos identifiants d'accès aux ressources partenaires. Chaque clé dispose d'un accès restreint à des données d'organisation spécifiques et peut être désactivée instantanément si nécessaire.
Manipulez vos clés API avec précaution : elles donnent un accès complet à votre compte ! N'exposez jamais ces clés dans des dépôts publics, des applications côté client ou tout autre endroit où elles pourraient être compromises.
Authentifiez les requêtes avec l'authentification HTTP Basic en transmettant votre clé API comme nom d'utilisateur. Laissez le mot de passe vide.
L'API n'accepte que les connexions HTTPS sécurisées. Les requêtes HTTP non chiffrées sont rejetées, de même que toute requête dépourvue d'identifiants d'authentification valides.
Exemple de requête
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.
Vérifier la clé secrète
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>" }
Liste de contrôle de mise en production
Utilisez cette liste de contrôle avant d'activer une intégration partenaire pour des installations en production.
Configuration de la Partner Console
- Votre profil de partenaire est complet.
- L'URL de votre logo, votre site web, votre catégorie et votre description sont exacts.
- Votre méthode de liaison des données est configurée : Direct Link ou Linking Identifier.
- La liaison des installations a été testée avec au moins une installation réelle.
- Le bon type de clé est utilisé :
- Dryrun pour les tests d'écriture non destructifs.
- Read-only pour une consommation des données en toute sécurité.
- Live uniquement lorsque vous êtes prêt à modifier des données de production.
Authentification et gestion des clés
- Les clés secrètes sont stockées uniquement côté serveur.
- Les clés ne sont pas intégrées dans des applications côté client, des applications mobiles, des dépôts publics ou des tickets d'assistance.
- La rotation et la révocation des clés ont été testées.
- Votre équipe sait quelle clé est utilisée par chaque environnement.
Validation des données
- Les champs obligatoires sont présents pour chaque endpoint que vous appelez.
- Les identifiants d'installation correspondent à la méthode de liaison configurée.
- Les ID provenant de votre système sont stables et ne changent pas d'une synchronisation à l'autre.
- Les importations volumineuses sont divisées en lots respectant les limites documentées.
- Les éléments de lot en échec peuvent être identifiés et renvoyés.
Test des endpoints
Avant le lancement, testez chaque endpoint dont dépend votre intégration :
- Les organisations et les installations peuvent être lues.
- Les membres peuvent être enregistrés et mis à jour.
- Les formules d'abonnement, les zones d'accès et les heures d'accès se synchronisent correctement.
- Les enregistrements d'entrée sont acceptés et peuvent être rapprochés de votre système.
- Les instantanés de rapports utilisent la période de reporting et les indicateurs attendus.
- Les flux des contrôleurs de porte/portail sont testés sur du matériel réel, le cas échéant.
Préparation des Access Time Windows
Si l'intégration fournit des Access Time Windows :
- Les exemples absolus et hebdomadaires satisfont à la liste de contrôle de certification des producteurs.
- Les epochs sont des secondes Unix entières non entourées de guillemets ; les limites exactes
[from, to)ont été testées. - Les valeurs UTC par défaut, les fuseaux horaires IANA personnalisés de l'intégration et les changements d'heure d'été pertinents ont été vérifiés.
- Un flux de révisions par membre/source unique, durable et croissant coordonne les mises à jour incrémentielles, le rapprochement et les nouvelles tentatives.
- Les opérateurs comprennent les comportements en cas d'omission, de remplacement complet, d'idempotence, de conflit, d'obsolescence et de
[]explicite. - Chaque
scope_key, y comprisdefault, dispose d'une correspondance Performance Hub approuvée ; il a été vérifié que les clés inconnues entraînent un refus par défaut. - La fréquence d'actualisation attendue de l'intégration, l'ancienneté maximale des sources, le comportement en cas de source obsolète et les alertes sont configurés.
- Il a été démontré qu'un échec de récupération en amont n'émet pas d'instantané vide ou partiel.
- La convergence du flux de staging, l'annulation/la révocation et les limites de début et de fin sur les portes physiques respectent les objectifs convenus.
- Les règles habituelles et les autorisations permanentes ont été vérifiées comme solutions de repli, et les plages ne peuvent pas contourner la désactivation d'un utilisateur,
blockAllAccess, la maintenance ou le géorepérage.
Préparation du contrôle d'accès
Pour les intégrations de contrôle d'accès :
- Votre système prend la décision d'accès avant d'appeler Performance Hub.
- L'intégration gère
device_offline,maintenance_mode_activeetunlock_confirmation_timeout. - Les opérateurs savent qu'un délai d'expiration signifie que le déverrouillage n'a pas été confirmé.
- Vos journaux stockent l'
event_idet lecommand_idrenvoyés. - Vous disposez d'une procédure de repli manuelle pour le personnel de l'installation.
Gestion des erreurs et nouvelles tentatives
- Les réponses
400,401,403,404,409et422sont remontées aux opérateurs ou aux équipes d'assistance au lieu d'être réessayées aveuglément. - Les réponses
429,500,502,503et504utilisent une logique de nouvelles tentatives limitée avec backoff. - Les échecs répétés déclenchent une alerte dans votre système.
- L'intégration n'abandonne jamais silencieusement les enregistrements en échec.
Observabilité
- Vos journaux incluent l'endpoint, l'horodatage, l'identifiant d'installation, l'ID de l'enregistrement source, le résultat de la requête et le corps de la réponse.
- Votre équipe d'assistance peut effectuer des recherches par ID de membre, ID d'installation, ID d'enregistrement d'entrée ou ID d'événement de déverrouillage.
- Vous disposez d'un moyen de rejouer ou de rapprocher les synchronisations en échec.
Lancement en production
- Performance Hub a confirmé votre accès en production.
- Au moins une installation en production a activé votre intégration.
- Votre clé de production est active.
- Vos contacts opérationnels et techniques sont à jour.
- Votre procédure d'assistance est documentée pour les clients.
Une fois ces vérifications terminées, votre intégration configurée apparaîtra dans l'annuaire des partenaires Performance Hub, au sein de la plateforme principale Performance Hub.
Bonnes pratiques
Appliquez ces modèles pour que les intégrations partenaires restent prévisibles, observables et sûres pour les installations.
Identifier les installations de manière cohérente
Choisissez la méthode de liaison configurée pour votre compte partenaire et utilisez-la de manière cohérente :
- Direct Link - utilisez le
facility_idPerformance Hub renvoyé par l'endpoint des installations. - Linking Identifier - utilisez votre propre identifiant de site, comme un ID d'agence, un code de site ou un numéro de magasin.
N'envoyez pas les deux identifiants dans la même requête. Performance Hub résout les requêtes à l'aide de la méthode de liaison configurée pour votre compte partenaire.
Consultez Méthodes de liaison des partenaires pour obtenir des conseils de configuration.
Écrire par lots avec précaution
La Partner API accepte des corps de requête JSON et est conçue pour des procédures de synchronisation par lots, lorsque cela est documenté. Limitez la taille des lots et faites en sorte qu'ils puissent être relancés.
Recommandations par défaut :
- Utilisez jusqu'à 1000 éléments par requête par lot pour des performances optimales.
- Maintenez les charges utiles sous 10MB.
- Ne dépassez pas 5 requêtes par seconde et par endpoint.
Les limites de débit sont ajustables et peuvent être configurées au cas par cas par votre responsable de compte partenaire Performance Hub. Si vous prévoyez des importations volumineuses, du trafic lié à un lancement ou des importations rétroactives de données de reporting, convenez du débit nécessaire avant la fenêtre de modification.
Si vous devez synchroniser un jeu de données volumineux, divisez-le en blocs déterministes et journalisez l'ID de chaque bloc de votre côté. Il est ainsi plus facile d'analyser les nouvelles tentatives en échec.
Réessayer en toute sécurité
Utilisez un backoff exponentiel pour les échecs temporaires tels que 429, 500, 502, 503 et 504.
Évitez les boucles de nouvelles tentatives rapprochées. Un bon point de départ consiste à :
- Réessayer après 1 seconde.
- Réessayer après 2 secondes.
- Réessayer après 4 secondes.
- Arrêter et déclencher une alerte si l'opération échoue toujours.
Pour les échecs de validation tels que 400 ou 422, corrigez la requête avant de réessayer.
Utiliser l'idempotence lorsqu'elle est prise en charge
L'endpoint de déverrouillage des contrôleurs de porte/portail prend en charge une idempotency_key facultative. Réutiliser la même clé pour le même partenaire, la même installation et la même porte renvoie le résultat existant lorsqu'il est disponible.
Utilisez une clé stable pour l'action effectuée, par exemple un ID d'enregistrement d'entrée ou un ID d'événement d'accès provenant de votre système.
Ne supposez pas que tous les endpoints d'écriture prennent en charge l'idempotence, sauf si cela est documenté pour l'endpoint concerné.
Maintenir des données sources propres
Envoyez des valeurs stables et normalisées dans la mesure du possible :
- Utilisez des ID de membres, de formules, d'installations et d'enregistrements d'entrée cohérents provenant de votre système source.
- Utilisez des horodatages ISO 8601 pour les dates et les heures.
- Envoyez les numéros de téléphone au format international lorsqu'ils sont disponibles.
- Envoyez les devises à l'aide des champs documentés pour chaque endpoint.
- Évitez de surcharger les champs de texte libre avec des données qui ont leur place dans des champs structurés.
Prévoir des synchronisations incrémentielles et complètes
La plupart des intégrations partenaires ont besoin des deux :
- Synchronisations incrémentielles pour les modifications quotidiennes.
- Synchronisations de rapprochement complètes pour corriger les événements manqués, les importations historiques ou les dérives de données.
Votre intégration doit pouvoir renvoyer l'état actuel d'un membre, d'une formule d'abonnement ou d'un instantané de rapport sans dépendre de la réussite d'une requête précédente.
Publier les Access Time Windows en toute sécurité
Traitez la valeur access_time_windows de chaque membre comme un instantané complet, doté de sa propre révision indépendante :
- Coordonnez un flux unique et strictement croissant de
access_time_windows_revisionentre les processus incrémentiels et de rapprochement. - Relancez une livraison incertaine ou temporairement en échec avec la même révision et la même charge utile normalisée.
- Omettez
access_time_windowslorsque vous ne le mettez pas à jour. - N'envoyez
[]qu'après qu'une récupération réussie depuis la source de référence a prouvé qu'il ne reste aucune plage. Ne transformez jamais un délai d'expiration en amont, un résultat partiel ou un échec d'analyse en révocation. - Gardez
external_idetscope_keystables, et certifiez chaque correspondance de portée avant la mise en production. - Surveillez l'ancienneté des données sources par rapport à la politique de fraîcheur convenue pour cette intégration.
Consultez le guide de référence pour les producteurs d'Access Time Windows pour les instantanés complets, les fuseaux horaires, l'heure d'été, l'annulation et les vecteurs de test.
Traiter le contrôle d'accès comme critique pour la sécurité
Pour les déverrouillages de contrôleurs de porte/portail :
- Votre système doit décider si la personne est autorisée à entrer avant d'appeler Performance Hub.
- Performance Hub ne renvoie
200qu'après que le contrôleur sur site a confirmé le déverrouillage physique du relais. - La plupart des confirmations aboutissent en 3 à 5 secondes.
- Un délai d'expiration correspond à un échec explicite du déverrouillage, et non à une réussite en arrière-plan.
- Ne réessayez que conformément à vos propres règles d'accès et de sécurité.
Journalisez toujours l'event_id et le command_id renvoyés par l'endpoint de déverrouillage.
Surveiller votre intégration
Utilisez les journaux de requêtes de la Partner Console pendant le développement et le lancement. En production, tenez également vos propres journaux avec :
- L'horodatage de la requête.
- L'endpoint.
- L'ID de l'enregistrement source.
- L'identifiant d'installation.
- Le code de statut HTTP.
- Le corps de la réponse ou le message d'erreur de Performance Hub.
Ces champs accélèrent considérablement l'assistance et le rapprochement lorsqu'un client demande ce qui s'est passé.
Organisations
Représente l'entité commerciale de premier niveau qui exploite une ou plusieurs installations intégrées à la plateforme Performance Hub.
Points de terminaison
GET /partner/v1/organisations - List all organisations
L'objet Organisation
Attributs
org_id
stringobligatoireIdentifiant unique de l'organisation.
name
stringobligatoireNom de l'organisation.
L'objet Organisation
{
"org_id": "00000000-0000-0000-0000-000000000050",
"name": "Harbourside Group"
}
Lister toutes les organisations
Renvoie la liste des organisations accessibles à votre compte partenaire.
Valeur renvoyée
Renvoie un objet JSON dont la propriété data contient un tableau d'objets Organisation.
Requête
curl https://partner-api.performancehub.co/partner/v1/organisations \
-u sk_live_YOUR_PARTNER_SECRET_KEY:
Réponse
{
"data": [
{
"org_id": "00000000-0000-0000-0000-000000000050",
"name": "Harbourside Group"
},
{
"org_id": "6ba7b811-9dad-11d1-80b4-00c04fd430c8",
"name": "Wellness Studios Network"
}
]
}
Installations
Représente un lieu physique, comme un bureau, un magasin, une salle de spectacle, un campus, une clinique ou une salle de sport, où les membres peuvent accéder à des services.
Points de terminaison
GET /partner/v1/facilities - List all facilities
L'objet installation
Attributs
facility_id
stringobligatoireIdentifiant unique de l'installation.
org_id
stringobligatoireIdentifiant unique de l'organisation parente.
name
stringobligatoireNom de l'installation.
brand
stringfacultatifNom de la marque utilisée par l'installation.
website_url
stringfacultatifURL du site web de l'installation.
place_data
objectfacultatifDonnées de localisation issues de l'API Google Places contenant le pays, l'adresse formatée, le Google Place ID, la province et la ville.
social_links
objectfacultatifLiens vers les réseaux sociaux de l'installation.
timezone
stringfacultatifIdentifiant de fuseau horaire IANA (par exemple,
"Australia/Sydney","America/New_York").
L'objet installation
{
"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"
}
Lister toutes les installations
Renvoie la liste des installations accessibles à votre compte partenaire.
Valeur renvoyée
Renvoie un objet JSON dont la propriété data contient un tableau d'objets installation.
Requête
curl https://partner-api.performancehub.co/partner/v1/facilities \
-u sk_live_YOUR_PARTNER_SECRET_KEY:
Réponse
{
"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"
}
]
}
Formules d'abonnement
Définit une offre achetable proposée par une organisation ou une installation, y compris les services, les droits, le calendrier et les tarifs.
Points de terminaison
POST /partner/v1/membership-plans - Save a membership plan
L'objet Membership Plan
Attributs
membership_plan_id
stringobligatoireIdentifiant unique de la formule d'abonnement.
facility_id
stringl'un ou l'autreIndiquez le type d'identifiant d'installation configuré pour votre intégration : utilisez facility_id pour les intégrations à liaison directe, ou linking_identifier pour les intégrations à identifiant de liaison. N'envoyez pas les deux ; l'API utilise le type d'identifiant configuré pour votre compte partenaire et ignore l'autre. En savoir plusIdentifiant unique de l'installation dans Performance Hub.
linking_identifier
stringl'un ou l'autreIndiquez le type d'identifiant d'installation configuré pour votre intégration : utilisez facility_id pour les intégrations à liaison directe, ou linking_identifier pour les intégrations à identifiant de liaison. N'envoyez pas les deux ; l'API utilise le type d'identifiant configuré pour votre compte partenaire et ignore l'autre. En savoir plusValeur d'identifiant unique que le partenaire utilise pour chaque site (par exemple, « Branch ID », « Location Code », « Store Number »). En savoir plus
name
stringobligatoireNom lisible de la formule (par exemple,
"Office tenant – business hours","Student – term access","Hotel guest","10 Class Pack").billing_cycle
stringfacultatifFréquence de facturation. L'une des valeurs
weekly,fortnightly,monthly,annuallyouone_time.price
integerfacultatifCoût de base dans la plus petite unité monétaire (cents pour USD/AUD).
currency
stringfacultatifCode de devise ISO 4217 (par exemple,
"AUD","USD").description
stringfacultatifDescription marketing ou interne facultative.
active_members
integerfacultatifNombre de membres actifs utilisant cette formule d'abonnement
is_recurring
booleanfacultatifIndique si la formule est renouvelée automatiquement.
is_trial
booleanfacultatifIndique s'il s'agit d'une offre d'essai.
visible_to_public
booleanfacultatifIndique si la formule peut être achetée en libre-service.
duration_days
integerfacultatifNombre de jours de validité de la formule d'abonnement.
access_zones
arrayfacultatifTableau des zones d'accès incluses dans la formule d'abonnement. Chaque zone peut définir ses propres heures d'accès. Consultez Zones d'accès pour plus de détails.
class_limit
integerfacultatifNombre maximal de cours autorisés (null pour un nombre illimité).
L'objet Membership Plan
Cet exemple utilise facility_id. Pour une intégration à identifiant de liaison, envoyez plutôt "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
}
Zones d'accès
Les zones d'accès définissent les espaces précis d'une installation auxquels une formule d'abonnement donne accès. Chaque zone peut avoir ses propres heures d'accès, ce qui permet d'appliquer des restrictions horaires différentes selon l'espace.
Structure
Chaque zone d'accès comprend :
name
stringobligatoireLe nom de la zone (par exemple, « Level 3 Tenancy », « Library », « Guest Floors », « Main Gym Floor »).
description
stringfacultatifDescription de ce qui est inclus dans cette zone.
access_hours
objectfacultatifHeures d'accès propres à cette zone. Consultez Heures d'accès pour le format des plages horaires.
Exemple
Un immeuble de bureaux doté d'une salle de sport pour ses locataires : accès aux locaux loués pendant les heures ouvrables, et à la salle de sport du petit matin jusqu'en fin de soirée.
{
"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"]]
}
}
]
}
Heures d'accès
Les heures d'accès indiquent quand les membres peuvent accéder à une zone donnée pour chaque jour de la semaine. Elles sont définies par zone d'accès, ce qui permet d'appliquer des restrictions horaires différentes aux différents espaces d'une installation.
Structure
{
"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"]]
}
Chaque jour est un tableau de plages horaires au format HH:MM (format 24 heures). Un tableau vide [] signifie qu'aucun accès n'est possible ce jour-là. Les jours omis sont traités comme un tableau vide.
Exemples de cas d'usage
Locataire de bureaux – heures ouvrables : accès pendant les heures ouvrables, en semaine uniquement.
{
"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"]]
}
}
Étudiant – accès pendant le trimestre : une bibliothèque de campus ouverte en semaine, avec une pause en milieu de journée, ainsi que le samedi matin.
{
"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"]]
}
}
Salle de sport – lève-tôt : accès le matin uniquement, en semaine.
{
"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"]]
}
}
Client d'hôtel – 24 h/24, 7 j/7 : accès permanent, le cas d'usage le plus courant.
{
"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"]]
}
}
Exemple par zone
Une formule pour les clients d'un hôtel, avec un accès 24 heures sur 24 aux étages des chambres et des horaires plus restreints pour la piscine :
{
"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"]]
}
}
]
}
Enregistrer une formule d'abonnement
Crée ou met à jour des fiches de formules d'abonnement. L'API détermine s'il faut créer ou mettre à jour la fiche en fonction du membership_plan_id.
Paramètres
membership_plans
arrayobligatoireTableau d'objets Membership Plan à enregistrer. Maximum recommandé : 1000 éléments par requête pour des performances optimales. L'API regroupe automatiquement les éléments en lots pour leur traitement. Chaque élément doit inclure soit
facility_id(obligatoire si vous n'utilisez paslinking_identifier), soitlinking_identifier(obligatoire si vous n'utilisez pasfacility_id).
Valeur renvoyée
Renvoie un message simple confirmant l'opération de synchronisation.
Requête
Cet exemple utilise facility_id. Pour une intégration à identifiant de liaison, envoyez plutôt "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
}
]
}'
Réponse
Renvoie un message de réussite accompagné de métadonnées sur l'opération de synchronisation.
{
"message": "Membership plan sync successful.",
"metadata": {
"success": 98,
"skipped": 2,
"skipped_items": [
{
"membership_plan_id": "plan_456",
"facility_id": null,
"reason": "Missing facility_id"
}
]
}
}
Champs de métadonnées :
- success - Nombre de formules d'abonnement traitées avec succès
- skipped - Nombre de formules ignorées (le cas échéant)
- skipped_items - Tableau des formules ignorées, avec leurs motifs (le cas échéant)
- dry-run - Indicateur booléen en cas d'utilisation d'une clé de type dryrun (le cas échéant)
Membres
Représente un client individuel d'une installation. Il peut s'agir d'un lead, d'un prospect, d'un client régulier, d'un membre expiré ou d'un utilisateur bloqué.
Les upserts de membres peuvent également contenir un instantané access_time_windows complet et révisionné, comprenant des accès absolus et hebdomadaires récurrents. Consultez Access Time Windows avant de produire ces champs. Il s'agit d'autorisations supplémentaires qui ne remplacent pas les règles habituelles ni les autorisations permanentes de l'installation.
Points de terminaison
POST /partner/v1/members - Save a member
L'objet Member
Attributs
member_id
stringobligatoireIdentifiant unique du membre.
facility_id
stringl'un ou l'autreIndiquez le type d'identifiant d'installation configuré pour votre intégration : utilisez facility_id pour les intégrations à liaison directe, ou linking_identifier pour les intégrations à identifiant de liaison. N'envoyez pas les deux ; l'API utilise le type d'identifiant configuré pour votre compte partenaire et ignore l'autre. En savoir plusIdentifiant unique de l'installation dans Performance Hub.
linking_identifier
stringl'un ou l'autreIndiquez le type d'identifiant d'installation configuré pour votre intégration : utilisez facility_id pour les intégrations à liaison directe, ou linking_identifier pour les intégrations à identifiant de liaison. N'envoyez pas les deux ; l'API utilise le type d'identifiant configuré pour votre compte partenaire et ignore l'autre. En savoir plusValeur d'identifiant unique que le partenaire utilise pour chaque site (par exemple, « Branch ID », « Location Code », « Store Number »). En savoir plus
first_name
stringobligatoirePrénom du membre.
last_name
stringobligatoireNom de famille du membre.
email
stringfacultatifAdresse e-mail.
mobile_phone
stringfacultatifNuméro de téléphone mobile au format E.123 (par exemple,
"+1 415 555 2671").address
objectfacultatifObjet d'adresse physique doté des propriétés suivantes :
address_line_1(string) - Adresse principale (rue)address_line_2(string, optional) - Ligne d'adresse secondairecity(string) - Nom de la villestate(string) - Code de l'État/de la provincepostal_code(string) - Code postal/ZIPcountry(string) - Code pays ISO 3166-1 alpha-2 (par exemple, « AU », « US »)country_name(string, optional) - Nom complet du pays
date_of_birth
stringfacultatifDate de naissance au format
YYYY-MM-DD.gender
stringfacultatifL'une des valeurs
male,female,non_binary,prefer_not_to_sayouunknown.type
stringfacultatifType de membre (par exemple,
staff,member,prospect).tags
arrayfacultatifChaînes ou textes d'aide rapide permettant de classer et d'identifier des membres spécifiques (par exemple,
["vip", "personal-training", "student"]).membership_status
stringfacultatifStatut d'adhésion actuel (par exemple,
active,expired,on_hold).membership_plans
arrayfacultatifTableau des formules d'abonnement associées au membre.
profile_picture
stringfacultatifPhoto de profil encodée en Base64 (facultatif).
created
stringfacultatifHorodatage ISO 8601 de la création du membre.
updated
stringfacultatifHorodatage ISO 8601 de la dernière mise à jour du membre.
access_time_windows
arrayfacultatifInstantané complet, appartenant à la source, des Access Time Windows absolues et/ou hebdomadaires récurrentes. Omettez le champ pour conserver l'instantané tel quel ; envoyez un tableau vide avec une révision plus récente pour le révoquer. Consultez Access Time Windows pour les formes, la validation, la correspondance des portées et la sémantique de remplacement.
access_time_windows_revision
integerobligatoire avec access_time_windowsEntier non négatif, strictement croissant et compatible JSON, propre au flux de ce membre/cette source. Obligatoire dès que
access_time_windowsest présent.
L'objet 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
}
]
}
Plages horaires d'accès
Les Access Time Windows permettent à un membre partenaire de bénéficier d'un accès temporaire ou récurrent fourni par un système externe. Cette page est le guide de référence pour les producteurs de access_time_windows et de access_time_windows_revision.
Les Access Time Windows sont des autorisations supplémentaires qui ne peuvent qu'accorder l'accès. Une plage active peut autoriser l'accès, mais une plage inactive, expirée, obsolète ou sans correspondance ne refuse pas un accès déjà autorisé par une règle habituelle ou une autorisation permanente. La désactivation d'un utilisateur, le blocage explicite d'une porte, le mode de maintenance, le géorepérage, les limites de débit et la disponibilité du contrôleur continuent de s'appliquer.
Les implémentations destinées à des systèmes en amont particuliers sont des adaptateurs distincts. Elles doivent traduire leurs données sources dans ce contrat indépendant des fournisseurs sans modifier la signification de ses champs.
Champs de l'instantané de membre
access_time_windows
arrayfacultatifL'instantané complet des Access Time Windows pour ce membre et cette source partenaire. Un instantané peut combiner des plages
absoluteetweekly. Omettez le champ pour conserver l'instantané stocké tel quel ; envoyez[]pour révoquer toutes les plages appartenant à cette source.access_time_windows_revision
integerobligatoire avec access_time_windowsUn entier non négatif, strictement croissant et compatible JSON, propre au flux de révisions de ce membre/cette source. Il est obligatoire dès que
access_time_windowsest présent et ne doit pas dépasser9007199254740991.
Chaque instantané accepte au maximum 50 plages. external_id, scope_key et label acceptent au maximum 120 caractères. Une plage absolue peut couvrir au maximum 90 jours. Un jour de la semaine accepte au maximum huit blocs sans chevauchement. Les données invalides sont rejetées au lieu d'être tronquées ou interprétées.
Formes des plages
Une plage absolue désigne un intervalle exact unique :
Requête mixte complète
Cette requête remplace l'instantané précédent du membre appartenant à la source par une plage absolue et une plage hebdomadaire :
Règles relatives aux heures et aux limites
from, to, active_from et active_until sont des entiers JSON exprimés en secondes Unix, qui désignent des instants UTC :
- Envoyez un entier JSON sans guillemets. Les chaînes numériques, les nombres à virgule flottante, les chaînes RFC 3339 et les millisecondes Unix sont rejetés.
- Chaque intervalle est semi-ouvert :
[from, to). L'accès peut commencer exactement àfrom; il n'est plus actif exactement àto. fromdoit être inférieur àto. Lorsque les deux bornes hebdomadaires sont présentes,active_fromdoit être inférieur àactive_until.- Ne calculez pas d'epochs à partir d'une date/heure locale sans fuseau horaire. Convertissez d'abord l'heure source en instant UTC, puis divisez les millisecondes Unix par 1000 et vérifiez que le résultat est un entier.
Fuseaux horaires et heure d'été
timezone doit être un fuseau horaire IANA valide, comme UTC, Australia/Perth ou America/New_York. Sa valeur par défaut est UTC lorsqu'il est omis.
- Plages absolues :
fromettodésignent déjà des instants UTC exacts.timezonen'est qu'une métadonnée d'affichage et d'audit ; la modifier ne décale jamais aucun des deux instants. - Plages hebdomadaires :
timezonedéfinit l'heure locale et les règles d'heure d'été utilisées pour évalueraccess_hours. Ne convertissez pas les blocs hebdomadaires en UTC au préalable. - Lors du passage à l'heure d'été, une heure locale sautée par le fuseau horaire ne se produit jamais.
- Lors du retour à l'heure d'hiver, les deux instants réels correspondant à l'heure locale répétée correspondent au bloc hebdomadaire.
active_frometactive_untilrestent des instants UTC, même lorsqu'une plage hebdomadaire utilise un fuseau horaire autre qu'UTC.
access_hours utilise les valeurs en minuscules sun à sat. Chaque valeur est un tableau de paires [start, end] au format HH:mm sur 24 heures, complété par des zéros. Les blocs doivent être non vides, ordonnés et sans chevauchement. end est exclusif. Un bloc ne peut pas franchir minuit ; scindez un intervalle source de nuit en un bloc tardif le premier jour et un bloc matinal le jour suivant.
ID stables et correspondance des portées
external_id doit rester stable pendant toute la durée de vie d'une plage logique et être unique au sein de l'instantané du membre. Conservez-le lorsque les heures ou les libellés changent, afin que les opérateurs et les enregistrements d'audit puissent rapprocher les révisions. Ne le réutilisez pas pour une plage sans rapport.
scope_key est votre cible d'accès logique stable. Sa valeur par défaut est default. Un administrateur de l'installation associe chaque clé autorisée à des cibles Performance Hub : l'ensemble de l'installation, une porte ou une Portée d'accès :
Instantanés complets et révisions
Traitez ces deux champs comme une partition versionnée séparément au sein de l'upsert de membre :
| Entrée | Résultat |
|---|---|
access_time_windows omis |
L'instantané existant reste inchangé ; aucune révision n'est requise |
| Présent avec une révision plus récente | L'intégralité de l'instantané stocké pour ce membre/cette source est remplacée |
| Même révision et même charge utile normalisée | Relecture idempotente ; aucune modification de l'instantané |
| Même révision et charge utile normalisée différente | Conflit ; attribuez une nouvelle révision après rapprochement |
| Révision plus ancienne | L'instantané obsolète est ignoré ; il ne peut pas écraser un état plus récent |
access_time_windows: [] avec une révision plus récente |
Révoque explicitement toutes les plages appartenant à la source |
Un instantané est complet, ce n'est pas un correctif partiel. Si la révision 1842 contient les plages A et B, alors la révision 1843 qui ne contient que B supprime A.
Maintenez un flux de révisions coordonné unique par partenaire/membre pour l'ensemble des processus de webhook, d'interrogation périodique, de relecture et de rapprochement complet. Une séquence de base de données durable est préférable. Une valeur en millisecondes Unix ne peut servir de révision que si tous les processus d'écriture se coordonnent et garantissent un ordre strict et l'unicité ; il s'agit d'une valeur de révision, et non d'un champ d'epoch.
Conservez la requête et la révision exactes jusqu'à ce que la réponse de l'API soit connue. Après un délai d'expiration ou une erreur temporaire, renvoyez le même instantané normalisé avec la même révision. N'attribuez pas une nouvelle révision au seul motif que la livraison est incertaine.
Annulation, expiration et échecs en amont
- Annuler une plage : récupérez avec succès l'état de référence de la source, supprimez cette plage et envoyez l'instantané complet restant avec une révision plus récente.
- Annuler toutes les plages : envoyez
access_time_windows: []avec une révision plus récente. - Laisser expirer une plage absolue : elle cesse d'autoriser l'accès à
to; envoyez ultérieurement un rapprochement sans l'entrée expirée pour garder des instantanés propres. - Mettre fin à une plage hebdomadaire : supprimez-la dans un instantané plus récent, ou utilisez
active_untillorsque la source connaît l'instant de fin. - La récupération depuis la source échoue ou est incomplète : n'envoyez pas
[]et ne publiez pas d'instantané partiel. Déclenchez une alerte et relancez la récupération. Transformer un échec en amont en instantané vide revient à révoquer l'accès involontairement. - La requête Partner API échoue à la validation : corrigez les données et n'envoyez une révision plus récente que si l'instantané normalisé change. Relancez les échecs temporaires avec la révision d'origine.
La fraîcheur des sources est configurée pour chaque intégration en fonction de la fréquence de livraison et de rapprochement qu'elle garantit. Avant l'activation, convenez de l'ancienneté maximale des sources, de ce qui se passe lorsqu'elle est dépassée, des seuils d'alerte et de la possibilité pour les opérateurs d'accepter de ne s'appuyer que sur les bornes propres à chaque plage. Une plage provenant d'une source obsolète ne devient jamais une règle de refus ; les règles habituelles et les autorisations permanentes restent des solutions de repli.
Algorithme du producteur
Utilisez cette procédure indépendante du langage pour chaque mise à jour de membre :
Liste de contrôle de certification
Effectuez ces vérifications dans une installation de staging en utilisant la correspondance scope_key définitive :
- Une plage absolue sans fuseau horaire est acceptée et évaluée en UTC.
- Une plage absolue avec un fuseau IANA personnalisé conserve les mêmes instants
from/to. - Une plage hebdomadaire avec un fuseau IANA personnalisé suit l'heure locale lors du passage à l'heure d'été et du retour à l'heure d'hiver.
- Un instantané mixte absolu/hebdomadaire remplace entièrement l'instantané précédent.
- L'accès commence exactement à
fromet s'arrête exactement àto; les fins de blocs hebdomadaires sont également exclusives. - La modification des heures sous le même
external_idavec une révision plus récente prend effet. - L'omission de
access_time_windowsmodifie les autres champs du membre sans modifier les plages. - La relecture de la même révision/charge utile est idempotente.
- La même révision avec une charge utile différente renvoie un conflit et ne modifie pas l'instantané.
- Une révision plus ancienne reçue dans le désordre est signalée comme obsolète et ne peut pas rétablir un état antérieur.
- Un
[]plus récent révoque les plages appartenant à la source ; un échec de récupération en amont n'envoie rien. - Un
scope_keyinconnu ou sans correspondance entraîne un refus par défaut et génère un avertissement visible par les opérateurs. - Les alertes d'ancienneté des sources et la politique configurée pour les sources obsolètes fonctionnent au seuil convenu.
- Les chemins de webhook et de rapprochement complet convergent vers le même instantané et le même ordre de révisions.
- La livraison du flux atteint Door & Gate Access dans le délai convenu.
- Une plage active peut autoriser l'accès à la porte physique associée, mais ne peut pas contourner la désactivation d'un utilisateur,
blockAllAccess, la maintenance ou le géorepérage. - Avant, en dehors et après une plage, les règles habituelles et les autorisations permanentes continuent d'autoriser les utilisateurs qui remplissent par ailleurs les conditions.
Ressources associées
{
"external_id": "access-4b1782",
"kind": "absolute",
"from": 1792053000,
"to": 1792058400,
"timezone": "Australia/Perth",
"scope_key": "after_hours_entry",
"label": "Temporary site access"
}
Les champs obligatoires sont external_id, kind, from et to. timezone, scope_key et label sont facultatifs.
Une plage hebdomadaire désigne des intervalles récurrents en heure locale, éventuellement bornés par des instants 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"
}
Les champs obligatoires sont external_id, kind et access_hours. timezone, active_from, active_until, scope_key et label sont facultatifs.
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"
}
]
}
]
}'
Utilisez facility_id ou linking_identifier selon la méthode de liaison configurée. N'envoyez pas les deux.
Conversion en epoch
2026-10-15T08:30:00Z est converti en 1792053000 :
UTC instant Unix milliseconds Unix seconds sent
2026-10-15T08:30:00Z 1792053000000 1792053000
Conversion indépendante du langage :
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
Si la source offre une précision inférieure à la seconde, définissez une politique d'arrondi explicite pour le début et la fin avant les tests d'intégration. Ne transmettez jamais de millisecondes en comptant sur l'API pour deviner 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
Les partenaires n'envoient pas d'ID d'installation, de porte ou de Portée d'accès Performance Hub dans une plage. Un scope_key inconnu, désactivé ou sans correspondance entraîne un refus par défaut pour cette plage ; il n'élargit pas l'accès. Convenez des correspondances et testez-les avant le lancement.
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)
Vecteurs de test minimaux
[
{
"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."
}
]
Soumettez également des vecteurs négatifs pour les millisecondes Unix, les chaînes numériques, les nombres à virgule flottante, les fuseaux IANA invalides, from >= to, les external_id en double, les blocs qui se chevauchent, les blocs de nuit, plus de huit blocs dans une journée, plus de 50 plages et les clés de portée sans correspondance.
Enregistrer un membre
Crée ou met à jour des fiches de membres. L'API détermine s'il faut créer ou mettre à jour la fiche en fonction du member_id.
Paramètres
members
arrayobligatoireTableau d'objets Member à enregistrer. Maximum recommandé : 1000 éléments par requête pour des performances optimales. L'API regroupe automatiquement les éléments en lots pour leur traitement. Chaque élément doit inclure soit
facility_id(obligatoire si vous n'utilisez paslinking_identifier), soitlinking_identifier(obligatoire si vous n'utilisez pasfacility_id).Lorsqu'un membre inclut
access_time_windows, il doit également inclureaccess_time_windows_revision. Le tableau est un instantané complet de la source, et non un correctif partiel. Omettez-le pour conserver l'instantané existant, ou envoyez[]avec une révision plus récente pour révoquer toutes les plages appartenant à la source. Lisez le guide des Access Time Windows avant d'activer ce champ.
Valeur renvoyée
Renvoie un message simple confirmant l'opération de synchronisation.
Les champs du profil du membre restent des upserts normaux, même lorsqu'un instantané de plages est signalé comme une relecture idempotente ou ignoré car obsolète. Un instantané en conflit (même révision, charge utile différente) ne peut pas être renvoyé tel quel ; rapprochez l'état de la source et envoyez une révision plus récente.
Requête
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
}
]
}
]
}'
Réponse
Renvoie un message de réussite accompagné de métadonnées sur l'opération de synchronisation.
{
"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"
}
]
}
}
Champs de métadonnées :
- success - Nombre de membres traités avec succès
- skipped - Nombre de membres ignorés (le cas échéant)
- skipped_items - Tableau des membres ignorés, avec leurs motifs (le cas échéant)
- dry-run - Indicateur booléen en cas d'utilisation d'une clé de type dryrun (le cas échéant)
Enregistrements d'entrée
Représente l'enregistrement de la présence d'une personne dans une installation, à un cours ou à une activité. Utilisé pour le suivi de la fréquentation, l'analyse de l'utilisation et l'amélioration de la précision de la détection visuelle.
Points de terminaison
POST /partner/v1/check-ins - Save check-ins
L'objet Check-In
Attributs
check_in_id
stringfacultatifIdentifiant unique de l'enregistrement d'entrée. Facultatif : généré automatiquement à partir de la paire
member_idettimestamps'il n'est pas fourni.member_id
stringobligatoireIdentifiant unique du membre.
facility_id
stringl'un ou l'autreIndiquez le type d'identifiant d'installation configuré pour votre intégration : utilisez facility_id pour les intégrations à liaison directe, ou linking_identifier pour les intégrations à identifiant de liaison. N'envoyez pas les deux ; l'API utilise le type d'identifiant configuré pour votre compte partenaire et ignore l'autre. En savoir plusIdentifiant unique de l'installation dans Performance Hub.
linking_identifier
stringl'un ou l'autreIndiquez le type d'identifiant d'installation configuré pour votre intégration : utilisez facility_id pour les intégrations à liaison directe, ou linking_identifier pour les intégrations à identifiant de liaison. N'envoyez pas les deux ; l'API utilise le type d'identifiant configuré pour votre compte partenaire et ignore l'autre. En savoir plusValeur d'identifiant unique que le partenaire utilise pour chaque site (par exemple, « Branch ID », « Location Code », « Store Number »). En savoir plus
check_in_type
stringfacultatifType de visite. L'une des valeurs
member,class,staff,guestoutrial.source
stringfacultatifMode de saisie de l'enregistrement d'entrée. Les valeurs courantes sont
manual,tag,rfid,kiosk,app. D'autres valeurs commedoor_readeroubookingpeuvent également être utilisées.class_id
stringfacultatifFacultatif. À renseigner si l'enregistrement est lié à une réservation ou à une participation à un cours.
timestamp
stringobligatoireHorodatage au format ISO 8601 du moment où l'enregistrement d'entrée a eu lieu.
L'objet 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"
}
Enregistrer des entrées
Crée des enregistrements d'entrée. L'API dédoublonne automatiquement les enregistrements en fonction du membre, de l'installation et de l'horodatage.
Paramètres
check_ins
arrayobligatoireTableau d'objets Check-In à enregistrer. Maximum recommandé : 1000 éléments par requête pour des performances optimales. L'API regroupe automatiquement les éléments en lots pour leur traitement. Chaque élément doit inclure soit
facility_id(obligatoire si vous n'utilisez paslinking_identifier), soitlinking_identifier(obligatoire si vous n'utilisez pasfacility_id).
Valeur renvoyée
Renvoie un message simple confirmant l'opération de synchronisation.
Requête
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"
}
]
}'
Réponse
Renvoie un message de réussite accompagné de métadonnées sur l'opération de synchronisation.
{
"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"
}
]
}
}
Champs de métadonnées :
- success - Nombre d'enregistrements d'entrée traités avec succès
- skipped - Nombre d'enregistrements d'entrée ignorés (le cas échéant)
- skipped_items - Tableau des enregistrements d'entrée ignorés, avec leurs motifs (le cas échéant)
- dry-run - Indicateur booléen en cas d'utilisation d'une clé de type dryrun (le cas échéant)
Contrôle d'accès
La Partner API peut déclencher le matériel de contrôleur de porte/portail Performance Hub pour les installations où votre intégration est activée.
Utilisez cette API lorsque votre système de gestion des membres a déjà décidé qu'une personne est autorisée à entrer. Performance Hub n'évalue pas le statut d'adhésion, les heures d'accès, les règles de zones de portes, les contrôles antifraude ni la logique de suspension. Votre système reste l'autorité pour ces décisions.
La requête de déverrouillage est synchrone. Performance Hub envoie la commande au contrôleur sur site en temps réel et ne renvoie 200 qu'après que l'appareil a confirmé le déverrouillage physique du relais. La plupart des confirmations devraient aboutir en 3 à 5 secondes. Si aucune confirmation n'est reçue dans le délai imparti, l'API renvoie un échec explicite.
Vous pouvez également enregistrer une tentative d'accès ou un refus qui n'a jamais atteint le contrôleur. Cet appel ne déverrouille pas la porte. Il écrit un événement dans les Journaux d'accès de Door & Gate Access.
Points de terminaison
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'objet contrôleur de porte/portail
Attributs
door_id
stringobligatoireIdentifiant unique du contrôleur de porte/portail. Stockez-le dans votre système après la découverte et utilisez-le lorsque vous appelez l'endpoint de déverrouillage.
facility_id
stringobligatoireID d'installation Performance Hub.
linking_identifier
stringfacultatifIdentifiant d'installation du partenaire lorsque votre intégration utilise des identifiants de liaison. En savoir plus
name
stringobligatoireNom lisible de l'appareil configuré dans Performance Hub.
zone
stringfacultatifZone ou emplacement de la porte, par exemple
Entrance.status
stringobligatoireonlineouoffline.relay_state
stringfacultatifDernier état connu du relais, par exemple
lockedouunlocked.maintenance_mode
stringobligatoireMode de maintenance actuel. L'une des valeurs
off,force-openouforce-closed.hold_time_seconds
integerobligatoireDurée de maintien du déverrouillage configurée par défaut pour la porte.
last_seen
stringfacultatifHorodatage ISO de la dernière mise à jour des métadonnées de l'appareil.
L'objet contrôleur de porte/portail
{
"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"
}
Lister les contrôleurs de porte/portail
Renvoie les contrôleurs de porte/portail disponibles pour votre intégration.
Si ni facility_id ni linking_identifier n'est fourni, l'API renvoie les contrôleurs de porte/portail de toutes les installations liées à votre compte partenaire.
Paramètres
facility_id
stringfacultatif l'un ou l'autreIndiquez le type d'identifiant d'installation configuré pour votre intégration : utilisez facility_id pour les intégrations à liaison directe, ou linking_identifier pour les intégrations à identifiant de liaison. N'envoyez pas les deux ; l'API utilise le type d'identifiant configuré pour votre compte partenaire et ignore l'autre. En savoir plusID d'installation Performance Hub. À utiliser pour les intégrations à liaison directe.
linking_identifier
stringfacultatif l'un ou l'autreIndiquez le type d'identifiant d'installation configuré pour votre intégration : utilisez facility_id pour les intégrations à liaison directe, ou linking_identifier pour les intégrations à identifiant de liaison. N'envoyez pas les deux ; l'API utilise le type d'identifiant configuré pour votre compte partenaire et ignore l'autre. En savoir plusVotre propre identifiant d'installation/de site. À utiliser lorsque votre intégration est configurée pour les identifiants de liaison.
Valeur renvoyée
Renvoie un tableau d'objets contrôleur de porte/portail.
Requête
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:
Réponse
{
"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"
}
]
}
Obtenir l'état d'un contrôleur de porte/portail
Récupère le dernier état connu et la configuration de base d'un contrôleur de porte/portail.
Fournissez un identifiant d'installation afin que Performance Hub puisse vérifier que la porte appartient à une installation à laquelle votre intégration a accès.
Paramètres
door_id
stringobligatoireID du contrôleur de porte/portail renvoyé par l'endpoint de liste.
facility_id
stringl'un ou l'autreIndiquez le type d'identifiant d'installation configuré pour votre intégration : utilisez facility_id pour les intégrations à liaison directe, ou linking_identifier pour les intégrations à identifiant de liaison. N'envoyez pas les deux ; l'API utilise le type d'identifiant configuré pour votre compte partenaire et ignore l'autre. En savoir plusID d'installation Performance Hub. Obligatoire pour les intégrations à liaison directe.
linking_identifier
stringl'un ou l'autreIndiquez le type d'identifiant d'installation configuré pour votre intégration : utilisez facility_id pour les intégrations à liaison directe, ou linking_identifier pour les intégrations à identifiant de liaison. N'envoyez pas les deux ; l'API utilise le type d'identifiant configuré pour votre compte partenaire et ignore l'autre. En savoir plusIdentifiant d'installation du partenaire. Obligatoire pour les intégrations à identifiant de liaison.
Valeur renvoyée
Renvoie un objet contrôleur de porte/portail.
Requête
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:
Réponse
{
"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"
}
}
Déverrouiller un contrôleur de porte/portail
Envoie une commande de déverrouillage au contrôleur de porte/portail et attend que le relais physique confirme le déverrouillage.
Votre système doit décider si la personne est autorisée avant d'appeler cet endpoint. Performance Hub vérifie uniquement la clé partenaire, l'accès à l'installation, l'appartenance de la porte et l'état de l'appareil.
Paramètres
door_id
stringobligatoireID du contrôleur de porte/portail renvoyé par l'endpoint de liste.
facility_id
stringl'un ou l'autreIndiquez le type d'identifiant d'installation configuré pour votre intégration : utilisez facility_id pour les intégrations à liaison directe, ou linking_identifier pour les intégrations à identifiant de liaison. N'envoyez pas les deux ; l'API utilise le type d'identifiant configuré pour votre compte partenaire et ignore l'autre. En savoir plusID d'installation Performance Hub. Obligatoire pour les intégrations à liaison directe.
linking_identifier
stringl'un ou l'autreIndiquez le type d'identifiant d'installation configuré pour votre intégration : utilisez facility_id pour les intégrations à liaison directe, ou linking_identifier pour les intégrations à identifiant de liaison. N'envoyez pas les deux ; l'API utilise le type d'identifiant configuré pour votre compte partenaire et ignore l'autre. En savoir plusIdentifiant d'installation du partenaire. Obligatoire pour les intégrations à identifiant de liaison.
member_id
stringobligatoireID du membre chez le partenaire. Utilisé pour la journalisation d'audit et la liaison ultérieure des données.
first_name
stringobligatoirePrénom de la personne qui ouvre la porte.
last_name
stringobligatoireNom de famille de la personne qui ouvre la porte.
full_name
stringfacultatifFacultatif. S'il est omis, Performance Hub combine
first_nameetlast_name.check_in_id
stringfacultatifID d'enregistrement d'entrée facultatif provenant de votre système, pour la corrélation.
idempotency_key
stringfacultatifClé facultative de protection contre la relecture. Réutiliser la même clé pour le même partenaire, la même installation et la même porte renvoie le résultat existant lorsqu'il est disponible.
Valeur renvoyée
Renvoie 200 uniquement lorsque l'appareil confirme le déverrouillage physique du relais. La porte utilise la durée de maintien configurée dans Gestion d'appareils de Performance Hub ; les partenaires ne peuvent pas modifier la temporisation du relais pour chaque requête. La plupart des confirmations devraient aboutir en 3 à 5 secondes. Considérez le délai d'expiration documenté comme un échec explicite du déverrouillage et ne réessayez que conformément à vos propres règles de sécurité.
Échecs courants :
403 integration_not_enabled- votre intégration n'est pas activée pour l'installation.409 maintenance_mode_active- le personnel de l'installation a activé le mode de maintenance pour la porte.503 device_offline- le contrôleur de porte/portail est hors ligne ou ses données sont obsolètes.504 unlock_confirmation_timeout- la commande a été envoyée, mais aucune confirmation correspondante n'a été reçue avant l'expiration du délai.
Requête
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"
}'
Réponse
{
"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"
}
Réponse en cas d'échec
{
"status": "failed",
"reason": "device_offline",
"door_id": "00000000000000000000000000000007",
"facility_id": "550e8400-e29b-41d4-a716-446655440000",
"event_id": "00000000-0000-0000-0000-000000000045"
}
Enregistrer une tentative d'accès ou un refus
Enregistre une tentative d'accès ou un refus déjà décidé par votre système. Le contrôleur de porte/portail n'est pas contacté et la porte ne se déverrouille pas.
Utilisez cet endpoint lorsque votre système refuse l'entrée, ou lorsqu'une tentative doit apparaître dans les Journaux d'accès de Door & Gate Access sans déverrouillage. Performance Hub n'évalue pas le statut d'adhésion, les heures d'accès ni les autres règles d'accès.
Un événement refusé apparaît dans les Journaux d'accès de Door & Gate Access avec le résultat Denied, le nom de votre entreprise partenaire, la porte, l'identifiant du membre lorsque vous en envoyez un, et le code de motif sous une forme lisible. Par exemple, membership_expired s'affiche sous la forme « Membership Expired ». reason_display_text et user_email sont stockés avec l'événement.
Paramètres
door_id
stringobligatoireID du contrôleur de porte/portail renvoyé par l'endpoint de liste.
facility_id
stringl'un ou l'autreIndiquez le type d'identifiant d'installation configuré pour votre intégration : utilisez facility_id pour les intégrations à liaison directe, ou linking_identifier pour les intégrations à identifiant de liaison. N'envoyez pas les deux ; l'API utilise le type d'identifiant configuré pour votre compte partenaire et ignore l'autre. En savoir plusID d'installation Performance Hub. Obligatoire pour les intégrations à liaison directe.
linking_identifier
stringl'un ou l'autreIndiquez le type d'identifiant d'installation configuré pour votre intégration : utilisez facility_id pour les intégrations à liaison directe, ou linking_identifier pour les intégrations à identifiant de liaison. N'envoyez pas les deux ; l'API utilise le type d'identifiant configuré pour votre compte partenaire et ignore l'autre. En savoir plusIdentifiant d'installation du partenaire. Obligatoire pour les intégrations à identifiant de liaison.
outcome
stringobligatoiredeniedouattempted.reason
stringfacultatifCode de motif en snake_case minuscule, 64 caractères maximum. Obligatoire lorsque
outcomevautdenied. Exemple :membership_expired.reason_display_text
stringfacultatifMotif lisible, 256 caractères maximum. Exemple :
Membership expired on 2026-04-01.member_id
stringfacultatifID du membre chez le partenaire. Omettez-le lorsque l'identifiant d'accès ne correspond à aucun membre, par exemple une carte inconnue.
user_email
stringfacultatifAdresse e-mail de la personne qui a tenté d'accéder.
timestamp
stringfacultatifMoment de la tentative, au format ISO 8601 avec fuseau horaire. Exemple :
2026-05-18T10:15:30Z. Par défaut, l'heure de réception de la requête. Ne doit pas être située plus de 5 minutes dans le futur ni dater de plus de 30 jours.idempotency_key
stringfacultatifClé de protection contre la relecture, 128 caractères maximum. Réutiliser la même clé pour le même partenaire, la même installation et la même porte renvoie le résultat d'origine.
Valeur renvoyée
Renvoie 201 lorsque l'événement est enregistré. Rejouer la même idempotency_key renvoie 200 avec idempotent défini sur true et ne crée pas de nouvel événement.
Une clé dry-run renvoie 200 avec dry_run défini sur true. Rien n'est enregistré.
Échecs courants :
400- le corps est invalide, un refus n'a pas dereason, l'horodatage est hors plage, oufacility_id/linking_identifierne correspond à aucune installation liée.403- la clé est en lecture seule.403 integration_not_enabled- votre intégration n'est pas activée pour l'installation.messageen indique la raison.404- le contrôleur de porte/portail est introuvable pour l'installation liée.
Requête
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"
}'
Réponse
{
"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"
}
Relecture 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
}
Rapports d'installation
Un enregistrement ponctuel qui capture les principaux indicateurs opérationnels et financiers d'une installation pour une période donnée.
Points de terminaison
POST /partner/v1/report-snapshots - Save report snapshots
L'objet Report Snapshot
Attributs
facility_id
stringl'un ou l'autreIndiquez le type d'identifiant d'installation configuré pour votre intégration : utilisez facility_id pour les intégrations à liaison directe, ou linking_identifier pour les intégrations à identifiant de liaison. N'envoyez pas les deux ; l'API utilise le type d'identifiant configuré pour votre compte partenaire et ignore l'autre. En savoir plusIdentifiant unique de l'installation dans Performance Hub.
linking_identifier
stringl'un ou l'autreIndiquez le type d'identifiant d'installation configuré pour votre intégration : utilisez facility_id pour les intégrations à liaison directe, ou linking_identifier pour les intégrations à identifiant de liaison. N'envoyez pas les deux ; l'API utilise le type d'identifiant configuré pour votre compte partenaire et ignore l'autre. En savoir plusValeur d'identifiant unique que le partenaire utilise pour chaque site (par exemple, « Branch ID », « Location Code », « Store Number »). En savoir plus
start_date
stringobligatoireDate de début de la période de l'instantané au format
YYYY-MM-DD.end_date
stringobligatoireDate de fin de la période de l'instantané au format
YYYY-MM-DD.metrics
objectobligatoireObjet d'indicateurs contenant les données sur les membres et le chiffre d'affaires pour la période.
L'objet 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"
}
}
}
Enregistrer des instantanés de rapports
Soumet les indicateurs opérationnels et financiers d'une installation pour une période donnée.
Paramètres
snapshots
arrayobligatoireTableau d'objets Report Snapshot à enregistrer. 25 éléments maximum par requête. Chaque élément doit inclure soit
facility_id(obligatoire si vous n'utilisez paslinking_identifier), soitlinking_identifier(obligatoire si vous n'utilisez pasfacility_id).
Valeur renvoyée
Renvoie un message simple confirmant l'opération de synchronisation.
Requête
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"
}
}
}
]
}'
Réponse
{
"message": "Report snapshot sync successful."
}
Erreurs
La Partner API utilise des codes de statut HTTP standard et des corps de réponse JSON pour expliquer pourquoi une requête a échoué.
Structure des réponses d'erreur
La plupart des erreurs de l'API renvoient un corps JSON contenant un message et, le cas échéant, des détails structurés.
Codes de statut
Échecs liés aux Access Time Windows
La validation des plages échoue avant l'écriture de l'instantané invalide. Les causes courantes qui ne justifient pas une nouvelle tentative sont notamment :
- L'absence de
access_time_windows_revisionlorsqueaccess_time_windowsest présent. - Des valeurs d'epoch sous forme de chaîne, de nombre à virgule flottante ou probablement exprimées en millisecondes.
- Un fuseau horaire IANA invalide, un intervalle inversé, un
external_iden double, des blocs hebdomadaires qui se chevauchent ou un bloc de nuit qui n'a pas été scindé. - Une valeur qui dépasse les limites documentées de nombre, de longueur ou d'étendue.
Une révision répétée avec un contenu normalisé différent renvoie une erreur 409 Conflict. Effectuez un rapprochement avec le dernier état de référence et attribuez une révision plus récente ; ne continuez pas à réessayer la paire en conflit. Une révision plus ancienne est signalée comme un instantané obsolète ignoré au lieu d'être autorisée à écraser un état plus récent. Un scope_key inconnu ou sans correspondance entraîne un refus d'autorisation par défaut et doit être traité comme une alerte de configuration.
Si la livraison expire ou reçoit une erreur 5xx temporaire, renvoyez exactement le même instantané normalisé avec la même révision. Si la récupération depuis la source en amont a échoué, omettez entièrement le champ des plages ; ne le remplacez jamais par un tableau vide.
Recommandations pour les nouvelles tentatives
Réessayez les codes suivants avec un backoff exponentiel limité :
429500502503504
Ne réessayez pas aveuglément les codes suivants :
400401403404409422
Pour le contrôle d'accès, considérez toujours les réponses d'expiration de délai et d'appareil hors ligne comme des déverrouillages en échec, sauf si vos propres règles d'accès et processus de sécurité en disposent autrement.
Informations à fournir à l'assistance
Lorsque vous contactez l'assistance, indiquez :
- L'endpoint et la méthode HTTP.
- L'horodatage et le fuseau horaire.
- L'ID de la clé partenaire, et non la clé secrète.
- L'identifiant d'installation utilisé.
- L'ID de l'enregistrement source dans votre système.
- Le statut et le corps de la réponse.
- L'
event_idou lecommand_id, le cas échéant.
{
"success": false,
"message": "Request body.members[0].member_id is required"
}
Certains endpoints propres à un domaine renvoient un statut et un motif explicites. Par exemple, les échecs de contrôle d'accès incluent des champs tels que reason, door_id, facility_id et 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 requête est mal formée ou des champs obligatoires sont manquants. Corrigez la requête avant de réessayer.
401 Unauthorized
L'authentification a échoué. Vérifiez que vous utilisez l'authentification HTTP Basic avec votre clé secrète API comme nom d'utilisateur et un mot de passe vide.
403 Forbidden
La clé est valide, mais l'opération n'est pas autorisée. Les causes courantes sont l'utilisation d'une clé en lecture seule pour une opération d'écriture ou une tentative d'accès à une installation pour laquelle votre intégration n'est pas activée.
404 Not Found
La ressource demandée est introuvable ou n'est pas disponible pour votre intégration.
409 Conflict
La requête est en conflit avec l'état actuel de la ressource. Pour le contrôle d'accès, cela peut signifier qu'un contrôleur de porte/portail est en mode de maintenance.
422 Unprocessable Entity
La requête est un JSON valide, mais elle échoue à la validation sémantique. Corrigez les données avant de réessayer.
429 Too Many Requests
L'intégration a dépassé la limite de débit documentée. Réessayez avec un backoff exponentiel.
500 Internal Server Error
Performance Hub n'a pas pu traiter la requête en raison d'une erreur interne. Réessayez avec un backoff. Si le problème persiste, contactez l'assistance en indiquant l'endpoint, l'horodatage et le corps de la réponse.
503 Service Unavailable
Un service ou un appareil dont dépend la requête est indisponible. Pour les déverrouillages de contrôleurs de porte/portail, cela peut signifier que le contrôleur est hors ligne.
504 Gateway Timeout
Le délai de l'opération a expiré. Pour les déverrouillages de contrôleurs de porte/portail, cela signifie que le déverrouillage n'a pas été confirmé avant l'expiration du délai.
Gestion des versions
La version de la Partner API est indiquée dans l'URL. La version actuelle est :
Politique de modification
Performance Hub s'efforce, dans la mesure du possible, d'apporter des modifications additives et rétrocompatibles.
Exemples de modifications rétrocompatibles :
- L'ajout d'un nouveau champ facultatif à une requête.
- L'ajout d'un nouveau champ à une réponse.
- L'ajout d'un nouvel endpoint.
- L'ajout d'une nouvelle valeur d'énumération lorsque les clients sont censés gérer les valeurs inconnues.
- L'amélioration des messages de validation sans modifier le contrat des codes de statut.
access_time_windows et access_time_windows_revision sont des champs additifs des requêtes Member. Les clients existants qui les omettent conservent tel quel l'instantané des Access Time Windows stocké. Cette règle d'omission préserve la compatibilité des upserts partiels ; l'omission n'équivaut pas à l'envoi d'un tableau vide.
Exemples de modifications non rétrocompatibles :
- La suppression ou le renommage d'un champ.
- La modification du type d'un champ.
- Le passage d'un champ de requête facultatif à obligatoire.
- La suppression d'un endpoint.
- La modification de la signification d'un code de statut existant ou d'un
reasonpropre à un domaine.
Obsolescences
Lorsqu'une modification non rétrocompatible est nécessaire, Performance Hub évite, dans la mesure du possible, de modifier la version existante en place. Nous introduisons plutôt une nouvelle version ou un chemin de migration et communiquons la modification aux partenaires concernés.
Les avis d'obsolescence peuvent prendre la forme de :
- Une entrée dans le journal des modifications.
- Une communication directe aux partenaires.
- Des notes dans la Partner Console.
- Des conseils de migration dans la documentation.
Recommandations pour les clients
Concevez des clients qui tolèrent les modifications additives :
- Ignorez les champs de réponse que vous n'utilisez pas.
- Traitez les valeurs d'énumération inconnues comme non prises en charge au lieu de provoquer un plantage.
- Évitez les contrôles d'égalité stricts sur les réponses.
- Journalisez les valeurs non reconnues afin de pouvoir mettre à jour votre intégration de façon délibérée.
Pour les partitions Member révisionnées telles que les Access Time Windows, conservez la révision soumise et la charge utile normalisée jusqu'à ce que le résultat soit connu. Réutiliser une révision pour un contenu modifié constitue un conflit, tandis que rejouer le même contenu est idempotent. Consultez Access Time Windows.
Spécifications OpenAPI
Utilisez les spécifications OpenAPI publiées pour générer des clients, valider les requêtes et suivre l'évolution de la structure de l'API au fil du temps.
Consultez Spécifications OpenAPI.
https://partner-api.performancehub.co/partner/v1/
Journal des modifications
Ce journal des modifications recense les changements notables de la Partner API et de la Partner Console qui affectent le comportement des intégrations.
2026-09-09
2026-05-06
2026-05-01
Catégories de modifications
Les prochaines entrées utiliseront ces catégories :
- Ajouts - nouvel endpoint, champ, guide ou fonctionnalité.
- Modifications - comportement ou documentation modifiés sans suppression de la prise en charge.
- Obsolescences - fonctionnalité toujours disponible, mais faisant l'objet d'un plan de migration.
- Suppressions - fonctionnalité ou endpoint supprimé.
- Corrections - correction de bug ou de documentation.
- Sécurité - modification touchant l'authentification, les autorisations, le traitement des données ou la gestion des clés.
Ajouts
- Ajout d'instantanés
access_time_windowsde membres, indépendants des fournisseurs, combinant plages absolues et plages hebdomadaires récurrentes. - Ajout de la sémantique d'ordonnancement par
access_time_windows_revision, de relecture idempotente, de conflit, d'ignorance des données obsolètes et de révocation explicite. - Ajout de recommandations sur les fuseaux horaires IANA, l'heure d'été, la correspondance logique
scope_key, la fraîcheur des sources, l'implémentation côté producteur et la certification.
Ajouts
- Ajout d'une documentation du programme partenaires couvrant les types de partenaires, l'intégration, les bonnes pratiques, la préparation à la mise en production, les erreurs, la gestion des versions et l'assistance.
- Ajout d'un parcours de demande Devenir partenaire dédié aux futurs partenaires techniques et commerciaux.
- Ajout d'une documentation expliquant comment les intégrations partenaires approuvées apparaissent dans l'annuaire des partenaires Performance Hub, au sein de la plateforme principale Performance Hub.
Ajouts
- Ajout de la documentation du contrôle d'accès des contrôleurs de porte/portail, y compris les opérations de liste, d'état et de déverrouillage.
- Ajout de la documentation du comportement de déverrouillage synchrone : l'API ne renvoie un succès qu'après que le contrôleur sur site a confirmé le déverrouillage physique du relais.
- Ajout de la documentation de la prise en charge de la
idempotency_keyfacultative pour les requêtes de déverrouillage des contrôleurs de porte/portail.