Wind Wind / Docs
Dashboard →

Protocol

Authentication

The auth-code + PKCE flow, access & refresh tokens, and client credentials.

Wind uses redirect-only OAuth 2.0 authorization code + PKCE. There is no Link mode, no popup mode, and no sk_live_ API key. Three distinct things do the work:

  1. Client credentials (client_id + client_secret) — identify your app, used with HTTP Basic on /oauth/token and the management endpoints.
  2. Access token — bearer credential for POST /v1/ai/*; it is the connection. Short-lived (~15 min).
  3. Refresh token — mints new access tokens. ~90 days, rotates on every use, scoped to one connection.

Authorize

GET accounts.usewind.app/oauth/authorize browser redirect
ParamRequiredNotes
response_typeyescode
client_idyesapp_…
redirect_uriyesexact match against a registered URI
code_challengeyesbase64url(sha256(verifier))
code_challenge_methodyesS256
stateyesCSRF token you generate and later verify
requested_allocation_mcnopre-fills the spend cap the user edits
featuresnocomma list of feature slugs — names the consent “what for” line

The user logs in (email link / password / Continue with Google), sees the consent screen, sets the allocation, and approves. Wind redirects to your redirect_uri with ?code=…&state=…. The code is single-use, ~60 s TTL, and useless without the client secret and PKCE verifier.

Token exchange

POST api.usewind.app/oauth/token Basic client_id:client_secret
grant_type=authorization_code
code=<code>
redirect_uri=<same as authorize>
code_verifier=<verifier>

→ { access_token, expires_in, refresh_token, connection_id, allocation_mc, ... }

Persist { connection_id, refresh_token } on the app’s user record; cache the access_token with its expiry.

Refresh

POST api.usewind.app/oauth/token Basic client_id:client_secret
grant_type=refresh_token
refresh_token=<current>

→ { access_token, expires_in, refresh_token }   # new refresh_token — store it

Rotation is atomic or bust

Each refresh invalidates the previous refresh token. If you fetch a new one but crash before persisting it, that connection is dead and the user must re-connect. Write it in the same transaction as the work that used it.

Content is closer to a payment authorization than a scope list: the app (name, logo, verification state), the spend cap (pre-filled, editable, shown against the balance), a one-line feature-derived “what for” sentence, an optional velocity limit, a collapsed model/provider disclosure, and how to revoke. New features do not re-prompt.