简介

Performance Hub Partner API 使外部合作伙伴平台能够与 Performance Hub 的核心模块无缝集成。该 API 支持计算机视觉、分析、会员访问日志记录和设施洞察。

请求格式

API 接受 JSON 编码的请求正文,并返回 JSON 编码的响应。

速率限制

为确保公平使用和系统稳定,Partner API 账户的初始默认限制如下:

  • 每个端点每秒 5 个请求
  • 为获得最佳性能,每个批量请求建议最多 1000 个项目
  • 负载大小上限为 10MB

速率限制可以调整,并可由您的 Performance Hub 合作伙伴客户经理根据具体情况进行配置。如果您的集成在上线、迁移、报告回填或高流量设施方面需要更高的吞吐量,请在入驻期间或计划的变更窗口之前提出。

基础 URL

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

身份验证

访问 Partner API 需要使用 API 密钥进行身份验证。请通过 Partner Console 生成和管理您的密钥。

API 密钥是您访问合作伙伴资源的凭据。每个密钥只能访问特定的组织数据,并可在需要时立即停用。

**请谨慎处理您的 API 密钥,它们可提供对您账户的完全访问权限!**切勿在公共代码库、客户端应用程序或任何可能导致泄露的地方暴露这些密钥。

使用 HTTP Basic Auth 对请求进行身份验证,将您的 API 密钥作为用户名传递,密码留空。

**API 仅接受安全的 HTTPS 连接。**纯 HTTP 请求将被拒绝,缺少正确身份验证凭据的请求也会被拒绝。

请求示例

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.

验证密钥

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

上线检查清单

在为生产设施启用合作伙伴集成之前,请使用此检查清单。

Partner Console 设置

  • 您的合作伙伴资料已填写完整。
  • 您的徽标 URL、网站、类别和说明准确无误。
  • 已配置您的数据关联方式:Direct Link 或 Linking Identifier。
  • 已至少使用一个真实设施测试设施关联。
  • 正在使用正确的密钥类型:
    • Dryrun:用于非破坏性的写入测试。
    • Read-only:用于安全地使用数据。
    • Live:仅在您准备好影响生产数据时使用。

身份验证和密钥管理

  • 密钥仅存储在服务器端。
  • 密钥未嵌入客户端应用程序、移动应用、公共代码库或支持工单中。
  • 已测试密钥轮换和吊销。
  • 您的团队清楚每个环境使用的是哪个密钥。

数据验证

  • 您调用的每个端点的必填字段均已提供。
  • 设施标识符与您配置的关联方式相符。
  • 来自您系统的 ID 稳定,不会在多次同步之间发生变化。
  • 大规模导入已按文档所述的限制拆分为批次。
  • 可以识别并重新发送失败的批次项目。

端点测试

上线前,请测试您的集成所依赖的每个端点:

  • 可以读取组织和设施。
  • 可以保存和更新会员。
  • 会员计划、访问区域和访问时间可正确同步。
  • 签到被接受,并可关联回您的系统。
  • 报告快照使用预期的报告周期和指标。
  • 在适用情况下,已在真实硬件上测试门/闸机控制器流程。

Access Time Window 准备情况

如果集成提供 Access Time Windows:

  • 绝对时间窗口和每周时间窗口示例均通过生产方认证检查清单。
  • 纪元时间为不带引号的整数 Unix 秒;已测试精确的 [from, to) 边界。
  • 已验证 UTC 默认值、集成的自定义 IANA 时区以及相关的夏令时切换。
  • 使用一个持久的、单调递增的会员/源修订序列来协调增量更新、对账和重试。
  • 运营人员了解省略、完全替换、幂等、冲突、过时以及显式 [] 的行为。
  • 每个 scope_key(包括 default)都有经批准的 Performance Hub 映射;已测试未知密钥会按拒绝处理(fail closed)。
  • 已配置集成的预期刷新频率、最大源数据时效、源数据过时时的行为以及警报。
  • 已证明上游获取失败时不会发出空快照或部分快照。
  • 暂存序列的收敛、取消/撤销以及实体门的开始/结束边界均达到商定的目标。
  • 已验证常规规则和永久授权可作为后备途径,并且时间窗口无法绕过用户停用、blockAllAccess、维护或地理围栏。

门禁控制准备情况

对于门禁控制集成:

  • 您的系统在调用 Performance Hub 之前作出访问决策。
  • 集成能够处理 device_offline、maintenance_mode_active 和 unlock_confirmation_timeout。
  • 运营人员了解超时表示解锁未得到确认。
  • 您的日志会存储返回的 event_id 和 command_id。
  • 您为设施员工准备了手动后备流程。

错误处理和重试

  • 400、401、403、404、409 和 422 响应会呈现给运营人员或支持团队,而不是盲目重试。
  • 429、500、502、503 和 504 响应使用带退避的有限重试逻辑。
  • 重复失败会在您的系统中触发警报。
  • 集成绝不会静默丢弃失败的记录。

可观测性

  • 您的日志包含端点、时间戳、设施标识符、源记录 ID、请求结果和响应正文。
  • 您的支持团队可以按会员 ID、设施 ID、签到 ID 或解锁事件 ID 进行搜索。
  • 您有办法重放或对账失败的同步。

生产上线

  • Performance Hub 已确认您的生产访问权限。
  • 至少有一个生产设施已启用您的集成。
  • 您的生产密钥处于有效状态。
  • 您的运营联系人和技术联系人信息是最新的。
  • 您已为客户记录支持流程。

完成这些检查后,您配置的集成将出现在 Performance Hub 核心平台内的 Performance Hub 合作伙伴目录中。

最佳实践

采用以下模式,可使合作伙伴集成保持可预测、可观测,并确保设施的安全。

一致地标识设施

选择为您的合作伙伴账户配置的关联方式,并始终如一地使用:

  • Direct Link:使用设施端点返回的 Performance Hub facility_id。
  • Linking Identifier:使用您自己的位置标识符,例如分店 ID、位置代码或门店编号。

请勿在同一请求中同时发送两种标识符。Performance Hub 会使用为您的合作伙伴账户配置的关联方式解析请求。

有关设置指南,请参阅合作伙伴关联方式。

谨慎进行批量写入

Partner API 接受 JSON 请求正文,并在文档注明的情况下专为面向批量的同步流程而设计。请控制批次大小,并确保批次可重试。

默认建议:

  • 为获得最佳性能,每个批量请求最多 1000 个项目。
  • 负载大小保持在 10MB 以下。
  • 不超过每个端点每秒 5 个请求。

