Ultrahuman Metrics API

Reads user-consented Ring AIR / Ring Pro daily metrics via the ring_data scope - sleep stages, duration, efficiency and sleep score, HRV (rMSSD), resting and night heart rate, skin temperature deviation, SpO2, steps, movement index, recovery index/score, metabolic score, and VO2 max. GET by date (YYYY-MM-DD) or by a start/end epoch window (max 7 days). Endpoint paths are documented in the partner developer docs; request/response shapes here are modeled from the docs.

OpenAPI Specification

ultrahuman-openapi.yml Raw ↑
openapi: 3.0.3
info:
  title: Ultrahuman Partner (UltraSignal) API
  description: >-
    The Ultrahuman Partner API gives approved partners read access to
    user-consented health metrics from the Ultrahuman Ring AIR / Ring Pro and,
    for users with an active M1 patch, the Ultrahuman CGM. Access is secured with
    OAuth 2.0 (Authorization Code Grant plus Refresh Token flow) across three
    scopes: profile, ring_data, and cgm_data. Access is not self-serve - partners
    apply to the developer program and are issued a Client ID, Client Secret, and
    a registered redirect URI during onboarding; end users authorize data sharing
    from the Ultrahuman app (Profile -> Settings -> Partner ID). Access tokens
    expire in ~1 day (86400 seconds); refresh tokens rotate on each exchange.

    IMPORTANT: This document is MODELED by API Evangelist from Ultrahuman's public
    partner developer documentation. Endpoint paths, scopes, OAuth flows, query
    parameters, and the documented metric families are drawn from the docs;
    exact request/response schemas are approximations and should be verified
    against the live developer portal. Ultrahuman also documents a personal-token
    variant at GET /api/v1/partner/daily_metrics for a developer's own ring data.
  version: '1.0'
  contact:
    name: Ultrahuman Partnerships
    url: https://partnerships.ultrahuman.com/
  x-endpointsModeled: true
servers:
  - url: https://partner.ultrahuman.com
    description: Ultrahuman Partner API
tags:
  - name: OAuth
    description: OAuth 2.0 authorization, token exchange, and revocation.
  - name: Metrics
    description: Ring and CGM daily metrics for consented users.
  - name: User
    description: Basic authorized-user profile information.
