Introduction
The Performance Hub Partner API enables external partner platforms to seamlessly integrate with Performance Hub's core modules. The API supports computer vision, analytics, member access logging, and facility insights.
Request Format
The API accepts JSON-encoded request bodies and returns JSON-encoded responses.
Rate Limiting
To ensure fair usage and system stability, Partner API accounts start with default limits:
- 5 requests per second per endpoint
- Recommended: 1000 items maximum per batch request for optimal performance
- 10MB maximum payload size
Rate limits are adjustable and can be configured on a case-by-case basis by your Performance Hub partner account manager. If your integration needs higher throughput for launch, migrations, reporting backfills, or high-volume facilities, raise this during onboarding or before the planned change window.
Base URL
https://partner-api.performancehub.co/partner/v1/
Authentication
Access to the Partner API requires authentication using API secret keys. Generate and manage your keys through the Partner Console.
API keys serve as your credentials for accessing partner resources. Each key has restricted access to specific organisation data and can be deactivated instantly when needed.
Handle your API keys with care—they provide full access to your account! Never expose these keys in public repositories, client-side applications, or anywhere they could be compromised.
Authenticate requests using HTTP Basic Auth by passing your API key as the username. Leave the password empty.
The API only accepts secure HTTPS connections. Plain HTTP requests are rejected, as are any requests missing proper authentication credentials.
Example Request
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.
Verify Secret Key
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>" }
Going-Live Checklist
Use this checklist before enabling a partner integration for production facilities.
Partner Console setup
- Your partner profile is complete.
- Your logo URL, website, category, and description are accurate.
- Your data linking method is configured: Direct Link or Linking Identifier.
- Facility linking has been tested with at least one real facility.
- The right key type is being used:
- Dryrun for non-destructive write testing.
- Read-only for safe data consumption.
- Live only when you are ready to affect production data.
Authentication and key management
- Secret keys are stored server-side only.
- Keys are not embedded in client-side applications, mobile apps, public repositories, or support tickets.
- Key rotation and revocation have been tested.
- Your team knows which key is used by each environment.
Data validation
- Required fields are present for every endpoint you call.
- Facility identifiers match your configured linking method.
- IDs from your system are stable and do not change between syncs.
- Large imports are split into batches under the documented limits.
- Failed batch items can be identified and resent.
Endpoint testing
Before launch, test every endpoint your integration depends on:
- Organisations and facilities can be read.
- Members can be saved and updated.
- Membership plans, access zones, and access hours sync correctly.
- Check-ins are accepted and can be correlated back to your system.
- Report snapshots use the expected reporting period and metrics.
- Door/Gate Controller flows are tested on real hardware where applicable.
Access control readiness
For access control integrations:
- Your system makes the access decision before calling Performance Hub.
- The integration handles
device_offline,maintenance_mode_active, andunlock_confirmation_timeout. - Operators understand that a timeout means the unlock was not confirmed.
- Your logs store the returned
event_idandcommand_id. - You have a manual fallback process for facility staff.
Error handling and retries
400,401,403,404,409, and422responses are surfaced to operators or support teams rather than retried blindly.429,500,502,503, and504responses use bounded retry logic with backoff.- Repeated failures create an alert in your system.
- The integration never drops failed records silently.
Observability
- Your logs include endpoint, timestamp, facility identifier, source record ID, request outcome, and response body.
- Your support team can search by member ID, facility ID, check-in ID, or unlock event ID.
- You have a way to replay or reconcile failed syncs.
Production launch
- Performance Hub has confirmed your production access.
- At least one production facility has enabled your integration.
- Your production key is active.
- Your operational and technical contacts are current.
- Your support process is documented for customers.
After these checks are complete, your configured integration will appear in the Performance Hub partner directory inside the core Performance Hub platform.
Best Practices
Use these patterns to keep partner integrations predictable, observable, and safe for facilities.
Identify facilities consistently
Choose the linking method configured for your partner account and use it consistently:
- Direct Link - use the Performance Hub
facility_idreturned by the facilities endpoint. - Linking Identifier - use your own location identifier, such as a branch ID, location code, or store number.
Do not send both identifiers in the same request. Performance Hub resolves requests using the linking method configured for your partner account.
See Partner Linking Methods for setup guidance.
Batch writes carefully
The Partner API accepts JSON request bodies and is designed for batch-oriented sync workflows where documented. Keep batches bounded and retryable.
Default guidance:
- Use up to 1000 items per batch request for optimal performance.
- Keep payloads under 10MB.
- Stay within 5 requests per second per endpoint.
Rate limits are adjustable and can be configured on a case-by-case basis by your Performance Hub partner account manager. If you expect high-volume imports, launch traffic, or reporting backfills, agree the required throughput before the change window.
If you need to sync a large dataset, split it into deterministic chunks and log each chunk ID on your side. This makes failed retries easier to reason about.
Retry safely
Use exponential backoff for transient failures such as 429, 500, 502, 503, and 504.
Avoid tight retry loops. A good starting point is:
- Retry after 1 second.
- Retry after 2 seconds.
- Retry after 4 seconds.
- Stop and alert if the operation still fails.
For validation failures such as 400 or 422, fix the request before retrying.
Use idempotency where supported
The Door/Gate Controller unlock endpoint supports an optional idempotency_key. Reusing the same key for the same partner, facility, and door returns the existing result when one is available.
Use a stable key for the action being performed, for example a check-in ID or access event ID from your system.
Do not assume every write endpoint supports idempotency unless it is documented for that endpoint.
Keep source data clean
Send stable, normalized values wherever possible:
- Use consistent member, plan, facility, and check-in IDs from your source system.
- Use ISO 8601 timestamps for dates and times.
- Send phone numbers in international format where available.
- Send currencies using the fields documented for each endpoint.
- Avoid overloading free-text fields with data that belongs in structured fields.
Design for incremental and full syncs
Most partner integrations need both:
- Incremental syncs for day-to-day changes.
- Full reconciliation syncs to correct missed events, historical imports, or data drift.
Your integration should be able to resend the current state for a member, membership plan, or report snapshot without depending on a previous request having succeeded.
Treat access control as safety-critical
For Door/Gate Controller unlocks:
- Your system must decide whether the person is allowed to enter before calling Performance Hub.
- Performance Hub returns
200only after the on-site controller confirms the relay physically unlocked. - Most confirmations complete in 3-5 seconds.
- A timeout is an explicit failed unlock, not a background success.
- Retry only according to your own access and safety rules.
Always log the event_id and command_id returned by the unlock endpoint.
Monitor your integration
Use the Partner Console request logs during development and launch. In production, also maintain your own logs with:
- Request timestamp.
- Endpoint.
- Source record ID.
- Facility identifier.
- HTTP status code.
- Performance Hub response body or error message.
These fields make support and reconciliation much faster when a customer asks what happened.
Organisations
Represents the top-level business entity that operates one or more facilities integrated with the Performance Hub platform.
Endpoints
GET /partner/v1/organisations - List all organisations
The Organisation object
Attributes
org_id
stringrequiredUnique identifier for the organisation.
name
stringrequiredOrganisation name.
The Organisation object
{
"org_id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
"name": "FitLife Fitness Group"
}
List all organisations
Returns a list of organisations accessible to your partner account.
Returns
Returns a JSON object with a data property containing an array of Organisation objects.
Request
curl https://partner-api.performancehub.co/partner/v1/organisations \
-u sk_live_YOUR_PARTNER_SECRET_KEY:
Response
{
"data": [
{
"org_id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
"name": "FitLife Fitness Group"
},
{
"org_id": "6ba7b811-9dad-11d1-80b4-00c04fd430c8",
"name": "Wellness Studios Network"
}
]
}
Facilities
Represents a physical location, branch, club, gym, or studio where members can access services.
Endpoints
GET /partner/v1/facilities - List all facilities
The Facility object
Attributes
facility_id
stringrequiredUnique identifier for the facility.
org_id
stringrequiredUnique identifier for the parent organisation.
name
stringrequiredFacility name.
brand
stringoptionalBrand name used by the facility.
website_url
stringoptionalFacility website URL.
place_data
objectoptionalLocation data from Google Places API containing country, formatted address, Google Place ID, province, and city.
social_links
objectoptionalSocial media links for the facility.
timezone
stringoptionalIANA timezone identifier (e.g.,
"Australia/Sydney","America/New_York").
The Facility object
{
"facility_id": "550e8400-e29b-41d4-a716-446655440000",
"org_id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
"name": "FitLife Downtown",
"brand": "FitLife",
"website_url": "https://fitlife.com/downtown",
"social_links": {
"instagram": {
"handle": "@fitlifedowntown"
},
"facebook": {
"handle": "FitLifeDowntown"
}
},
"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"
}
List all facilities
Returns a list of facilities accessible to your partner account.
Returns
Returns a JSON object with a data property containing an array of Facility objects.
Request
curl https://partner-api.performancehub.co/partner/v1/facilities \
-u sk_live_YOUR_PARTNER_SECRET_KEY:
Response
{
"data": [
{
"facility_id": "550e8400-e29b-41d4-a716-446655440000",
"org_id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
"name": "FitLife Downtown",
"brand": "FitLife",
"website_url": "https://fitlife.com/downtown",
"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"
}
]
}
Membership Plans
Defines a purchasable offering from an organisation or facility, including services, entitlements, schedule, and pricing.
Endpoints
POST /partner/v1/membership-plans - Save a membership plan
The Membership Plan object
Attributes
membership_plan_id
stringrequiredUnique identifier for the membership plan.
facility_id
stringeither/orProvide the facility identifier type configured for your integration: use facility_id for direct-link integrations, or linking_identifier for linking-identifier integrations. Do not send both; the API uses the identifier type configured for your partner account and ignores the other one. Learn moreUnique identifier of the facility from Performance Hub.
linking_identifier
stringeither/orProvide the facility identifier type configured for your integration: use facility_id for direct-link integrations, or linking_identifier for linking-identifier integrations. Do not send both; the API uses the identifier type configured for your partner account and ignores the other one. Learn moreUnique identifier value for each location that the partner uses (e.g., "Branch ID", "Location Code", "Store Number"). Learn more
name
stringrequiredHuman-readable plan name (e.g.,
"Unlimited Monthly","10 Class Pack").billing_cycle
stringoptionalBilling frequency. One of
weekly,fortnightly,monthly,annually, orone_time.price
integeroptionalBase cost in smallest currency unit (cents for USD/AUD).
currency
stringoptionalISO 4217 currency code (e.g.,
"AUD","USD").description
stringoptionalOptional marketing or internal description.
active_members
integeroptionalNumber of active members using this membership plan
is_recurring
booleanoptionalWhether the plan auto-renews.
is_trial
booleanoptionalWhether this is a trial offering.
visible_to_public
booleanoptionalWhether the plan is available for self-service purchase.
duration_days
integeroptionalNumber of days the membership plan is valid for.
access_zones
arrayoptionalArray of access zones included in the membership plan. Each zone can define its own access hours. See Access Zones for details.
class_limit
integeroptionalMaximum number of classes allowed (null for unlimited).
The Membership Plan object
{
"membership_plan_id": "plan_99999",
"facility_id": "550e8400-e29b-41d4-a716-446655440000",
// "linking_identifier": "branch_downtown", // If using linking identifier
"name": "Unlimited Monthly",
"description": "Unlimited access to all gym facilities and group classes",
"billing_cycle": "monthly",
"price": 8900,
"currency": "AUD",
"duration_days": 30,
"is_recurring": true,
"is_trial": false,
"visible_to_public": true,
"active_members": 245,
"access_zones": [
{
"name": "Main Gym Floor",
"description": "Full access to cardio and weight training equipment",
"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": [["06:00", "20:00"]],
"sun": [["07:00", "18:00"]]
}
},
{
"name": "Group Fitness Studio",
"description": "Access to group fitness classes",
"access_hours": {
"sat": [["06:00", "20:00"]],
"sun": [["07:00", "18:00"]]
}
}
],
"class_limit": null
}
Access Zones
Access zones define specific areas within a facility where a membership plan grants access. Each zone can have its own access hours, allowing different time restrictions per area.
Structure
Each access zone includes:
name
stringrequiredThe name of the zone (e.g., "Main Gym Floor", "Group Fitness Studio").
description
stringoptionalDescription of what's included in that zone.
access_hours
objectoptionalAccess hours specific to this zone. See Access Hours for the time range format.
Example
"access_zones": [
{
"name": "Main Gym Floor",
"description": "Full access to cardio and weight training equipment",
"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": [["06:00", "20:00"]],
"sun": [["07:00", "18:00"]]
}
},
{
"name": "Group Fitness Studio",
"description": "Access to group fitness classes",
"access_hours": {
"sat": [["06:00", "20:00"]],
"sun": [["07:00", "18:00"]]
}
}
]
Access Hours
Access hours specify when members can access a specific zone during each day of the week. Access hours are defined per access zone, allowing different time restrictions for different areas of a facility.
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"]]
}
Each day is an array of time ranges in HH:MM format (24-hour clock). An empty array [] means no access on that day. Days that are omitted are treated the same as an empty array.
Example Use Cases
// Early Bird Access
// Morning-only gym access, weekdays only:
"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"]]
}
// Off-Peak Plan
// Avoids peak hours, weekdays only:
"access_hours": {
"mon": [["10:00", "12:00"], ["14:00", "16:00"]],
"tue": [["10:00", "12:00"], ["14:00", "16:00"]],
"wed": [["10:00", "12:00"], ["14:00", "16:00"]],
"thu": [["10:00", "12:00"], ["14:00", "16:00"]],
"fri": [["10:00", "12:00"], ["14:00", "16:00"]]
}
// Weekend Warrior
// Full-day access on weekends:
"access_hours": {
"sat": [["08:00", "20:00"]],
"sun": [["08:00", "20:00"]]
}
// 24/7 Access (Most common use case)
// Always-on access, unlimited:
"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"]]
}
Per-Zone Example
"access_zones": [
{
"name": "Main Gym Floor",
"description": "Full access to cardio and weight training equipment",
"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": [["06:00", "20:00"]],
"sun": [["07:00", "18:00"]]
}
},
{
"name": "Swimming Pool",
"description": "Access to 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"]]
}
}
]
Save a membership plan
Creates or updates membership plan records. The API determines whether to create or update based on the membership_plan_id.
Parameters
membership_plans
arrayrequiredArray of Membership Plan objects to save. Recommended maximum: 1000 items per request for optimal performance. The API automatically batches items for processing. Each item must include either
facility_id(required if not usinglinking_identifier) orlinking_identifier(required if not usingfacility_id).
Returns
Returns a simple message confirming the sync operation.
Request
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",
// "linking_identifier": "branch_downtown", // If using linking identifier
"name": "Unlimited Monthly",
"description": "Unlimited access to all gym facilities and group classes",
"billing_cycle": "monthly",
"price": 8900,
"currency": "AUD",
"duration_days": 30,
"is_recurring": true,
"is_trial": false,
"visible_to_public": true,
"active_members": 245,
"access_zones": [
{
"name": "Main Gym Floor",
"description": "Full access to cardio and weight training equipment",
"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": [["06:00", "20:00"]],
"sun": [["07:00", "18:00"]]
}
},
{
"name": "Group Fitness Studio",
"description": "Access to group fitness classes",
"access_hours": {
"sat": [["06:00", "20:00"]],
"sun": [["07:00", "18:00"]]
}
}
],
"class_limit": null
}
]
}'
Response
Returns a success message with metadata about the sync operation.
{
"message": "Membership plan sync successful.",
"metadata": {
"success": 98,
"skipped": 2,
"skipped_items": [
{
"membership_plan_id": "plan_456",
"facility_id": null,
"reason": "Missing facility_id"
}
]
}
}
Metadata fields:
- success - Number of membership plans successfully processed
- skipped - Number of plans skipped (if any)
- skipped_items - Array of skipped plans with reasons (if any)
- dry-run - Boolean flag if using dryrun key type (if applicable)
Members
Represents an individual customer of a facility. Can be a lead, prospect, recurring customer, expired member, or blocked user.
Endpoints
POST /partner/v1/members - Save a member
The Member object
Attributes
member_id
stringrequiredUnique identifier for the member.
facility_id
stringeither/orProvide the facility identifier type configured for your integration: use facility_id for direct-link integrations, or linking_identifier for linking-identifier integrations. Do not send both; the API uses the identifier type configured for your partner account and ignores the other one. Learn moreUnique identifier of the facility from Performance Hub.
linking_identifier
stringeither/orProvide the facility identifier type configured for your integration: use facility_id for direct-link integrations, or linking_identifier for linking-identifier integrations. Do not send both; the API uses the identifier type configured for your partner account and ignores the other one. Learn moreUnique identifier value for each location that the partner uses (e.g., "Branch ID", "Location Code", "Store Number"). Learn more
first_name
stringrequiredMember's first name.
last_name
stringrequiredMember's last name.
email
stringoptionalEmail address.
mobile_phone
stringoptionalMobile phone number in E.123 format (e.g.,
"+1 415 555 2671").address
objectoptionalPhysical address object with the following properties:
address_line_1(string) - Primary street addressaddress_line_2(string, optional) - Secondary address linecity(string) - City namestate(string) - State/province codepostal_code(string) - Postal/ZIP codecountry(string) - ISO 3166-1 alpha-2 country code (e.g., "AU", "US")country_name(string, optional) - Full country name
date_of_birth
stringoptionalBirth date in
YYYY-MM-DDformat.gender
stringoptionalOne of
male,female,non_binary,prefer_not_to_say, orunknown.type
stringoptionalMember type (e.g.
staff,member,prospect).tags
arrayoptionalQuick helper strings or texts to categorise and identify specific members (e.g.
["vip", "personal-training", "student"]).membership_status
stringoptionalCurrent membership status (e.g.,
active,expired,on_hold).membership_plans
arrayoptionalArray of membership plans associated with the member.
profile_picture
stringoptionalBase64-encoded profile picture (optional).
created
stringoptionalISO 8601 timestamp when the member was created.
updated
stringoptionalISO 8601 timestamp when the member was last updated.
The Member object
{
"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@email.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",
"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
}
]
}
Save a member
Creates or updates member records. The API determines whether to create or update based on the member_id.
Parameters
members
arrayrequiredArray of Member objects to save. Recommended maximum: 1000 items per request for optimal performance. The API automatically batches items for processing. Each item must include either
facility_id(required if not usinglinking_identifier) orlinking_identifier(required if not usingfacility_id).
Returns
Returns a simple message confirming the sync operation.
Request
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@email.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",
"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
}
]
}
]
}'
Response
Returns a success message with metadata about the sync operation.
{
"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"
}
]
}
}
Metadata fields:
- success - Number of members successfully processed
- skipped - Number of members skipped (if any)
- skipped_items - Array of skipped members with reasons (if any)
- dry-run - Boolean flag if using dryrun key type (if applicable)
Check-Ins
Represents a record of a person being present at a facility, class, or activity. Used for tracking attendance, usage analytics, and improving visual detection accuracy.
Endpoints
POST /partner/v1/check-ins - Save check-ins
The Check-In object
Attributes
check_in_id
stringoptionalUnique identifier for the check-in. Optional - auto-generated from
member_idandtimestamppair if not provided.member_id
stringrequiredUnique identifier of the member.
facility_id
stringeither/orProvide the facility identifier type configured for your integration: use facility_id for direct-link integrations, or linking_identifier for linking-identifier integrations. Do not send both; the API uses the identifier type configured for your partner account and ignores the other one. Learn moreUnique identifier of the facility from Performance Hub.
linking_identifier
stringeither/orProvide the facility identifier type configured for your integration: use facility_id for direct-link integrations, or linking_identifier for linking-identifier integrations. Do not send both; the API uses the identifier type configured for your partner account and ignores the other one. Learn moreUnique identifier value for each location that the partner uses (e.g., "Branch ID", "Location Code", "Store Number"). Learn more
check_in_type
stringoptionalType of visit. One of
member,class,staff,guest, ortrial.source
stringoptionalHow the check-in was captured. Common values include
manual,tag,rfid,kiosk,app. Additional values likedoor_readerorbookingmay also be used.class_id
stringoptionalOptional. If tied to a class booking or attendance.
timestamp
stringrequiredISO 8601 format timestamp of when the check-in occurred.
The Check-In object
{
// "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"
}
Save check-ins
Creates check-in records. The API automatically deduplicates based on member, facility, and timestamp.
Parameters
check_ins
arrayrequiredArray of Check-In objects to save. Recommended maximum: 1000 items per request for optimal performance. The API automatically batches items for processing. Each item must include either
facility_id(required if not usinglinking_identifier) orlinking_identifier(required if not usingfacility_id).
Returns
Returns a simple message confirming the sync operation.
Request
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"
}
]
}'
Response
Returns a success message with metadata about the sync operation.
{
"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"
}
]
}
}
Metadata fields:
- success - Number of check-ins successfully processed
- skipped - Number of check-ins skipped (if any)
- skipped_items - Array of skipped check-ins with reasons (if any)
- dry-run - Boolean flag if using dryrun key type (if applicable)
Access Control
The Partner API can trigger Performance Hub Door/Gate Controller hardware for facilities where your integration is enabled.
Use this API when your member management system has already decided that a person is allowed to enter. Performance Hub does not evaluate membership status, access hours, door-zone rules, fraud checks, or suspension logic. Your system remains the authority for those decisions.
The unlock request is synchronous. Performance Hub sends the command to the on-site controller over MQTT and returns 200 only after the device confirms that the relay physically unlocked. Most confirmations should complete in 3-5 seconds. If no confirmation is received within the timeout window, the API returns an explicit failure.
Endpoints
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
The Door/Gate Controller object
Attributes
door_id
stringrequiredUnique identifier for the Door/Gate Controller. Store this in your system after discovery and use it when calling the unlock endpoint.
facility_id
stringrequiredPerformance Hub facility ID.
linking_identifier
stringoptionalPartner facility identifier when your integration uses linking identifiers. Learn more
name
stringrequiredHuman-readable device name configured in Performance Hub.
zone
stringoptionalDoor zone or location, such as
Entrance.status
stringrequiredonlineoroffline.relay_state
stringoptionalLatest known relay state, such as
lockedorunlocked.maintenance_mode
stringrequiredCurrent maintenance mode. One of
off,force-open, orforce-closed.hold_time_seconds
integerrequiredDefault unlock hold time configured for the door.
last_seen
stringoptionalISO timestamp for the latest device metadata update.
The Door/Gate Controller object
{
"door_id": "577393ce6ec584aa4e2e2b1d1e73934c",
"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"
}
List Door/Gate Controllers
Returns Door/Gate Controllers available to your integration.
If neither facility_id nor linking_identifier is provided, the API returns Door/Gate Controllers across all facilities linked to your partner account.
Parameters
facility_id
stringoptional either/orProvide the facility identifier type configured for your integration: use facility_id for direct-link integrations, or linking_identifier for linking-identifier integrations. Do not send both; the API uses the identifier type configured for your partner account and ignores the other one. Learn morePerformance Hub facility ID. Use this for direct-link integrations.
linking_identifier
stringoptional either/orProvide the facility identifier type configured for your integration: use facility_id for direct-link integrations, or linking_identifier for linking-identifier integrations. Do not send both; the API uses the identifier type configured for your partner account and ignores the other one. Learn moreYour own facility/location identifier. Use this when your integration is configured for linking identifiers.
Returns
Returns an array of Door/Gate Controller objects.
Request
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:
Response
{
"data": [
{
"door_id": "577393ce6ec584aa4e2e2b1d1e73934c",
"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"
}
]
}
Get Door/Gate Controller status
Retrieves the latest known state and basic configuration for a single Door/Gate Controller.
Provide a facility identifier so Performance Hub can verify that the door belongs to a facility your integration can access.
Parameters
door_id
stringrequiredDoor/Gate Controller ID returned by the list endpoint.
facility_id
stringeither/orProvide the facility identifier type configured for your integration: use facility_id for direct-link integrations, or linking_identifier for linking-identifier integrations. Do not send both; the API uses the identifier type configured for your partner account and ignores the other one. Learn morePerformance Hub facility ID. Required for direct-link integrations.
linking_identifier
stringeither/orProvide the facility identifier type configured for your integration: use facility_id for direct-link integrations, or linking_identifier for linking-identifier integrations. Do not send both; the API uses the identifier type configured for your partner account and ignores the other one. Learn morePartner facility identifier. Required for linking-identifier integrations.
Returns
Returns a Door/Gate Controller object.
Request
curl -X GET "https://partner-api.performancehub.co/partner/v1/access-control/doors/577393ce6ec584aa4e2e2b1d1e73934c?facility_id=550e8400-e29b-41d4-a716-446655440000" \
-u sk_live_YOUR_PARTNER_SECRET_KEY:
Response
{
"data": {
"door_id": "577393ce6ec584aa4e2e2b1d1e73934c",
"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"
}
}
Unlock a Door/Gate Controller
Sends an unlock command to the Door/Gate Controller and waits for the physical relay to confirm it has unlocked.
Your system must decide whether the person is authorised before calling this endpoint. Performance Hub only verifies the partner key, facility access, door ownership, and device state.
Parameters
door_id
stringrequiredDoor/Gate Controller ID returned by the list endpoint.
facility_id
stringeither/orProvide the facility identifier type configured for your integration: use facility_id for direct-link integrations, or linking_identifier for linking-identifier integrations. Do not send both; the API uses the identifier type configured for your partner account and ignores the other one. Learn morePerformance Hub facility ID. Required for direct-link integrations.
linking_identifier
stringeither/orProvide the facility identifier type configured for your integration: use facility_id for direct-link integrations, or linking_identifier for linking-identifier integrations. Do not send both; the API uses the identifier type configured for your partner account and ignores the other one. Learn morePartner facility identifier. Required for linking-identifier integrations.
member_id
stringrequiredPartner member ID. This is used for audit logging and later data linking.
first_name
stringrequiredFirst name of the person opening the door.
last_name
stringrequiredLast name of the person opening the door.
full_name
stringoptionalOptional. If omitted, Performance Hub combines
first_nameandlast_name.check_in_id
stringoptionalOptional check-in ID from your system for correlation.
idempotency_key
stringoptionalOptional replay-protection key. Reusing the same key for the same partner, facility, and door returns the existing result when available.
Returns
Returns 200 only when the device confirms the relay physically unlocked. The door uses the hold time configured in Performance Hub Device Management; partners cannot override relay timing per request. Most confirmations should complete in 3-5 seconds. Treat the documented timeout as an explicit failed unlock and retry only according to your own safety rules.
Common failures:
403 integration_not_enabled- your integration is not enabled for the facility.409 maintenance_mode_active- facility staff have enabled maintenance mode for the door.503 device_offline- the Door/Gate Controller is offline or stale.504 unlock_confirmation_timeout- the command was sent but no matching confirmation was received before timeout.
Request
curl -X POST https://partner-api.performancehub.co/partner/v1/access-control/doors/577393ce6ec584aa4e2e2b1d1e73934c/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": "Smith",
"full_name": "Jane Smith",
"source": "door_reader",
"idempotency_key": "unlock_20260501_0001"
}'
Response
{
"status": "unlocked",
"door_id": "577393ce6ec584aa4e2e2b1d1e73934c",
"facility_id": "550e8400-e29b-41d4-a716-446655440000",
"event_id": "2d98e9ff-3a2a-46d4-a22f-5f23f7d75b11",
"command_id": "9d4d013d-d929-4a87-8b52-6cc66f56ff07",
"hold_time_seconds": 10,
"confirmed_at": "2026-05-01T04:30:00.000Z"
}
Failure response
{
"status": "failed",
"reason": "device_offline",
"door_id": "577393ce6ec584aa4e2e2b1d1e73934c",
"facility_id": "550e8400-e29b-41d4-a716-446655440000",
"event_id": "2d98e9ff-3a2a-46d4-a22f-5f23f7d75b11"
}
Facility Reports
A point-in-time record capturing key operational and financial metrics for a facility during a specific period.
Endpoints
POST /partner/v1/report-snapshots - Save report snapshots
The Report Snapshot object
Attributes
facility_id
stringeither/orProvide the facility identifier type configured for your integration: use facility_id for direct-link integrations, or linking_identifier for linking-identifier integrations. Do not send both; the API uses the identifier type configured for your partner account and ignores the other one. Learn moreUnique identifier of the facility from Performance Hub.
linking_identifier
stringeither/orProvide the facility identifier type configured for your integration: use facility_id for direct-link integrations, or linking_identifier for linking-identifier integrations. Do not send both; the API uses the identifier type configured for your partner account and ignores the other one. Learn moreUnique identifier value for each location that the partner uses (e.g., "Branch ID", "Location Code", "Store Number"). Learn more
start_date
stringrequiredSnapshot period start date in
YYYY-MM-DDformat.end_date
stringrequiredSnapshot period end date in
YYYY-MM-DDformat.metrics
objectrequiredMetrics object containing member and revenue data for the period.
The Report Snapshot object
{
"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"
}
}
}
Save report snapshots
Submits operational and financial metrics for a facility during a specific period.
Parameters
snapshots
arrayrequiredArray of Report Snapshot objects to save. Maximum 25 items per request. Each item must include either
facility_id(required if not usinglinking_identifier) orlinking_identifier(required if not usingfacility_id).
Returns
Returns a simple message confirming the sync operation.
Request
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"
}
}
}
]
}'
Response
{
"message": "Report snapshot sync successful."
}
Errors
The Partner API uses standard HTTP status codes and JSON response bodies to explain why a request failed.
Error response shape
Most API errors return a JSON body with a message and, where available, structured details.
Status codes
Retry guidance
Retry these with bounded exponential backoff:
429500502503504
Do not blindly retry these:
400401403404409422
For access control, always treat timeout and offline responses as failed unlocks unless your own access rules and safety processes say otherwise.
Support details to include
When contacting support, include:
- Endpoint and HTTP method.
- Timestamp and timezone.
- Partner key ID, not the secret key.
- Facility identifier used.
- Source record ID from your system.
- Response status and body.
event_idorcommand_idwhere available.
{
"success": false,
"message": "Request body.members[0].member_id is required"
}
Some domain-specific endpoints return an explicit status and reason. For example, access-control failures include fields such as reason, door_id, facility_id, and event_id.
{
"status": "failed",
"reason": "device_offline",
"door_id": "577393ce6ec584aa4e2e2b1d1e73934c",
"facility_id": "550e8400-e29b-41d4-a716-446655440000",
"event_id": "2d98e9ff-3a2a-46d4-a22f-5f23f7d75b11"
}
400 Bad Request
The request is malformed or missing required fields. Fix the request before retrying.
401 Unauthorized
Authentication failed. Check that you are using HTTP Basic Auth with your API secret key as the username and an empty password.
403 Forbidden
The key is valid but the operation is not allowed. Common causes include using a read-only key for a write operation or attempting to access a facility where your integration is not enabled.
404 Not Found
The requested resource was not found or is not available to your integration.
409 Conflict
The request conflicts with the current resource state. For access control, this can include a Door/Gate Controller being in maintenance mode.
422 Unprocessable Entity
The request is valid JSON but fails semantic validation. Fix the data before retrying.
429 Too Many Requests
The integration exceeded the documented rate limit. Retry with exponential backoff.
500 Internal Server Error
Performance Hub could not complete the request because of an internal error. Retry with backoff. If the problem continues, contact support with the endpoint, timestamp, and response body.
503 Service Unavailable
A dependent service or device is unavailable. For Door/Gate Controller unlocks, this can mean the controller is offline.
504 Gateway Timeout
The operation timed out. For Door/Gate Controller unlocks, this means the unlock was not confirmed before the timeout window.
Versioning
The Partner API is versioned in the URL. The current version is:
Change policy
Performance Hub aims to make additive, backward-compatible changes wherever possible.
Examples of backward-compatible changes:
- Adding a new optional field to a request.
- Adding a new field to a response.
- Adding a new endpoint.
- Adding a new enum value where clients are expected to handle unknown values.
- Improving validation messages without changing the status code contract.
Examples of breaking changes:
- Removing or renaming a field.
- Changing the type of a field.
- Making an optional request field required.
- Removing an endpoint.
- Changing the meaning of an existing status code or domain-specific
reason.
Deprecations
When a breaking change is required, Performance Hub will avoid changing the existing version in place where possible. Instead, we will introduce a new version or migration path and communicate the change to affected partners.
Deprecation notices can include:
- A changelog entry.
- Direct partner communication.
- Notes in the Partner Console.
- Migration guidance in the docs.
Client recommendations
Build clients that tolerate additive changes:
- Ignore response fields you do not use.
- Treat unknown enum values as unsupported rather than crashing.
- Avoid strict response equality checks.
- Log unrecognized values so you can update your integration intentionally.
OpenAPI specifications
Use the published OpenAPI specifications to generate clients, validate requests, and track API shape changes over time.
https://partner-api.performancehub.co/partner/v1/
Changelog
This changelog records notable Partner API and Partner Console changes that affect integration behaviour.
2026-05-06
2026-05-01
Change categories
Future entries use these categories:
- Added - new endpoint, field, guide, or capability.
- Changed - behaviour or documentation changed without removing support.
- Deprecated - feature remains available but has a planned migration path.
- Removed - feature or endpoint removed.
- Fixed - bug fix or documentation correction.
- Security - authentication, authorization, data handling, or key-management change.
Added
- Added partner program documentation covering partner types, onboarding, best practices, go-live readiness, errors, versioning, and support.
- Added a dedicated Become a Partner enquiry flow for prospective technical and commercial partners.
- Added documentation for how approved partner integrations appear inside the Performance Hub partner directory in the core Performance Hub platform.
Added
- Added Door/Gate Controller access-control documentation, including list, status, and unlock operations.
- Added synchronous unlock behaviour documentation: the API returns success only after the on-site controller confirms the relay physically unlocked.
- Added optional
idempotency_keysupport documentation for Door/Gate Controller unlock requests.