速率限制可以调整,并可由您的 Performance Hub 合作伙伴客户经理根据具体情况进行配置。如果您预计会有大量导入、上线流量或报告回填,请在变更窗口之前商定所需的吞吐量。

如果需要同步大型数据集,请将其拆分为确定性的分块,并在您这一侧记录每个分块 ID。这样更容易分析失败的重试。

安全地重试

对于 429、500、502、503 和 504 等暂时性故障,请使用指数退避。

避免密集的重试循环。建议从以下方式开始:

  1. 1 秒后重试。
  2. 2 秒后重试。
  3. 4 秒后重试。
  4. 如果操作仍然失败,则停止并发出警报。

对于 400 或 422 等验证失败,请先修正请求再重试。

在支持的情况下使用幂等性

门/闸机控制器解锁端点支持可选的 idempotency_key。对同一合作伙伴、设施和门重复使用相同的密钥时,如有现有结果,将返回该结果。

为所执行的操作使用稳定的密钥,例如您系统中的签到 ID 或访问事件 ID。

除非文档注明某个写入端点支持幂等性,否则请勿假定所有写入端点都支持。

保持源数据整洁

尽可能发送稳定、规范化的值:

  • 使用源系统中一致的会员、计划、设施和签到 ID。
  • 日期和时间使用 ISO 8601 时间戳。
  • 尽可能以国际格式发送电话号码。
  • 使用各端点文档中注明的字段发送货币。
  • 避免在自由文本字段中塞入本应放在结构化字段中的数据。

同时设计增量同步和完整同步

大多数合作伙伴集成都需要两者:

  • 增量同步:用于日常变更。
  • 完整对账同步:用于纠正遗漏的事件、历史导入或数据偏差。

您的集成应能够重新发送会员、会员计划或报告快照的当前状态,而不依赖于之前的请求是否成功。

安全地发布 Access Time Windows

将每个会员的 access_time_windows 值视为一个完整的、独立修订的快照:

  • 在增量工作进程和对账工作进程之间协调一个单调递增的 access_time_windows_revision 序列。
  • 对于不确定或暂时失败的投递,使用相同的修订号和规范化负载进行重试。
  • 不更新 access_time_windows 时,请省略该字段。
  • 仅在从权威源成功获取数据并证明不再有任何时间窗口后,才发送 []。切勿将上游超时、部分结果或解析失败转化为撤销。
  • 保持 external_id 和 scope_key 稳定,并在投入生产前认证每个范围映射。
  • 根据为该集成商定的新鲜度策略监控源数据的时效。

有关完整快照、时区、夏令时、取消和测试向量,请参阅权威的 Access Time Windows 生产方指南。

将门禁控制视为安全关键功能

对于门/闸机控制器解锁:

  • 在调用 Performance Hub 之前,您的系统必须确定是否允许该人员进入。
  • 仅当现场控制器确认继电器已实际解锁后,Performance Hub 才会返回 200。
  • 大多数确认在 3-5 秒内完成。
  • 超时表示明确的解锁失败,而不是在后台成功。
  • 仅按照您自己的访问和安全规则进行重试。

始终记录解锁端点返回的 event_id 和 command_id。

监控您的集成

在开发和上线期间,请使用 Partner Console 请求日志。在生产环境中,还请维护您自己的日志,包含以下内容:

  • 请求时间戳。
  • 端点。
  • 源记录 ID。
  • 设施标识符。
  • HTTP 状态码。
  • Performance Hub 响应正文或错误消息。

当客户询问发生了什么情况时,这些字段可以大大加快支持和对账的速度。

组织

表示运营一个或多个已与 Performance Hub 平台集成的设施的顶级业务实体。

端点

GET /partner/v1/organisations - List all organisations

组织对象

属性

  • org_id string 必填

    组织的唯一标识符。

  • name string 必填

    组织名称。

组织对象

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

列出所有组织

返回您的合作伙伴账户可访问的组织列表。

返回值

返回一个 JSON 对象,其 data 属性包含组织对象数组。

请求

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

响应

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

设施

表示会员可以使用服务的实体场所,例如办公室、门店、场馆、校园、诊所或健身房。

端点

GET /partner/v1/facilities - List all facilities

设施对象

属性

  • facility_id string 必填

    设施的唯一标识符。

  • org_id string 必填

    上级组织的唯一标识符。

  • name string 必填

    设施名称。

  • brand string 可选

    设施使用的品牌名称。

  • website_url string 可选

    设施网站 URL。

  • place_data object 可选

    来自 Google Places API 的位置数据,包含国家/地区、格式化地址、Google Place ID、省/州和城市。

  • social_links object 可选

    设施的社交媒体链接。

  • timezone string 可选

    IANA 时区标识符(例如 "Australia/Sydney"、"America/New_York")。

设施对象

{
  "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"
}

列出所有设施

返回您的合作伙伴账户可访问的设施列表。

返回值

返回一个 JSON 对象,其 data 属性包含设施对象数组。

请求

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

响应

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

会员计划

定义组织或设施提供的可购买产品,包括服务、权益、时间安排和价格。

端点

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

会员计划对象

属性

  • membership_plan_id string 必填

    会员计划的唯一标识符。

  • facility_id string 二选一请提供为您的集成配置的设施标识符类型:直接关联集成使用 facility_id,关联标识符集成使用 linking_identifier。请勿同时发送两者;API 会使用为您的合作伙伴账户配置的标识符类型,并忽略另一个。了解详情

    Performance Hub 中设施的唯一标识符。

  • linking_identifier string 二选一请提供为您的集成配置的设施标识符类型:直接关联集成使用 facility_id,关联标识符集成使用 linking_identifier。请勿同时发送两者;API 会使用为您的合作伙伴账户配置的标识符类型,并忽略另一个。了解详情

    合作伙伴为每个位置使用的唯一标识符值(例如“Branch ID”“Location Code”“Store Number”)。了解详情

  • name string 必填

    易读的计划名称(例如 "Office tenant – business hours"、"Student – term access"、"Hotel guest"、"10 Class Pack")。

  • billing_cycle string 可选

    计费频率。取值为 weekly、fortnightly、monthly、annually 或 one_time 之一。

  • price integer 可选

    以最小货币单位表示的基础费用(USD/AUD 为分)。

  • currency string 可选

    ISO 4217 货币代码(例如 "AUD"、"USD")。

  • description string 可选

    可选的营销说明或内部说明。

  • active_members integer 可选

    使用此会员计划的活跃会员数量

  • is_recurring boolean 可选

    该计划是否自动续订。

  • is_trial boolean 可选

    是否为试用产品。

  • visible_to_public boolean 可选

    该计划是否可供自助购买。

  • duration_days integer 可选

    会员计划的有效天数。

  • access_zones array 可选

    会员计划包含的访问区域数组。每个区域都可以定义自己的访问时间。有关详细信息,请参阅访问区域。

  • class_limit integer 可选

    允许的最大课程数量(null 表示不限)。

