Guides
Testing your integration
There is no separate sandbox. You test against the same service with an athlete account you control, which means what passes in testing behaves the same way in production.
Set up a test athlete
- Create a second CorrConnect account for testing, with an email address you can read (you'll need to verify it).
- Register a separate app for development, so your test grants and limits stay apart from production. An account can own up to 10 apps.
- Approve the development app with the test athlete, as in the Quickstart.
Add test data
Sign in as the test athlete and add activities in the portal:
- Upload a FIT file from your own watch or bike computer, or a GPX or TCX export. Each upload creates one record per session, track or activity, and sends
activity.created. - Import JSON summaries when you need exact values, for example a run with no distance to check your code handles
distance_.meters: null
Uploading the same file twice is ignored, so change the file (or use a different one) when you need a fresh event.
Test webhooks
- Point a subscription at a public HTTPS tunnel to your machine; plain-HTTP
localhostcallbacks aren't accepted by the hosted service. - Send a
webhook.testevent and check your signature check passes. - Then make it fail on purpose: change one byte of the body, or use a timestamp more than 5 minutes old. Both must be rejected.
- Return
500once and watch the retry arrive with the sameCorrConnect-Event-IdandCorrConnect-Delivery-Attempt: 2about a minute later.
Rehearse the endings
Run each of these with the test athlete and check your app recovers:
| Do this | Your app should see |
|---|---|
| Revoke the app in the athlete's CorrConnect account | grant.revoked, then 401 on calls |
Click your own Disconnect (calls POST /) | {"status": "revoked"}, then grant.revoked |
| Refresh twice with the same refresh token, a minute apart | invalid_grant on the second, then grant.revoked |
Approve again with only profile:read | 403 insufficient_ on /v1/activities |
| Wait an hour without refreshing | 401 invalid_, then a successful refresh |
Ask for scope=sleep:read | The authorize page stops with invalid_scope |
Check your limits
Every Bearer response with a valid token carries RateLimit-Remaining and X-RateLimit-User-Remaining. Log them during a backfill to see how close you run to the 100-per-15-minutes app limit and the 30-per-15-minutes limit for one athlete. Your test athlete's calls count against your development app only.