openapi: 3.1.0 info: title: XRHealth Platform API version: 1.0.0 description: Common API for XRHealth applications and approved integrations. x-harvested-from: https://api.xr.health/v1/openapi.json x-harvested: '2026-09-04' x-harvest-method: searched servers: - url: https://api.xr.health/v1 description: Production. Resolved from the relative "/v1" servers entry in the published document at https://api.xr.health/v1/openapi.json (RFC 3986 relative reference against the retrieval URL). paths: /: get: operationId: getApiMetadata summary: Get API metadata responses: '200': description: API metadata /openapi.json: get: operationId: getOpenApiDocument summary: Get the OpenAPI document responses: '200': description: OpenAPI document /auth/passwordless/start: post: operationId: startPatientPasswordlessLogin summary: Send a one-time patient login code security: - applicationToken: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PasswordlessStartRequest' responses: '202': description: A code request was accepted. '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/RateLimited' '503': $ref: '#/components/responses/Unavailable' /auth/passwordless/verify: post: operationId: verifyPatientPasswordlessLogin summary: Exchange a one-time code for XRHealth tokens security: - applicationToken: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PasswordlessVerifyRequest' responses: '200': description: XRHealth access and refresh tokens. content: application/json: schema: $ref: '#/components/schemas/TokenResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '503': $ref: '#/components/responses/Unavailable' /auth/public/passwordless/start: post: operationId: startPublicPatientPasswordlessLogin summary: Start passwordless login for a registered public client requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PublicPasswordlessStartRequest' responses: '202': description: A code request was accepted. '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/RateLimited' '503': $ref: '#/components/responses/Unavailable' /auth/public/passwordless/verify: post: operationId: verifyPublicPatientPasswordlessLogin summary: Exchange a passwordless code for a short-lived PKCE authorization code requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PublicPasswordlessVerifyRequest' responses: '200': description: A one-time authorization code. content: application/json: schema: $ref: '#/components/schemas/AuthorizationCodeResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '503': $ref: '#/components/responses/Unavailable' /auth/public/token: post: operationId: exchangePublicPatientToken summary: Exchange a PKCE authorization code or rotate a public-client refresh token requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PublicTokenRequest' responses: '200': description: XRHealth access and refresh tokens. content: application/json: schema: $ref: '#/components/schemas/TokenResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '503': $ref: '#/components/responses/Unavailable' /auth/public/token/revoke: post: operationId: revokePublicPatientToken summary: Revoke a public-client refresh token requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PublicTokenRevokeRequest' responses: '200': description: The refresh token is no longer usable. '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '503': $ref: '#/components/responses/Unavailable' /auth/token/refresh: post: operationId: refreshPatientToken summary: Rotate a patient refresh token security: - applicationToken: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/RefreshTokenRequest' responses: '200': description: Rotated XRHealth tokens. content: application/json: schema: $ref: '#/components/schemas/TokenResponse' '401': $ref: '#/components/responses/Unauthorized' '503': $ref: '#/components/responses/Unavailable' /auth/token/revoke: post: operationId: revokePatientToken summary: Revoke a patient refresh token security: - applicationToken: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/RefreshTokenRequest' responses: '200': description: The refresh token is no longer usable. '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '503': $ref: '#/components/responses/Unavailable' /me: get: operationId: getCurrentPatient summary: Get the current public patient subject security: - applicationToken: [] patientBearer: [] responses: '200': description: The current public patient identity. content: application/json: schema: $ref: '#/components/schemas/MeResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '503': $ref: '#/components/responses/Unavailable' /.well-known/jwks.json: get: operationId: getPatientApiJwks summary: Get the public signing keys for XRHealth patient access tokens responses: '200': description: JSON Web Key Set. content: application/json: schema: type: object required: - keys properties: keys: type: array items: type: object '503': $ref: '#/components/responses/Unavailable' components: securitySchemes: applicationToken: type: apiKey in: header name: X-XRHealth-Application-Token patientBearer: type: http scheme: bearer bearerFormat: JWT schemas: PasswordlessStartRequest: type: object required: - email properties: email: type: string format: email additionalProperties: false PasswordlessVerifyRequest: type: object required: - request_id - email - code properties: request_id: type: string format: uuid email: type: string format: email code: type: string pattern: ^\d{4,8}$ additionalProperties: false PublicPasswordlessStartRequest: type: object required: - client_id - email - code_challenge - code_challenge_method properties: client_id: type: string minLength: 8 maxLength: 128 email: type: string format: email code_challenge: type: string minLength: 43 maxLength: 128 code_challenge_method: type: string enum: - S256 additionalProperties: false PublicPasswordlessVerifyRequest: type: object required: - client_id - request_id - email - code properties: client_id: type: string minLength: 8 maxLength: 128 request_id: type: string format: uuid email: type: string format: email code: type: string pattern: ^\d{4,8}$ additionalProperties: false PublicTokenRequest: type: object required: - client_id - grant_type properties: client_id: type: string minLength: 8 maxLength: 128 grant_type: type: string enum: - authorization_code - refresh_token authorization_code: type: string minLength: 16 code_verifier: type: string minLength: 43 maxLength: 128 refresh_token: type: string minLength: 16 additionalProperties: false PublicTokenRevokeRequest: type: object required: - client_id - refresh_token properties: client_id: type: string minLength: 8 maxLength: 128 refresh_token: type: string minLength: 16 additionalProperties: false AuthorizationCodeResponse: type: object required: - authorization_code - expires_in properties: authorization_code: type: string expires_in: type: integer example: 60 RefreshTokenRequest: type: object required: - refresh_token properties: refresh_token: type: string minLength: 16 additionalProperties: false TokenResponse: type: object required: - token_type - access_token - expires_in - refresh_token - refresh_token_expires_in - subject - scope properties: token_type: type: string enum: - Bearer access_token: type: string expires_in: type: integer example: 900 refresh_token: type: string refresh_token_expires_in: type: integer example: 2592000 subject: type: string description: Opaque public patient subject. scope: type: string example: patient:login patient:read MeResponse: type: object required: - subject - application - scopes properties: subject: type: string application: type: string scopes: type: array items: type: string responses: BadRequest: description: The request is invalid. Unauthorized: description: The application or patient token is invalid. Forbidden: description: The token does not have access to this resource. RateLimited: description: The request was rate limited. Unavailable: description: The authentication module is temporarily unavailable.