会员计划对象

此示例使用 facility_id。对于关联标识符集成,请改为发送 "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
}

访问区域

访问区域定义设施内会员计划授予访问权限的特定区域。每个区域都可以有自己的访问时间,从而为不同区域设置不同的时间限制。

结构

每个访问区域包括:

  • name string 必填

    区域名称(例如“Level 3 Tenancy”“Library”“Guest Floors”“Main Gym Floor”)。

  • description string 可选

    该区域所含内容的说明。

  • access_hours object 可选

    此区域专用的访问时间。有关时间范围格式,请参阅访问时间。

示例

一栋为租户提供健身房的办公楼:在工作时间内可访问租用区域,从清晨到深夜可访问健身房。

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

访问时间

访问时间指定会员在一周中的每一天可以访问特定区域的时间。访问时间按访问区域定义,因此可以为设施的不同区域设置不同的时间限制。

结构

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

每一天都是一个由 HH:MM 格式(24 小时制)时间范围组成的数组。空数组 [] 表示当天不可访问。省略的日期与空数组的处理方式相同。

用例示例

**办公室租户 – 工作时间:**仅在工作日的工作时间内可访问。

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

**学生 – 学期访问:**校园图书馆在工作日开放(中午有休息时间),周六上午也开放。

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

**健身房 – 早鸟:**仅在工作日上午可访问。

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

**酒店住客 – 全天候:**始终可访问,这是最常见的用例。

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

按区域设置示例

一个酒店住客计划:客房楼层全天候可访问,泳池的开放时间较短:

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

保存会员计划

创建或更新会员计划记录。API 根据 membership_plan_id 确定是创建还是更新。

参数

  • membership_plans array 必填

    要保存的会员计划对象数组。为获得最佳性能,建议每个请求最多 1000 个项目。API 会自动对项目进行分批处理。每个项目必须包含 facility_id(未使用 linking_identifier 时必填)或 linking_identifier(未使用 facility_id 时必填)。

返回值

返回一条确认同步操作的简单消息。

请求

此示例使用 facility_id。对于关联标识符集成,请改为发送 "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
      }
    ]
  }'

响应

返回一条成功消息,其中包含有关同步操作的元数据。

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

元数据字段:

  • success:成功处理的会员计划数量
  • skipped:跳过的计划数量(如有)
  • skipped_items:跳过的计划及原因的数组(如有)
  • dry-run:使用 dryrun 密钥类型时的布尔标志(如适用)

会员

表示设施的单个客户。可以是潜在客户、意向客户、长期客户、已过期会员或被封禁用户。

会员更新插入(upsert)还可以携带一个完整的、带修订号的 access_time_windows 快照,其中包含绝对访问时间和每周重复访问时间。在生成这些字段之前,请参阅 Access Time Windows。它们是附加权限,不会取代设施的常规规则或永久授权。

端点

POST /partner/v1/members - Save a member

会员对象

属性

  • member_id string 必填

    会员的唯一标识符。

  • facility_id string 二选一请提供为您的集成配置的设施标识符类型:直接关联集成使用 facility_id,关联标识符集成使用 linking_identifier。请勿同时发送两者;API 会使用为您的合作伙伴账户配置的标识符类型,并忽略另一个。了解详情

    Performance Hub 中设施的唯一标识符。

  • linking_identifier string 二选一请提供为您的集成配置的设施标识符类型:直接关联集成使用 facility_id,关联标识符集成使用 linking_identifier。请勿同时发送两者;API 会使用为您的合作伙伴账户配置的标识符类型,并忽略另一个。了解详情

    合作伙伴为每个位置使用的唯一标识符值(例如“Branch ID”“Location Code”“Store Number”)。了解详情

  • first_name string 必填

    会员的名字。

  • last_name string 必填

    会员的姓氏。

  • email string 可选

    电子邮件地址。

  • mobile_phone string 可选

    E.123 格式的手机号码(例如 "+1 415 555 2671")。

  • address object 可选

    实际地址对象,包含以下属性:

    • address_line_1(string):主要街道地址
    • address_line_2(string,可选):地址第二行
    • city(string):城市名称
    • state(string):州/省代码
    • postal_code(string):邮政编码
    • country(string):ISO 3166-1 alpha-2 国家/地区代码(例如“AU”“US”)
    • country_name(string,可选):国家/地区全称
  • date_of_birth string 可选

    YYYY-MM-DD 格式的出生日期。

  • gender string 可选

    取值为 male、female、non_binary、prefer_not_to_say 或 unknown 之一。

  • type string 可选

    会员类型(例如 staff、member、prospect)。

  • tags array 可选

    用于对特定会员进行分类和识别的快捷辅助字符串或文本(例如 ["vip", "personal-training", "student"])。

  • membership_status string 可选

    当前会员状态(例如 active、expired、on_hold)。

  • membership_plans array 可选

    与会员关联的会员计划数组。

  • profile_picture string 可选

    Base64 编码的个人资料照片(可选)。

  • created string 可选

    会员创建时间的 ISO 8601 时间戳。

  • updated string 可选

    会员上次更新时间的 ISO 8601 时间戳。

  • access_time_windows array 可选

    由源拥有的绝对和/或每周重复 Access Time Windows 的完整快照。省略该字段将保持快照不变;使用更新的修订号发送空数组可将其撤销。有关结构、验证、范围映射和替换语义,请参阅 Access Time Windows。

  • access_time_windows_revision integer 提供 access_time_windows 时必填

    此会员/源序列的单调递增、非负且 JSON 安全的整数。只要存在 access_time_windows,此字段即为必填。

会员对象

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

访问时间窗口

Access Time Windows 允许合作伙伴会员携带由外部系统提供的临时或周期性访问权限。本页面是 access_time_windows 和 access_time_windows_revision 的权威生产方指南。

Access Time Windows 是仅用于允许的附加权限。有效的时间窗口可以允许访问,但无效、已过期、已过时或未映射的时间窗口不会拒绝常规规则或永久授权已允许的访问。用户停用、显式门禁封锁、维护模式、地理围栏、速率限制和控制器可用性仍然适用。

针对特定上游系统的实现属于单独的适配器。它们必须将其源数据转换为这一与供应商无关的约定,且不得改变字段的含义。

