PAI Health logo

Developers

PAI Health API (2.4.3)

Getting Started

PAI is the first scientifically validated score that prescribes personal activity levels for optimal health. Our proprietary technology provides a cardiorespiratory fitness score based on a user's personal profile and heart rate data, which is an accurate assessment and predictor of long term health.

With the PAI Health API, you can integrate PAI into your organization’s health system, wearable or application.

To request access, please fill out our developer registration form.

Organizations

Data in the PAI Health API is partitioned by organization. PAI Health users can be found under the PAI Health organization id 2188a980-70a2-4b24-b145-8139cb7f9106.

If you require your own organization for your integration you will need to request one as part of the registration process. Once your organization has been provisioned, you will be given an organization id to use.

The organization id is required to access any data in the Admin API and User APIs, and your account must belong to the same organization in order to be granted authorization.

Authentication

Most requests to the PAI Health API will require authentication.

The PAI Health API supports Bearer authentication using an industry standard Json Web Token (JWT) access token, which can be retrieved for a given account using the Auth API.

Once your have retrieved an access token for an account you need to pass in the token using an Authorization header: Authorization : Bearer {accessToken}

Resources

Within a given organization, these are the resource types you can interact with using the Admin and User APIs.

Resource Description
Account A record representing an individual or system that has API access to data within the organization
User An actual person who tracks their health data in the system
Group A groups of users
Group Member A user who currently belongs to a group
Group Membership A record of which groups a user belongs to
Group Event A group member event (Joined, Removed, etc.)
Profile The current user’s personal information
Heartrate Summary Heartrate record of a user for a particular day including heart rate measurements (bpm)
Biometric Biometric data (ie. max heart rate, resting heart rate, weight, height) associated with a user for a particular day
PAI Summary Summary of PAI information (current PAI score, daily PAI earned, intensity zones, etc.) for a user for a particular day
PAI Calculation A PAI calculation that triggers automatically as new heart rate data comes in for a user (given valid biometrics)
VO2 Max Assessment An assessment that generates a VO2 max summary based off of self-reported activity and biometrics
VO2 Max Summary Summary of VO2 max information (VO2 max score, calibration status, etc.) for a user for a particular day
VO2 Max Calculation A VO2 max calculation that triggers automatically as new PAI summary information comes in for a user (given valid biometrics)
Webhook An external subscription to various events within the PAI Health API

Auth API

Used by all accounts to authenicate with the PAI Health API.

Potential Uses:

  • Authenticating an account
  • Resetting a password
  • Registering an account
  • Resending a confirmation email
  • Confirming an account email

View the detailed Auth API Documentation here.

Admin API

Used by organization Administrators to manage accounts and view user data across the organization.

Potential Uses:

  • Administrating accounts and users
  • Administrating groups and group members
  • Accessing user heartrates and biometrics
  • Accessing user PAI summaries
  • Accessing user vo2 max summaries

View the detailed Admin API Documentation here.

User API

Used by end-users to manage and view their personal data.

Potential Uses:

  • Changing personal account information
  • Accessing personal biometrics and heartrates
  • Accessing personal PAI summaries
  • Accessing personal vo2 max summaries

View the detailed User API Documentation here.

Fields

Naming Conventions

  • Field names are camelCase

  • Abbreviations are camelCase (i.e. href, maxSpeedKph)

  • Dates are in ISO 8601 standard format

  • For date and time fields, the following suffixes are commonly used:

    • On for days and dates
    • In{Unit} for duration
    • At for precise times, including full dates that include the time.

    Example:

    RegisteredOn: 2013-07-13, DurationInSeconds: 312, ModifiedAt: 2013-07-13T14:35:00Z

Common Fields

