How to Integrate the Oura API (2026)
Updated July 9, 2026
The Oura API v2 gives you a connected user's sleep, activity, readiness, heart rate, workouts, and SpO2 as clean daily summaries and time series over a simple REST base at https://api.ouraring.com/v2/. Auth is OAuth 2.0 Authorization Code — you send the user to Oura's consent screen, exchange the returned code for an access token, then call usercollection/* endpoints with a Bearer token. Registration is self-serve, so you can start building in minutes.
Two things to internalize before you write code, because they shape your whole plan:
- Personal Access Tokens are deprecated (December 2025). New PATs can no longer be created, and new integrations must use OAuth 2.0 only. If a tutorial tells you to paste a personal token, it is out of date. (Previously issued PATs may still function during a transition period — verify against the current docs.)
- There is a 10-user cap until Oura approves your app. A freshly registered app can connect at most 10 Oura users. To go beyond that you must submit the app for Oura's review; after approval the limit is lifted. Plan for that approval step before any public launch.
If you are still choosing a provider or comparing device coverage, see our overview of wearable data APIs. Oura is often evaluated alongside recovery-focused bands — our WHOOP API guide covers that neighboring integration.
What you'll need
- An Oura account and an Oura Ring with an active membership on the test user's side (some data requires an active subscription).
- An app registered in the Oura developer portal, which gives you a
client_idandclient_secret. - A registered redirect URI (your OAuth callback), served over HTTPS in production.
- A server-side place to store tokens — you exchange the authorization code and store the access and refresh tokens on your backend, never in the client.
Step 1: Register your app and get credentials
In the Oura developer portal, create a new application. Set a name and one or more redirect URIs (these must match exactly at authorization time). Oura issues a client_id and a client_secret — treat the secret like a password and keep it server-side only.
Note your app starts under the 10-user cap. That is enough to build and test; request approval later when you are ready for more users.
Step 2: Send the user to the authorization URL
Redirect the user to Oura's authorize endpoint with the scopes you need. As of 2026 there are 8 scopes (verify the current set in the docs):
| Scope | Grants |
|---|---|
email | User's email address |
personal | Personal info (gender, age, height, weight) |
daily | Daily summaries — sleep, activity, readiness |
heartrate | Time-series heart rate (Gen 3+) |
workout | Auto-detected and user-entered workouts |
tag | User-entered tags |
session | Guided and unguided sessions in the Oura app |
spo2 | Daily SpO2 average recorded during sleep |
Request only the scopes you actually use — the user can toggle individual scopes at the consent screen. Build the authorize URL against https://cloud.ouraring.com/oauth/authorize:
GET https://cloud.ouraring.com/oauth/authorize
?response_type=code
&client_id=YOUR_CLIENT_ID
&redirect_uri=https://yourapp.com/oauth/oura/callback
&scope=daily heartrate workout spo2
&state=RANDOM_ANTI_CSRF_STRING
Generate state per request and verify it on the callback to defend against CSRF. After the user consents, Oura redirects to your redirect_uri with ?code=...&state=....
Step 3: Exchange the code for tokens
On your callback, verify state, then POST the code to the token endpoint https://api.ouraring.com/oauth/token to receive an access token and a refresh token:
curl -s -X POST "https://api.ouraring.com/oauth/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=AUTHORIZATION_CODE" \
-d "redirect_uri=https://yourapp.com/oauth/oura/callback" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"
The response contains an access_token, a refresh_token, and a token_type of Bearer. Store both tokens on your backend, mapped to your internal user ID.
Here is the same exchange in TypeScript:
const res = await fetch("https://api.ouraring.com/oauth/token", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "authorization_code",
code,
redirect_uri: "https://yourapp.com/oauth/oura/callback",
client_id: process.env.OURA_CLIENT_ID!,
client_secret: process.env.OURA_CLIENT_SECRET!,
}),
});
const { access_token, refresh_token } = await res.json();
// persist both, keyed to your user
Step 4: Fetch data from the usercollection endpoints
All data lives under the base https://api.ouraring.com/v2/ at usercollection/* paths. List endpoints accept start_date and end_date (ISO dates); you can also fetch a single document by its document_id. Send the access token as a Bearer header:
curl -s \
-H "Authorization: Bearer ${OURA_ACCESS_TOKEN}" \
"https://api.ouraring.com/v2/usercollection/daily_activity?start_date=2026-07-01&end_date=2026-07-09"
The response wraps records in a data array with a next_token for pagination:
{
"data": [
{
"id": "…",
"day": "2026-07-08",
"score": 82,
"active_calories": 512,
"steps": 9231
}
],
"next_token": null
}
Commonly used usercollection endpoints (confirm the exact set for your scopes at https://api.ouraring.com/v2/docs):
| Endpoint | What it returns |
|---|---|
daily_activity | Daily activity score, steps, calories |
daily_sleep | Daily sleep score and contributors |
daily_readiness | Daily readiness score |
heartrate | Time-series heart rate (Gen 3+) |
workout | Auto-detected and entered workouts |
daily_spo2 | Daily average SpO2 during sleep |
A 403 here usually means the token is missing the required scope, or the user's Oura subscription has lapsed — not a bad token.
Step 5: Paginate and refresh tokens
For a date range that returns more rows than one page, follow next_token: when it is non-null, repeat the request passing it back to Oura until it comes back null. When an access token expires, exchange the stored refresh token for a new pair:
curl -s -X POST "https://api.ouraring.com/oauth/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token" \
-d "refresh_token=STORED_REFRESH_TOKEN" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"
Persist the newly returned tokens and retry the original request. Refresh on a 401, or proactively before expiry.
Step 6: Request app approval before you scale
Once you are past testing, submit your app for Oura's review to lift the 10-user cap. Until approval clears, the eleventh user's authorization will fail, so gate any public rollout on it. Approval is also where Oura checks how you use and store health data, so have your privacy handling ready.
Gotchas and production notes
- OAuth only. PATs are deprecated (Dec 2025) and cannot be created for new integrations — build the OAuth flow from day one.
- The 10-user cap is real. It blocks scale, not testing. Submit for approval well before launch; do not discover the cap in production.
- Scopes gate data, and a 403 is usually a scope or membership problem, not an auth bug. Request the minimum scopes, and remember users can disable individual scopes at consent.
- Some metrics need hardware or a subscription. Time-series heart rate needs a Gen 3 ring or newer, and certain data requires an active Oura membership.
- Store tokens server-side. Do the code exchange and all refreshes on your backend; never ship the
client_secretto a client. - Verify volatile details. Treat the exact scope list, endpoint set, and any PAT transition behavior as things to confirm against the live docs at
https://api.ouraring.com/v2/docs, since Oura updates them.
For where Oura fits among recovery and sleep-tracking sources, and how to avoid integrating a dozen wearables one at a time, see our wearable data APIs overview.
Frequently asked questions
- Does the Oura API still support Personal Access Tokens?
- No for new integrations. Oura deprecated Personal Access Tokens in December 2025, so new PATs can no longer be created and new integrations must use OAuth 2.0 only. Previously issued PATs may still function during a transition period, but you should not build on them; verify the current status in Oura's docs.
- Does the Oura API require approval?
- Registration is self-serve, but a freshly registered app can connect at most 10 Oura users until Oura approves it. You build and test freely under that cap, then submit the app for Oura's review to lift the limit before a public launch. Plan for that approval step in your timeline.
- What OAuth endpoints and scopes does Oura use?
- Authorize at https://cloud.ouraring.com/oauth/authorize and exchange or refresh tokens at https://api.ouraring.com/oauth/token. As of 2026 there are eight scopes: email, personal, daily, heartrate, workout, tag, session, and spo2, and the user can toggle individual scopes at consent. Request only what you need and verify the current list in the docs.
- Why am I getting a 403 from a usercollection endpoint?
- A 403 on an Oura v2 endpoint usually means the access token is missing the scope that endpoint requires, or the user's Oura subscription has lapsed. It is generally a scope or membership problem rather than an invalid token, so check the scopes you requested and the user's membership status before assuming an auth bug.
- What data can I read from the Oura API v2?
- Under https://api.ouraring.com/v2/ the usercollection endpoints expose daily summaries and time series, including daily_activity, daily_sleep, daily_readiness, heartrate, workout, and daily_spo2, among others. List endpoints accept start_date and end_date, and you can fetch a single document by its id. Confirm the exact endpoint set for your scopes at https://api.ouraring.com/v2/docs.
Keep reading
Independent comparison, last reviewed July 9, 2026. Pricing, rate limits, and feature availability change often — confirm current details in each provider’s official documentation before you commit. Product and company names are trademarks of their respective owners; AIFitnessAPI is not affiliated with, endorsed by, or sponsored by any product listed here.
← All integration guides · by AIFitnessAPI