会员快照字段

  • access_time_windows array 可选

    此会员和合作伙伴源的完整 Access Time Window 快照。一个快照可以混合包含 absolute 和 weekly 时间窗口。省略该字段将保持已存储的快照不变;发送 [] 将撤销此源拥有的所有时间窗口。

  • access_time_windows_revision integer 提供 access_time_windows 时必填

    此会员/源修订序列的一个单调递增、非负且 JSON 安全的整数。只要存在 access_time_windows,此字段即为必填,且不得超过 9007199254740991。

每个快照最多接受 50 个时间窗口。external_id、scope_key 和 label 最多接受 120 个字符。绝对时间窗口的跨度最长为 90 天。每周中的每一天最多接受八个不重叠的时段。无效数据将被拒绝,而不会被截断或推测。

时间窗口结构

绝对时间窗口标识一个确切的时间区间:

完整的混合请求

此请求将会员之前由源拥有的快照替换为一个绝对时间窗口和一个每周时间窗口:

时间和边界规则

from、to、active_from 和 active_until 是以 Unix 秒表示的 JSON 整数,用于标识 UTC 时刻:

  • 发送不带引号的 JSON 整数。数字字符串、浮点数、RFC 3339 字符串和 Unix 毫秒值都会被拒绝。
  • 每个区间都是左闭右开区间:[from, to)。访问可以恰好在 from 开始;恰好在 to 时不再有效。
  • from 必须小于 to。当两个每周边界都存在时,active_from 必须小于 active_until。
  • 不要根据不带时区的本地日期/时间推导纪元时间。请先将源时间解析为 UTC 时刻,然后将 Unix 毫秒值除以 1000,并验证结果为整数。

时区和夏令时

timezone 必须是有效的 IANA 时区,例如 UTC、Australia/Perth 或 America/New_York。省略时默认为 UTC。

  • 绝对时间窗口:from 和 to 已经标识确切的 UTC 时刻。timezone 仅为显示和审计元数据;更改它绝不会使任一时刻发生偏移。
  • 每周时间窗口:timezone 定义用于评估 access_hours 的本地挂钟时间和夏令时规则。请勿预先将每周时段转换为 UTC。
  • 在夏令时开始(时钟拨快)时,该时区跳过的本地时间永远不会出现。
  • 在夏令时结束(时钟拨回)时,带有该重复本地时间的两个真实时刻都与每周时段匹配。
  • 即使每周时间窗口使用非 UTC 时区,active_from 和 active_until 仍然是 UTC 时刻。

access_hours 使用小写的 sun 到 sat。每个值是由 [start, end] 对组成的数组,采用补零的 24 小时制 HH:mm 格式。时段必须非空、有序且互不重叠。end 不包含在内。时段不能跨越午夜;请将跨夜的源区间拆分为第一天的较晚时段和第二天的较早时段。

稳定 ID 和范围映射

external_id 必须在逻辑时间窗口的整个生命周期内保持稳定,并在会员快照中保持唯一。当时间或标签发生变化时,请保持其稳定,以便运营人员和审计记录能够关联各个修订版本。请勿将其重复用于不相关的时间窗口。

scope_key 是您稳定的逻辑访问目标,默认为 default。设施管理员会将每个允许的键映射到 Performance Hub 中的整个设施、门或访问范围目标:

完整快照和修订

将这两个字段视为会员更新插入中单独进行版本控制的分区:

输入 结果
省略 access_time_windows 现有快照保持不变;无需修订号
存在且修订号更新 替换此会员/源已存储的整个快照
相同修订号且规范化负载相同 幂等重放;快照不变
相同修订号但规范化负载不同 冲突;对账后分配新的修订号
较旧的修订号 跳过过时快照;不能覆盖较新的状态
access_time_windows: [] 且修订号更新 显式撤销源拥有的所有时间窗口

快照是完整的,而不是补丁。如果修订版本 1842 包含时间窗口 A 和 B,那么仅包含 B 的修订版本 1843 将移除 A。

在 webhook 工作进程、轮询、重放和完整对账之间,为每个合作伙伴/会员维护一个协调一致的修订序列。建议使用持久的数据库序列。只有在每个写入方都进行协调并保证严格的顺序和唯一性时,才能将 Unix 毫秒值用作修订号;它是修订值,而不是纪元时间字段。

在获知 API 响应之前,请持久保存确切的请求和修订号。发生超时或暂时性错误后,请使用相同的修订号重试相同的规范化快照。不要仅因传输投递结果不确定就分配新的修订号。

取消、过期和上游故障

  • **取消一个时间窗口:**成功获取权威源状态,移除该时间窗口,然后使用更新的修订号发送剩余的完整快照。
  • **取消所有时间窗口:**使用更新的修订号发送 access_time_windows: []。
  • **让绝对时间窗口过期:**它在 to 时停止允许访问;之后发送一次不含已过期条目的对账,以保持快照整洁。
  • **结束每周时间窗口:**在更新的快照中将其移除;如果源具有已知的结束时刻,也可以使用 active_until。
  • **源获取失败或不完整:**不要发送 [],也不要发布部分快照。发出警报并重试获取。将上游故障转化为空快照会导致意外撤销访问权限。
  • **Partner API 请求未通过验证:**修正数据;仅当规范化快照发生变化时,才发送更新的修订号。对于暂时性故障,请使用原修订号重试。

源数据新鲜度根据每个集成承诺的投递和对账频率按集成进行配置。在激活之前,请商定最大源数据时效、超出时效时的处理方式、警报阈值,以及运营人员是否可以确认仅依赖每个时间窗口自身的边界。过时的源时间窗口永远不会成为拒绝规则;常规规则和永久授权仍是后备途径。

生产方算法

每次更新会员时,请使用以下与语言无关的工作流程:

认证检查清单

