Skip to content

feat(integrations): add Oura Ring provider#454

Draft
vikohone wants to merge 5 commits intothe-momentum:mainfrom
vikohone:227-add-oura-provider
Draft

feat(integrations): add Oura Ring provider#454
vikohone wants to merge 5 commits intothe-momentum:mainfrom
vikohone:227-add-oura-provider

Conversation

@vikohone
Copy link

Summary

  • Implement full Oura Ring integration using the Strategy + Factory + Template pattern
  • Add OAuth2 authorization flow (Authorization Code Grant, no PKCE, body auth method)
  • Add workout import with mapping for ~80 Oura activity types to unified WorkoutType enum
  • Add 24/7 data collection: sleep (with stages), readiness/recovery, heart rate, daily activity (steps/calories/distance), and SpO2
  • Add webhook endpoints for real-time data notifications (notification-then-pull pattern, matching Garmin's approach)
  • Add comprehensive test suite (strategy, OAuth, workouts, 247 data normalization, webhooks)

Closes #227

New Files (15)

  • app/schemas/oura/ — Pydantic models for all Oura API v2 responses
  • app/constants/workout_types/oura.py — Activity string → WorkoutType mapping
  • app/services/providers/oura/ — Strategy, OAuth, Workouts, 247 Data components
  • app/api/routes/v1/oura_webhooks.py — Webhook notification + subscription management endpoints
  • app/static/provider-icons/oura.svg — Provider icon
  • tests/providers/oura/ — Test suite (5 test files)

Modified Files (10)

  • factory.py — Register OuraStrategy
  • config.py — Add Oura OAuth env vars
  • .env.example — Document Oura env vars
  • provider_settings_service.py — Enable Oura in provider list
  • routes/v1/__init__.py — Register webhook router
  • schemas/__init__.py — Export Oura schema classes
  • Test files — Add Oura fixtures, factory tests, settings test updates

Test plan

  • Ruff lint passes on all new files
  • Python imports work correctly (factory, strategy, all components)
  • Unit tests pass: pytest tests/providers/oura/ -v
  • Factory tests pass: pytest tests/providers/test_provider_factory.py -v
  • Settings tests pass: pytest tests/services/test_provider_settings_service.py -v
  • Full test suite: pytest -v
  • Manual OAuth flow test with Oura developer credentials

🤖 Generated with Claude Code

Implement full Oura Ring integration following the Strategy + Factory +
Template pattern. Includes OAuth2 authorization flow, workout import with
type mapping, 24/7 data collection (sleep, readiness, heart rate, daily
activity, SpO2), and webhook endpoints for real-time notifications.

Closes the-momentum#227

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@vikohone vikohone marked this pull request as draft February 10, 2026 12:02
vikohone and others added 2 commits February 11, 2026 15:02
Address PR review feedback from the-momentum#446 (Strava PR):
- Move all business logic from webhook routes to a dedicated service
  class (OuraWebhookService), keeping routes as thin handlers
- Use log_structured() instead of logger.info/error f-strings for
  structured JSON logging with queryable attributes
- Change oura_webhook_verification_token to SecretStr in config
- Add timestamp parsing tests for the webhook service

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Apply project code review checklist:
- Replace all self.logger f-string calls with log_structured() in
  data_247.py (15 calls) and workouts.py (2 calls)
- Fix type annotations: replace Any with DbSession and
  BaseProviderStrategy in webhook_service.py
- Remove unused db: DbSession params from 3 subscription route handlers
- Remove dead code: unused DataSourceRepository import and instance

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@bartmichalak
Copy link
Contributor

Hi @vikohone 👋

Thanks a lot for your contribution!

Someone from our team will be able to verify the changes this week. Manual code review is still very important to us, because as you can see for example here:
#446

agents can still make a lot of mistakes - but in many cases, it's a matter of the Agents.md files not describing all the conventions we use, so we'll be updating them after going through the latest integration PRs.

BTW, if you haven't joined our Discord yet, I highly recommend it!
https://discord.gg/qrcfFnNE6H

Copy link
Collaborator

@KaliszS KaliszS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi. I have done rebasing job (also fixed linter issues), so you have to fetch origin, if you want to continue editing that branch (otherwise you may face new conflicts if you try to push more commits).

In general, we cannot confirm whether this works, because (right now) we don't have an access to any Oura Ring. Could you provid some screenshoots (or a video maybe) with an example of syncing data from Oura to Open Wearables frontend, please?

}

@staticmethod
def _parse_data_timestamp(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't that something that should be handled within utils/dates.py?

@KaliszS
Copy link
Collaborator

KaliszS commented Mar 9, 2026

Hi @vikohone. Are you planning to continue work or should we take over this PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Provider request: Oura Ring

3 participants