All resources contain the following fields:

  • id: the id of the resource (usually a UUID unless it's a child of another resource)
  • createdAt: ISO standard ("YYYY-MM-DDTHH:mm:ss.sssZ") datetime when the resource was created
  • createdBy: account id that created the resource, UUID
  • modifiedAt: ISO standard ("YYYY-MM-DDTHH:mm:ss.sssZ") datetime when the resource was last modified.
  • modifiedBy: account id that last modified the resource, UUID.
  • href: (optional) if the resource endpoint supports GET for an individual resource, the field is present on any resource(s) returned as a fully qualified url that points to the given resource. See the location header below for some more details.

Note: The audit fields should not be relied upon to drive any business logic in your application - they may change or be updated at any time by the system.

Example: GET /admin/api/v2/organizations/2188a980-70a2-4b24-b145-8139cb7f9106/users/bcc41062-fd2e-4c14-b5cb-526cdf3a8a59

{
  "id": "bcc41062-fd2e-4c14-b5cb-526cdf3a8a59",
  "email": "abc@gmail.com",
  ...
  "createdAt": "0001-01-01T00:00:00Z",
  "createdBy": "e023a5c9-47ed-49fd-8857-1dd42a9d4818",
  "modifiedAt": "0001-01-01T00:00:00Z",
  "modifiedBy": "e023a5c9-47ed-49fd-8857-1dd42a9d4818"
}

Request Headers

Allow HTTP method override

The POST method supports the custom header X-HTTP-Method-Override which will override the http method being used. This is useful for legacy browser support that doesnt support the full set of Http verbs.

Content-Type

The Content-Type header is used to determine the format for the representation of the resource. Only application/json is supported currently.

Accept-Language

Accept-Language header is used to determine any localization for the resource.

X-No-Return-Resource

X-No-Return-Resource header can be used to exclude the resource from being returned in the response body. By default the resource is returned in the body for POST, PUT, and PATCH operations, but you may want to override this behaviour for performance reasons if you don't need the returned resource.

Response Headers

Location

The Location header is always returned in the response of any POST request that creates a new resource with the fully-qualified URL of the resource.

The common 'href' field also contain this same URL.

The Link header is used to support HATEOS for navigation and discoverability through the API.

A Link header is returned for a resource if there are related resources (child resources, collection links etc) the client may be interested in (see more on collection headers below).

Links are fully qualified and require no parsing on the consumer side. Following the Link header RFC standard, multiple links are separated by commas.

Example:

<https://api.paihealth.com/api/v2/organizations/2188a980-70a2-4b24-b145-8139cb7f9106/users/bcc41062-fd2e-4c14-b5cb-526cdf3a8a59>; rel="resource"

Partial Responses (Field Selection)

The PAI Health API supports the return of partial resources via field selection to optimize payloads for clients. This allows clients to select which fields they are interested in and optimize their payload accordingly. Currently this is only supported on GET requests.

GET /api/v2/admin/organizations/2188a980-70a2-4b24-b145-8139cb7f9106/users?fields=firstName,lastName

This example would only contain the firstName and lastName fields for all user resources returned. Fields are validated against the resource model to ensure they all exist on the resource. If not, a 400 Bad Request error will be returned.

Collections

Collection endpoints return a simple array of resources.

[{resource1}, {resource2}, .. ]

Collections support filtering, sorting, and paging.

Filtering

Simple

Simple filtering is supported to reduce the result set using simple equality statements.

GET /api/v2/admin/organizations/2188a980-70a2-4b24-b145-8139cb7f9106/users?firstName=Joe

GET /api/v2/admin/organizations/2188a980-70a2-4b24-b145-8139cb7f9106/users?firstName=Joe&country=CA

Simple filtering only supports =. Multiple simple filters can be combined as separate query params using the &. Unknown filter params will be ignored.

Complex

Complex filtering is supported to reduce the result set using a broader set of conditions.

GET /api/v2/admin/organizations/2188a980-70a2-4b24-b145-8139cb7f910/pai/summaries?q=(paiScore>=100 AND paiScore<=160) OR userId IN ["id123", "id456"]

GET /api/v2/admin/organizations/2188a980-70a2-4b24-b145-8139cb7f910/accounts?q=accountType=Regular AND (accountStatus LIKE _ct%)

Supported tokens are currently =,<,>,<=,>=,!=, IN, NOT IN, LIKE and each condition should be separated by a logical condition AND or OR.

Notes:

  • Spaces are required between IN, NOT IN, AND, OR, LIKE keywords
  • The LIKE keyword can only be used for string fields, and it supports two wildcards %(0 or 1+ chars) and _(a single char)
  • Quotes are not strictly required for string values unless you need to use ", (, ) within the value
  • Nested conditions are supported up to 4 levels deep within parentheses ( )
  • Extra spaces between terms is ignored if not with double-quotes "

The following will result in a 400 Bad Request:

  • Any of the resource fields in the filter do not exist as filterable query params on the resource
  • Invalid query format is provided (i.e. q=nonsense)
  • Max query length is exceeded (currently 5000 characters)
  • Nested condition depth over 4 levels

Sorting

Sorting is specified with the sort parameter and supports ascending and descending sorting over multiple fields.

GET /api/v2/organizations/2188a980-70a2-4b24-b145-8139cb7f910/users?sort=-lastName,firstName

Use - to denote descending order, and separate multiple fields with commas. Sort priority is left to right.
Validation ensures all of the resource fields in the sort exist as filterable query params on the resource. If not, a 400 Bad Request error is returned.

Paging

Paging is specified with the offset and limit parameters to allow the client to select the set of data they want to use.

Total count for the request is returned as a custom header, along with the limit and offset information.

X-Pagination-Count: 53
X-Pagination-Offset: 5
X-Pagination-Limit: 20

The links header includes pagination information for next, prev, first, and last (at a minimum):

Example:

<https://api.paihealth.com/api/v2/organizations/2188a980-70a2-4b24-b145-8139cb7f910/users?offset=0&limit=5>; rel="first",
<https://api.paihealth.com/api/v2/organizations/2188a980-70a2-4b24-b145-8139cb7f910/users?offset=5&limit=5>; rel="prev",
<https://api.paihealth.com/api/v2/organizations/2188a980-70a2-4b24-b145-8139cb7f910/users?offset=15&limit=5>; rel="next",
<https://api.paihealth.com/api/v2/organizations/2188a980-70a2-4b24-b145-8139cb7f910/users?offset=50&limit=5>; rel="last",

Paging also takes into account any filters and sorting that has been specified - this applies to the links generated for navigation, counts, etc.

Caching & Compression

Deflate and Gzip are supported by default for anything over 1kb in size unless the X-No-Compression header is sent in the request.

In addition, we support client caching using the 304 (Not Modified) response using the following options below.

ETag

Responses include a header ETag containing a hash or checksum of the representation. This value changes whenever the output representation changes.

If an inbound HTTP request contains a If-None-Match header with a matching ETag value for a given resource, the API will return a 304 Not Modified status code and no content instead of the output representation of the resource.

Last-Modified

The response header Last-Modified contains a timestamp in RFC 1123 (e.g. Mon, 15 Jun 2009 20:45:30 GMT) format using the modifiedOn field as the value.

If an inbound request contains If-Modified-Since header with a value greater than than the modifiedOn field then the API will return a 304 Not Modified status code and no content instead of the output representation of the resource.

Throttling & Rate-Limits

Rate-limiting on the API is controlled at the organization level.

If the number of requests exceeds the rate limit for the API, a 429 (Too Many Requests) status code will be returned.

Errors

Standard Error Payload

Any errors returned by the PAI Health API will return 4xx or 5xx status codes, and use the following standard error payload in the response body:

{
  "errors": [
    {
      "message": "Sorry, we cannot save your workout at this time",
      "code": "INVALID_HEARTRATE"
      "errors": [
        ..
      ]
    }
  ]
}

Common Status and Error Codes

Status Code Standard Error Code Description
400 BAD_REQUEST Invalid request. Malformed or invalid parameters. Error message should be explained in the error payload.
401 UNAUTHORIZED The request requires a user authentication. Used when no authentication is supplied.
403 FORBIDDEN Access is not allowed to perform that action on that resource. Used when user is authenticated but does not have the correct permissions (authorization).
404 NOT_FOUND No resource exists at this URI
405 METHOD_NOT_ALLOWED VERB is not supported on this resource
415 UNSUPPORTED_MEDIA_TYPE If request contains Content-Type that is not supported in the API
500 INTERNAL_SERVER_ERROR An unexpected error. Should not normally be returned, but any uncaught exceptions at the application layer should get caught by a global error handler and return a 500. Should be logged and a generic error payload returned to the client.