使用最终的 scope_key 映射,在暂存设施中完成以下检查:

  • 省略时区的绝对时间窗口被接受,并按 UTC 进行评估。
  • 使用自定义 IANA 时区的绝对时间窗口保留相同的 from/to 时刻。
  • 使用自定义 IANA 时区的每周时间窗口在夏令时开始和结束切换时都遵循本地挂钟时间。
  • 混合绝对/每周时间窗口的快照完全替换之前的快照。
  • 访问恰好在 from 开始、恰好在 to 停止;每周时段的结束时间同样不包含在内。
  • 在同一 external_id 下使用更新的修订号更新时间后生效。
  • 省略 access_time_windows 时,会更改其他会员字段而不更改时间窗口。
  • 重放相同的修订号/负载是幂等的。
  • 相同修订号/不同负载返回冲突,且不更改快照。
  • 乱序到达的较旧修订号被报告为过时,且不能回滚状态。
  • 更新的 [] 会撤销源拥有的时间窗口;上游获取失败时不发送任何内容。
  • 未知或未映射的 scope_key 按拒绝处理(fail closed),并生成运营人员可见的警告。
  • 源数据时效警报和已配置的过时源策略在商定的阈值下正常工作。
  • webhook 路径和完整对账路径收敛到相同的快照和修订顺序。
  • 序列投递在商定的目标时间内到达 Door & Gate Access。
  • 有效的时间窗口可以允许访问已映射的实体门,但无法绕过用户停用、blockAllAccess、维护或地理围栏。
  • 在时间窗口之前、之外和之后,常规规则和永久授权仍会允许其他方面符合条件的用户访问。

相关指南

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

必填字段为 external_id、kind、from 和 to。timezone、scope_key 和 label 为可选字段。

每周时间窗口标识按本地挂钟时间周期性重复的时间区间,并可选择以 UTC 时刻作为边界:

{
  "external_id": "weekly-early-access",
  "kind": "weekly",
  "timezone": "America/New_York",
  "access_hours": {
    "sun": [],
    "mon": [["06:00", "08:30"]],
    "tue": [["06:00", "08:30"]],
    "wed": [["06:00", "08:30"]],
    "thu": [["06:00", "08:30"]],
    "fri": [["06:00", "08:30"]],
    "sat": []
  },
  "active_from": 1790812800,
  "active_until": 1796083200,
  "scope_key": "main_entry",
  "label": "Weekday early access"
}

必填字段为 external_id、kind 和 access_hours。timezone、active_from、active_until、scope_key 和 label 为可选字段。

curl -X POST https://partner-api.performancehub.co/partner/v1/members \
  -u sk_live_YOUR_PARTNER_SECRET_KEY: \
  -H "Content-Type: application/json" \
  -d '{
    "members": [
      {
        "member_id": "member_11111",
        "facility_id": "550e8400-e29b-41d4-a716-446655440000",
        "first_name": "John",
        "last_name": "Smith",
        "access_time_windows_revision": 1842,
        "access_time_windows": [
          {
            "external_id": "access-4b1782",
            "kind": "absolute",
            "from": 1792053000,
            "to": 1792058400,
            "timezone": "Australia/Perth",
            "scope_key": "after_hours_entry",
            "label": "Temporary site access"
          },
          {
            "external_id": "weekly-early-access",
            "kind": "weekly",
            "timezone": "America/New_York",
            "access_hours": {
              "sun": [],
              "mon": [["06:00", "08:30"]],
              "tue": [["06:00", "08:30"]],
              "wed": [["06:00", "08:30"]],
              "thu": [["06:00", "08:30"]],
              "fri": [["06:00", "08:30"]],
              "sat": []
            },
            "active_from": 1790812800,
            "active_until": 1796083200,
            "scope_key": "main_entry",
            "label": "Weekday early access"
          }
        ]
      }
    ]
  }'

根据您配置的关联方式,使用 facility_id 或 linking_identifier。请勿同时发送两者。

纪元时间转换

2026-10-15T08:30:00Z 转换为 1792053000:

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

与语言无关的转换方式:

instant = parse_source_timestamp_with_explicit_zone(source_timestamp)
milliseconds = instant.to_unix_milliseconds()
assert milliseconds modulo 1000 equals 0
seconds = milliseconds / 1000
assert seconds is a JSON-safe nonnegative integer

如果源数据具有亚秒级精度,请在集成测试之前制定明确的开始/结束舍入策略。切勿传递毫秒值并依赖 API 推断单位。

Partner scope_key           Performance Hub mapping
default                     Facility's configured default target
main_entry                  Access Scope "Main entrances"
after_hours_entry           Doors approved for after-hours entry

合作伙伴不会在时间窗口中发送 Performance Hub 设施、门或访问范围 ID。未知、已停用或未映射的 scope_key 会使该时间窗口按拒绝处理(fail closed),而不会扩大访问权限。请在上线前商定并测试映射。

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)

最低测试向量

[
  {
    "name": "absolute-half-open",
    "window": {
      "external_id": "tv-absolute",
      "kind": "absolute",
      "from": 1792053000,
      "to": 1792058400
    },
    "expect": {
      "1792052999": "inactive",
      "1792053000": "active",
      "1792058399": "active",
      "1792058400": "inactive"
    }
  },
  {
    "name": "weekly-dst",
    "window": {
      "external_id": "tv-weekly-dst",
      "kind": "weekly",
      "timezone": "America/New_York",
      "access_hours": {
        "sun": [["01:00", "03:30"]],
        "mon": [],
        "tue": [],
        "wed": [],
        "thu": [],
        "fri": [],
        "sat": []
      }
    },
    "expect": "Evaluate local wall time: skipped times do not occur; both repeated 01:30 instants qualify."
  }
]

还请提交以下负面测试向量:Unix 毫秒值、数字字符串、浮点数、无效的 IANA 时区、from >= to、重复的 external_id、重叠的时段、跨夜时段、一天超过八个时段、超过 50 个时间窗口,以及未映射的范围键。

保存会员

创建或更新会员记录。API 根据 member_id 确定是创建还是更新。

参数

  • members array 必填

    要保存的会员对象数组。为获得最佳性能,建议每个请求最多 1000 个项目。API 会自动对项目进行分批处理。每个项目必须包含 facility_id(未使用 linking_identifier 时必填)或 linking_identifier(未使用 facility_id 时必填)。

    当会员包含 access_time_windows 时,还必须包含 access_time_windows_revision。该数组是完整的源快照,而不是补丁。省略该数组可保留现有快照;使用更新的修订号发送 [] 可撤销源拥有的所有时间窗口。启用此字段之前,请阅读 Access Time Windows 指南。

返回值

返回一条确认同步操作的简单消息。

即使时间窗口快照被报告为幂等重放或因过时而跳过,会员资料字段仍按正常方式更新插入。修订号相同但负载不同的冲突快照不能原样重试;请对源状态进行对账,并发送更新的修订号。

请求

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

响应

返回一条成功消息,其中包含有关同步操作的元数据。

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

元数据字段:

  • success:成功处理的会员数量
  • skipped:跳过的会员数量(如有)
  • skipped_items:跳过的会员及原因的数组(如有)
  • dry-run:使用 dryrun 密钥类型时的布尔标志(如适用)

签到