paths:
  /authorize:
    get:
      operationId: authorize
      tags:
        - OAuth
      summary: Authorization endpoint (Authorization Code Grant)
      description: >-
        Redirects the user to Ultrahuman to consent to the requested scopes.
        On approval, Ultrahuman redirects back to the registered redirect_uri
        with an authorization code.
      parameters:
        - name: response_type
          in: query
          required: true
          schema:
            type: string
            enum: [code]
        - name: client_id
          in: query
          required: true
          schema:
            type: string
        - name: redirect_uri
          in: query
          required: true
          schema:
            type: string
            format: uri
        - name: scope
          in: query
          required: true
          description: Space-delimited scopes - profile, ring_data, cgm_data.
          schema:
            type: string
            example: profile ring_data cgm_data
        - name: state
          in: query
          required: false
          schema:
            type: string
      responses:
        '302':
          description: Redirect to redirect_uri with an authorization code (or an error).
  /api/partners/oauth/token:
    post:
      operationId: token
      tags:
        - OAuth
      summary: Token endpoint (code exchange and refresh)
      description: >-
        Exchanges an authorization code for an access token, or exchanges a
        refresh token for a new access token. Perform token exchanges
        server-side. Refresh tokens rotate on each exchange.
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/TokenRequest'
      responses:
        '200':
          description: A new access token (and rotated refresh token).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TokenResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /api/partners/oauth/revoke:
    post:
      operationId: revoke
      tags:
        - OAuth
      summary: Revoke a token
      description: Revokes an access or refresh token.
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required: [token, client_id, client_secret]
              properties:
                token:
                  type: string
                client_id:
                  type: string
                client_secret:
                  type: string
      responses:
        '200':
          description: Token revoked.
        '400':
          $ref: '#/components/responses/BadRequest'
  /api/partners/v1/user_data/metrics:
    get:
      operationId: getUserMetrics
      tags:
        - Metrics
      summary: Get a user's daily health metrics
      description: >-
        Returns consented daily metrics for the authorized user. Ring metrics
        require the ring_data scope; glucose/CGM metrics require the cgm_data
        scope and an active M1 patch. Query by a single date (YYYY-MM-DD) or by a
        start_epoch/end_epoch window (max range 7 days). date and the epoch pair
        are mutually exclusive.
      security:
        - bearerAuth: []
      parameters:
        - name: date
          in: query
          required: false
          description: Target day in YYYY-MM-DD. Mutually exclusive with the epoch pair.
          schema:
            type: string
            format: date
        - name: start_epoch
          in: query
          required: false
          description: Window start, epoch seconds. Use with end_epoch (max 7-day range).
          schema:
            type: integer
            format: int64
        - name: end_epoch
          in: query
          required: false
          description: Window end, epoch seconds.
          schema:
            type: integer
            format: int64
        - name: email
          in: query
          required: false
          description: Optional target user's email for authorized multi-user access.
          schema:
            type: string
            format: email
      responses:
        '200':
          description: The user's metrics for the requested period.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MetricsResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
  /api/partners/v1/user_data/user_info:
    get:
      operationId: getUserInfo
      tags:
        - User
      summary: Get the authorized user's basic profile
      description: >-
        Returns basic profile info (user ID, time zone, etc.) for the authorized
        user. Requires the profile scope.
      security:
        - bearerAuth: []
      responses:
        '200':
          description: Basic user profile.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserInfo'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: OAuth 2.0 access token in the Authorization header.
  responses:
    BadRequest:
      description: Invalid parameters, or the epoch window exceeded the 7-day limit.
    Unauthorized:
      description: Missing, invalid, or expired access token.
    NotFound:
      description: User not found, or the partner lacks permission for the requested data.
  schemas:
    TokenRequest:
      type: object
      required: [grant_type, client_id, client_secret]
      properties:
        grant_type:
          type: string
          enum: [authorization_code, refresh_token]
        client_id:
          type: string
        client_secret:
          type: string
        code:
          type: string
          description: Required for grant_type=authorization_code.
        redirect_uri:
          type: string
          format: uri
        refresh_token:
          type: string
          description: Required for grant_type=refresh_token.
    TokenResponse:
      type: object
      properties:
        access_token:
          type: string
        token_type:
          type: string
          example: Bearer
        expires_in:
          type: integer
          example: 86400
        refresh_token:
          type: string
        scope:
          type: string
        created_at:
          type: integer
          format: int64
    UserInfo:
      type: object
      properties:
        id:
          type: string
        timezone:
          type: string
          example: Asia/Kolkata
    MetricsResponse:
      type: object
      description: >-
        Modeled envelope of daily metrics. The docs describe roughly 40+ metric
        fields spanning cardiovascular, sleep, glucose, activity/recovery, and
        temperature families; representative fields are shown here.
      properties:
        date:
          type: string
          format: date
        cardiovascular:
          type: object
          properties:
            heart_rate:
              type: number
            hrv_rmssd:
              type: number
            night_resting_heart_rate:
              type: number
            sleep_hrv:
              type: number
            spo2:
              type: number
        sleep:
          type: object
          properties:
            total_duration_minutes:
              type: number
            efficiency:
              type: number
            rem_minutes:
              type: number
            deep_minutes:
              type: number
            light_minutes:
              type: number
            sleep_score:
              type: number
            temperature_deviation:
              type: number
        activity_recovery:
          type: object
          properties:
            steps:
              type: integer
            active_minutes:
              type: number
            movement_index:
              type: number
            recovery_index:
              type: number
            recovery_score:
              type: number
            metabolic_score:
              type: number
            vo2_max:
              type: number
        temperature:
          type: object
          properties:
            skin_temperature_celsius:
              type: number
            avg_body_temperature_sleep:
              type: number
        glucose:
          type: object
          description: Present only with the cgm_data scope and an active M1 patch.
          properties:
            readings:
              type: array
              items:
                type: object
                properties:
                  epoch:
                    type: integer
                    format: int64
                  value_mgdl:
                    type: number
            average_mgdl:
              type: number
            variability:
              type: number
            estimated_hba1c:
              type: number
            time_in_target_percent:
              type: number