What the API exposes
| Capability | Scope required |
|---|---|
| List a pilot's flights | flights:read |
| Read a single flight (scoring, metadata, basic analysis) | flights:read |
| Upload an IGC flight on the pilot's behalf | flights:write |
| Delete a flight | flights:delete |
| Read the pilot's profile (name, club, CIVL id) | profile:read |
| Read the pilot's email address | profile:email |
| Update the pilot's profile (planned, not yet shipped) | profile:write |
| Read public community data (sites, leaderboards) (planned) | community:read |
The exhaustive scope list and what each grants is in the Scopes reference.
Three ways to authenticate
we-fly supports three credential flows, picked by how your integration runs:
| Flow | When to use | Doc |
|---|---|---|
| Client credentials (OAuth 2.0) | A backend you control accesses your own account programmatically (sync from another tracker, automated import, etc.) | Server-to-server |
| Authorization Code + PKCE (OAuth 2.0) | A third-party app or site wants to act on behalf of any we-fly user who grants consent | User authorization |
| Device code (RFC 8628) | A CLI tool, vario, or embedded device with no usable browser | Device authorization grant |
| API keys | Personal scripts, weekend hacks | Personal API keys |
All three end up presenting a Bearer token to the API. The difference
is how that token was obtained and which user it represents.
Base URL
https://we-fly.cloud
Use https:// only. The API does not redirect from http://; bad
schemes get a connection error.
Versioning
| Path prefix | Status |
|---|---|
/api/v1/... | Stable. Breaking changes require a new prefix (/api/v2/...) and a 6-month deprecation window with a Sunset header. |
/api/oauth/... | Stable. RFC 6749 / 7009 / 7662. The shapes of these endpoints are pinned by the RFCs. |
/.well-known/oauth-authorization-server | Stable. RFC 8414. |
Anything not under /api/v1/... or /api/oauth/... is not part of
the public contract — it's internal to the dashboard and may change
without notice.
Conventions
Request format
- All request bodies are JSON unless explicitly noted (the OAuth token endpoint and the upload endpoint accept additional content types per their respective specs).
- All headers and parameters are case-insensitive in name but
case-sensitive in value (so
Authorization: Bearer …works, butBearer wf_at_FOO≠Bearer wf_at_foo).
Response format
- Success:
2xxwith a JSON body shaped as{ "data": …, … }. - Failure:
4xx/5xxwith{ "error": "code", "error_description": "human prose" }. - Lists are wrapped in
{ "data": [...], "pagination": { … } }.
Time
- All timestamps are ISO 8601 in UTC with a trailing
Z("2026-05-27T14:30:00.000Z"). - The
flight_datefield is calendar-date only ("YYYY-MM-DD"), parsed from the IGCHFDTEheader.
IDs
- Flight IDs and user IDs are MongoDB hex ObjectIds (24 chars,
[a-f0-9]). - Client IDs are opaque strings prefixed
wf_app_. - Tokens are opaque strings prefixed
wf_at_(access) /wf_rt_(refresh) /wf_key_(API key) /wf_code_(authorization code) /wf_dc_(device code) /wf_secret_(client secret) /wf_whsec_(webhook signing secret). - The prefix is stable — your secret scanner can pattern-match on it.
Operational requirements
- Always send a
User-Agentthat identifies your integration. We use it in support requests and to scope rate-limit adjustments. Example:User-Agent: XContestSync/1.2 (+https://xcontest.org). - Honour
Retry-Afteron 429 responses. Hammering us when limited will get your app suspended. - Refresh tokens are single-use. See the refresh-token rotation rules — if you replay an old refresh token, your entire token chain is revoked and the user has to re-authorise.
- Never store secrets in client-side code (browser bundle, mobile
app binary). Public clients must use PKCE; confidential clients must
keep
clientSecretserver-side only.
Sandbox / staging
There is currently no separate sandbox environment. We recommend you
register a pending application against production and test with your
own account first — pending applications are restricted to read-only
scopes for their owner, so the blast radius is contained. Promote to
approved (admin action) once you're ready to onboard other users.