表示某人出现在某个设施、课程或活动中的记录。用于跟踪出勤、进行使用情况分析以及提高视觉检测的准确性。

端点

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

签到对象

属性

  • check_in_id string 可选

    签到的唯一标识符。可选;如未提供,将根据 member_id 和 timestamp 组合自动生成。

  • member_id string 必填

    会员的唯一标识符。

  • facility_id string 二选一请提供为您的集成配置的设施标识符类型:直接关联集成使用 facility_id,关联标识符集成使用 linking_identifier。请勿同时发送两者;API 会使用为您的合作伙伴账户配置的标识符类型,并忽略另一个。了解详情

    Performance Hub 中设施的唯一标识符。

  • linking_identifier string 二选一请提供为您的集成配置的设施标识符类型:直接关联集成使用 facility_id,关联标识符集成使用 linking_identifier。请勿同时发送两者;API 会使用为您的合作伙伴账户配置的标识符类型,并忽略另一个。了解详情

    合作伙伴为每个位置使用的唯一标识符值(例如“Branch ID”“Location Code”“Store Number”)。了解详情

  • check_in_type string 可选

    到访类型。取值为 member、class、staff、guest 或 trial 之一。

  • source string 可选

    签到的采集方式。常见值包括 manual、tag、rfid、kiosk、app。也可以使用 door_reader 或 booking 等其他值。

  • class_id string 可选

    可选。适用于与课程预订或出勤关联的情况。

  • timestamp string 必填

    签到发生时间的 ISO 8601 格式时间戳。

签到对象

{
  // "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"
}

保存签到

创建签到记录。API 会根据会员、设施和时间戳自动去重。

参数

  • check_ins array 必填

    要保存的签到对象数组。为获得最佳性能,建议每个请求最多 1000 个项目。API 会自动对项目进行分批处理。每个项目必须包含 facility_id(未使用 linking_identifier 时必填)或 linking_identifier(未使用 facility_id 时必填)。

返回值

返回一条确认同步操作的简单消息。

请求

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

响应

返回一条成功消息,其中包含有关同步操作的元数据。

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

元数据字段:

  • success:成功处理的签到数量
  • skipped:跳过的签到数量(如有)
  • skipped_items:跳过的签到及原因的数组(如有)
  • dry-run:使用 dryrun 密钥类型时的布尔标志(如适用)

门禁控制

对于已启用您的集成的设施,Partner API 可以触发 Performance Hub 门/闸机控制器硬件。

当您的会员管理系统已确定某人可以进入时,请使用此 API。Performance Hub 不会评估会员状态、访问时间、门区规则、欺诈检查或暂停逻辑。这些决策仍由您的系统负责。

解锁请求是同步的。Performance Hub 会实时将命令发送到现场控制器,并且仅在设备确认继电器已实际解锁后才返回 200。大多数确认应在 3-5 秒内完成。如果在超时时间内未收到确认,API 将返回明确的失败结果。

您还可以记录从未到达控制器的访问尝试或拒绝。该调用不会解锁门,而是将事件写入 Door & Gate Access 访问日志。

端点

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

门/闸机控制器对象

属性

  • door_id string 必填

    门/闸机控制器的唯一标识符。发现后将其存储在您的系统中,并在调用解锁端点时使用。

  • facility_id string 必填

    Performance Hub 设施 ID。

  • linking_identifier string 可选

    当您的集成使用关联标识符时的合作伙伴设施标识符。了解详情

  • name string 必填

    在 Performance Hub 中配置的易读设备名称。

  • zone string 可选

    门区或位置,例如 Entrance。

  • status string 必填

    online 或 offline。

  • relay_state string 可选

    最新已知的继电器状态,例如 locked 或 unlocked。

  • maintenance_mode string 必填

    当前维护模式。取值为 off、force-open 或 force-closed 之一。

  • hold_time_seconds integer 必填

    为该门配置的默认解锁保持时间。

  • last_seen string 可选

    最近一次设备元数据更新的 ISO 时间戳。

门/闸机控制器对象

{
  "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"
}

列出门/闸机控制器

返回您的集成可用的门/闸机控制器。

如果既未提供 facility_id 也未提供 linking_identifier,API 将返回与您的合作伙伴账户关联的所有设施中的门/闸机控制器。

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

参数

  • facility_id string 可选 二选一请提供为您的集成配置的设施标识符类型:直接关联集成使用 facility_id,关联标识符集成使用 linking_identifier。请勿同时发送两者;API 会使用为您的合作伙伴账户配置的标识符类型,并忽略另一个。了解详情

    Performance Hub 设施 ID。适用于直接关联集成。

  • linking_identifier string 可选 二选一请提供为您的集成配置的设施标识符类型:直接关联集成使用 facility_id,关联标识符集成使用 linking_identifier。请勿同时发送两者;API 会使用为您的合作伙伴账户配置的标识符类型,并忽略另一个。了解详情

    您自己的设施/位置标识符。当您的集成配置为使用关联标识符时,请使用此参数。

返回值

返回门/闸机控制器对象数组。

请求

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:

响应

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

获取门/闸机控制器状态

检索单个门/闸机控制器的最新已知状态和基本配置。

请提供设施标识符,以便 Performance Hub 验证该门属于您的集成可以访问的设施。

参数

  • door_id string 必填

    列表端点返回的门/闸机控制器 ID。

  • facility_id string 二选一请提供为您的集成配置的设施标识符类型:直接关联集成使用 facility_id,关联标识符集成使用 linking_identifier。请勿同时发送两者;API 会使用为您的合作伙伴账户配置的标识符类型,并忽略另一个。了解详情

    Performance Hub 设施 ID。直接关联集成必填。

  • linking_identifier string 二选一请提供为您的集成配置的设施标识符类型:直接关联集成使用 facility_id,关联标识符集成使用 linking_identifier。请勿同时发送两者;API 会使用为您的合作伙伴账户配置的标识符类型,并忽略另一个。了解详情

    合作伙伴设施标识符。关联标识符集成必填。

返回值

返回一个门/闸机控制器对象。

请求

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:

响应

{
  "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"
  }
}

解锁门/闸机控制器

向门/闸机控制器发送解锁命令,并等待物理继电器确认已解锁。

在调用此端点之前,您的系统必须确定该人员是否已获授权。Performance Hub 仅验证合作伙伴密钥、设施访问权限、门的归属和设备状态。

