CorrConnectDocs
Early accessRequest access

Platform

Rate limits

The free tier is per app and costs nothing. Every response tells you where you stand, so you never have to guess.

The free tier

LimitPer 15 minutesPer day
Your app, across all its athletes and tokens10010,000
One athlete within your app302,000

These count requests to the Bearer API: GET /v1/profile, GET /v1/activities and GET /v1/activities/{activity_id}. Token exchange, refresh, revocation and webhooks don't count. A request that is turned away with 429 doesn't count either.

The per-athlete limit stops one busy account from using your whole budget. If we raise your app's limits, the per-athlete limit grows with them, to 30% of the 15-minute limit and 20% of the daily one, and never below 30 and 2,000 unless the app limit itself is lower.

Need more?

Email [email protected] with your client_id, what you're building and the volume you expect. There is no form in the console yet. Once raised, GET /v1/developer/apps shows "tier": "custom" and the new numbers. There is no charge.

Headers on Bearer responses

Every Bearer response that gets past the token check carries these, including 403, 404 and 429 rate_limit_exceeded. A 401 invalid_access_token and a 429 service_capacity_exceeded don't, because neither is counted against your app.

HeaderMeaning
RateLimit-PolicyYour app's windows, for example 100;w=900, 10000;w=86400
RateLimit-Limit, RateLimit-RemainingThe app window closest to running out
RateLimit-ResetSeconds until that window resets
X-RateLimit-Limit, X-RateLimit-RemainingThe same window, older header names
X-RateLimit-ResetWhen that window resets, as Unix seconds
X-RateLimit-User-Limit, X-RateLimit-User-Remaining, X-RateLimit-User-ResetThis athlete's window closest to running out; reset in Unix seconds

The RateLimit-* headers follow the IETF HTTP API rate-limit draft. Note the two reset styles: RateLimit-Reset is a number of seconds, X-RateLimit-Reset is a timestamp.

When you hit a limit

You get 429 rate_limit_exceeded with Retry-After in seconds:

JSON
{
  "code": "rate_limit_exceeded",
  "message": "This app has used its request limit for this athlete; retry after 37 seconds.",
  "request_id": "req_...",
  "details": {"scope": "athlete", "per_15_minutes": 100, "per_day": 10000, "per_athlete_per_15_minutes": 30, "per_athlete_per_day": 2000}
}

details.scope is app when your whole app ran out and athlete when one athlete did. Pause the affected work until Retry-After has passed. For athlete, other athletes' requests still go through.

The shared ceiling

All third-party apps together share a ceiling of 50 requests per second, with bursts to 100. When it's reached you get 429 service_capacity_exceeded with Retry-After. It keeps response times steady for everyone, and it isn't counted against your app.

Token endpoint

POST /oauth/token counts failures, not successes, so a stranger who knows your public client_id can't lock out your real traffic:

WhatLimit per minuteAnswer
Failed requests from one address for one app20429 slow_down
Requests with a malformed client_id from one address60429 slow_down
Successful exchanges and refreshes for one app3,000429 slow_down
Any token requests from one address600429 slow_down

Failures across all addresses for one app (up to 600 a minute) are counted for our alerting but never block a valid request. The check and the count are separate steps, so a burst of parallel requests can pass a limit by at most the number in flight.

Other limits

WhatLimit
Athlete approvals (consent submissions)60 an hour per athlete
Account sign-ups5 an hour per network address
Sign-in attempts10 per 15 minutes per network address
App registrations20 an hour per account, 60 an hour per network address
Apps per account10
Webhook subscriptions per app3
Workout file uploads20 an hour per athlete