参数

  • door_id string 必填

    列表端点返回的门/闸机控制器 ID。

  • facility_id string 二选一请提供为您的集成配置的设施标识符类型:直接关联集成使用 facility_id,关联标识符集成使用 linking_identifier。请勿同时发送两者;API 会使用为您的合作伙伴账户配置的标识符类型,并忽略另一个。了解详情

    Performance Hub 设施 ID。直接关联集成必填。

  • linking_identifier string 二选一请提供为您的集成配置的设施标识符类型:直接关联集成使用 facility_id,关联标识符集成使用 linking_identifier。请勿同时发送两者;API 会使用为您的合作伙伴账户配置的标识符类型,并忽略另一个。了解详情

    合作伙伴设施标识符。关联标识符集成必填。

  • member_id string 必填

    合作伙伴会员 ID。用于审计日志记录和后续数据关联。

  • first_name string 必填

    开门人员的名字。

  • last_name string 必填

    开门人员的姓氏。

  • full_name string 可选

    可选。如果省略,Performance Hub 会将 first_name 和 last_name 组合起来。

  • check_in_id string 可选

    可选,来自您系统的签到 ID,用于关联。

  • idempotency_key string 可选

    可选的重放保护密钥。对同一合作伙伴、设施和门重复使用相同的密钥时,如有现有结果,将返回该结果。

返回值

仅当设备确认继电器已实际解锁时才返回 200。门使用在 Performance Hub 设备管理中配置的保持时间;合作伙伴无法在单个请求中覆盖继电器时序。大多数确认应在 3-5 秒内完成。请将文档所述的超时视为明确的解锁失败,并仅按照您自己的安全规则进行重试。

常见失败情况:

  • 403 integration_not_enabled:该设施未启用您的集成。
  • 409 maintenance_mode_active:设施员工已为该门启用维护模式。
  • 503 device_offline:门/闸机控制器处于离线状态或状态已过时。
  • 504 unlock_confirmation_timeout:命令已发送,但在超时前未收到匹配的确认。

请求

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

响应

{
  "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"
}

失败响应

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

记录访问尝试或拒绝

记录您的系统已作出决定的访问尝试或拒绝。此操作不会联系门/闸机控制器,门也不会解锁。

当您的系统拒绝进入,或者某次尝试需要在不解锁的情况下显示在 Door & Gate Access 访问日志中时,请使用此端点。Performance Hub 不会评估会员状态、访问时间或其他访问规则。

被拒绝的事件会显示在 Door & Gate Access 访问日志中,其中包含 Denied 结果、您的合作伙伴名称、门、会员标识符(如果您发送了该标识符),以及以易读形式显示的原因代码。例如,membership_expired 显示为“Membership Expired”。reason_display_text 和 user_email 会与事件一起存储。

参数

  • door_id string 必填

    列表端点返回的门/闸机控制器 ID。

  • facility_id string 二选一请提供为您的集成配置的设施标识符类型:直接关联集成使用 facility_id,关联标识符集成使用 linking_identifier。请勿同时发送两者;API 会使用为您的合作伙伴账户配置的标识符类型,并忽略另一个。了解详情

    Performance Hub 设施 ID。直接关联集成必填。

  • linking_identifier string 二选一请提供为您的集成配置的设施标识符类型:直接关联集成使用 facility_id,关联标识符集成使用 linking_identifier。请勿同时发送两者;API 会使用为您的合作伙伴账户配置的标识符类型,并忽略另一个。了解详情

    合作伙伴设施标识符。关联标识符集成必填。

  • outcome string 必填

    denied 或 attempted。

  • reason string 可选

    小写 snake_case 格式的原因代码,最多 64 个字符。当 outcome 为 denied 时必填。示例:membership_expired。

  • reason_display_text string 可选

    易读的原因说明,最多 256 个字符。示例:Membership expired on 2026-04-01。

  • member_id string 可选

    合作伙伴会员 ID。如果凭据未匹配到任何会员(例如未知卡片),请省略此参数。

  • user_email string 可选

    尝试访问的人员的电子邮件地址。

  • timestamp string 可选

    尝试发生的时间,采用带时区的 ISO 8601 格式。示例:2026-05-18T10:15:30Z。默认为收到请求的时间。不得晚于当前时间 5 分钟以上,也不得早于 30 天前。

  • idempotency_key string 可选

    重放保护密钥,最多 128 个字符。对同一合作伙伴、设施和门重复使用相同的密钥将返回原始结果。

返回值

记录事件后返回 201。重放相同的 idempotency_key 将返回 200,并将 idempotent 设置为 true,不会创建新事件。

dry-run 密钥返回 200,并将 dry_run 设置为 true。不会记录任何内容。

常见失败情况:

  • 400:请求正文无效、拒绝事件缺少 reason、时间戳超出范围,或 facility_id / linking_identifier 与已关联的设施不匹配。
  • 403:密钥为只读密钥。
  • 403 integration_not_enabled:该设施未启用您的集成。message 会说明原因。
  • 404:在已关联的设施中未找到该门/闸机控制器。

请求

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

响应

{
  "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"
}

幂等重放

{
  "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
}

设施报告

记录设施在特定期间内关键运营和财务指标的时间点记录。

端点

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

报告快照对象

属性

  • facility_id string 二选一请提供为您的集成配置的设施标识符类型:直接关联集成使用 facility_id,关联标识符集成使用 linking_identifier。请勿同时发送两者;API 会使用为您的合作伙伴账户配置的标识符类型,并忽略另一个。了解详情

    Performance Hub 中设施的唯一标识符。

  • linking_identifier string 二选一请提供为您的集成配置的设施标识符类型:直接关联集成使用 facility_id,关联标识符集成使用 linking_identifier。请勿同时发送两者;API 会使用为您的合作伙伴账户配置的标识符类型,并忽略另一个。了解详情

    合作伙伴为每个位置使用的唯一标识符值(例如“Branch ID”“Location Code”“Store Number”)。了解详情

  • start_date string 必填

    YYYY-MM-DD 格式的快照期间开始日期。

  • end_date string 必填

    YYYY-MM-DD 格式的快照期间结束日期。

  • metrics 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"
    }
  }
}

保存报告快照

提交设施在特定期间内的运营和财务指标。

参数

  • snapshots array 必填

    要保存的报告快照对象数组。每个请求最多 25 个项目。每个项目必须包含 facility_id(未使用 linking_identifier 时必填)或 linking_identifier(未使用 facility_id 时必填)。

返回值

返回一条确认同步操作的简单消息。

请求

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

响应

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

错误

Partner API 使用标准 HTTP 状态码和 JSON 响应正文来说明请求失败的原因。

错误响应结构

大多数 API 错误会返回一个 JSON 正文,其中包含一条消息,并在可用时包含结构化详细信息。

状态码

Access Time Window 失败

时间窗口验证会在写入无效快照之前失败。常见的不可重试原因包括:

  • 存在 access_time_windows 时缺少 access_time_windows_revision。
  • 字符串、浮点数或疑似毫秒级的纪元时间值。
  • 无效的 IANA 时区、颠倒的时间区间、重复的 external_id、重叠的每周时段,或未拆分的跨夜时段。
  • 超出文档所述数量、长度或跨度限制的值。

重复的修订号但规范化内容不同时,返回 409 Conflict。请根据最新的权威状态进行对账并分配更新的修订号;不要继续重试存在冲突的组合。较旧的修订号会被报告为已跳过的过时快照,而不会覆盖较新的状态。未知或未映射的 scope_key 在授权时会按拒绝处理(fail closed),应将其视为配置警报。

如果投递超时或收到暂时性的 5xx,请使用相同的修订号重试完全相同的规范化快照。如果从上游源获取数据失败,请完全省略时间窗口字段;切勿以空数组代替。

重试指南

对以下错误使用有限次数的指数退避进行重试:

  • 429
  • 500
  • 502
  • 503
  • 504

不要盲目重试以下错误:

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

对于门禁控制,除非您自己的访问规则和安全流程另有规定,否则请始终将超时和离线响应视为解锁失败。

联系支持时需提供的详细信息

联系支持时,请提供:

  • 端点和 HTTP 方法。
  • 时间戳和时区。
  • 合作伙伴密钥 ID,而非密钥本身。
  • 使用的设施标识符。
  • 您系统中的源记录 ID。
  • 响应状态和正文。
  • event_id 或 command_id(如有)。
{
  "success": false,
  "message": "Request body.members[0].member_id is required"
}

某些特定领域的端点会返回明确的状态和原因。例如,门禁控制失败会包含 reason、door_id、facility_id 和 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

请求格式错误或缺少必填字段。请先修正请求再重试。

401 Unauthorized

身份验证失败。请检查您是否使用了 HTTP Basic Auth,并以 API 密钥作为用户名、密码留空。

403 Forbidden

密钥有效,但不允许执行该操作。常见原因包括使用只读密钥执行写入操作,或尝试访问未启用您的集成的设施。

404 Not Found

未找到请求的资源,或该资源对您的集成不可用。

409 Conflict

请求与资源的当前状态冲突。对于门禁控制,这可能包括门/闸机控制器处于维护模式。

422 Unprocessable Entity

请求是有效的 JSON,但未通过语义验证。请先修正数据再重试。

429 Too Many Requests

集成超出了文档所述的速率限制。请使用指数退避进行重试。

500 Internal Server Error

由于内部错误,Performance Hub 无法完成请求。请使用退避进行重试。如果问题仍然存在,请联系支持并提供端点、时间戳和响应正文。

503 Service Unavailable

某个依赖的服务或设备不可用。对于门/闸机控制器解锁,这可能表示控制器处于离线状态。

504 Gateway Timeout

操作超时。对于门/闸机控制器解锁,这表示在超时时间内未确认解锁。

版本控制

Partner API 在 URL 中标明版本。当前版本为:

变更政策

Performance Hub 力求尽可能进行增量式、向后兼容的变更。

向后兼容变更的示例:

  • 在请求中添加新的可选字段。
  • 在响应中添加新字段。
  • 添加新端点。
  • 在客户端应能处理未知值的情况下添加新的枚举值。
  • 在不改变状态码约定的情况下改进验证消息。

access_time_windows 和 access_time_windows_revision 是增量添加的会员请求字段。省略这些字段的现有客户端会保持已存储的 Access Time Window 快照不变。此省略规则保留了部分更新插入的兼容性;省略并不等同于发送空数组。

破坏性变更的示例:

  • 移除或重命名字段。
  • 更改字段的类型。
  • 将可选的请求字段改为必填。
  • 移除端点。
  • 更改现有状态码或特定领域 reason 的含义。

弃用

当需要进行破坏性变更时,Performance Hub 会尽可能避免直接修改现有版本,而是引入新版本或迁移路径,并将变更告知受影响的合作伙伴。

弃用通知可能包括:

  • 更新日志条目。
  • 与合作伙伴的直接沟通。
  • Partner Console 中的说明。
  • 文档中的迁移指南。

客户端建议

构建能够容忍增量变更的客户端:

  • 忽略您不使用的响应字段。
  • 将未知的枚举值视为不受支持,而不是导致崩溃。
  • 避免对响应进行严格的相等性检查。
  • 记录无法识别的值,以便您有计划地更新集成。

对于带修订号的会员分区(例如 Access Time Windows),请持久保存已提交的修订号和规范化负载,直到获知结果。对已更改的内容重复使用修订号会产生冲突,而重放相同的内容则是幂等的。请参阅 Access Time Windows。

OpenAPI 规范

使用已发布的 OpenAPI 规范生成客户端、验证请求,并跟踪 API 结构随时间的变化。

请参阅 OpenAPI 规范。

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

更新日志

本更新日志记录影响集成行为的重要 Partner API 和 Partner Console 变更。

2026-09-09

2026-05-06

2026-05-01

变更类别

今后的条目将使用以下类别:

  • 新增:新的端点、字段、指南或功能。
  • 变更:行为或文档发生变化,但未移除支持。
  • 弃用:功能仍然可用,但已有计划的迁移路径。
  • 移除:功能或端点已移除。
  • 修复:错误修复或文档更正。
  • 安全:身份验证、授权、数据处理或密钥管理方面的变更。

新增

  • 新增与供应商无关的会员 access_time_windows 快照,支持混合使用绝对时间窗口和每周重复时间窗口。
  • 新增 access_time_windows_revision 排序、幂等重放、冲突、跳过过时数据和显式撤销语义。
  • 新增 IANA 时区、夏令时、逻辑 scope_key 映射、源数据新鲜度、生产方实现和认证指南。

新增

  • 新增合作伙伴计划文档,涵盖合作伙伴类型、入驻、最佳实践、上线准备、错误、版本控制和支持。
  • 为潜在的技术和商业合作伙伴新增专门的“成为合作伙伴”咨询流程。
  • 新增文档,说明已批准的合作伙伴集成如何显示在 Performance Hub 核心平台内的 Performance Hub 合作伙伴目录中。

新增

  • 新增门/闸机控制器门禁控制文档,包括列出、状态和解锁操作。
  • 新增同步解锁行为文档:仅当现场控制器确认继电器已实际解锁后,API 才返回成功。
  • 新增门/闸机控制器解锁请求可选 idempotency_key 支持的文档。