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:
- Client credentials (
client_id+client_secret) — identify your app, used with HTTP Basic on/oauth/tokenand the management endpoints. - Access token — bearer credential for
POST /v1/ai/*; it is the connection. Short-lived (~15 min). - Refresh token — mints new access tokens. ~90 days, rotates on every use, scoped to one connection.
Authorize
accounts.usewind.app/oauth/authorize browser redirect | Param | Required | Notes |
|---|---|---|
response_type | yes | code |
client_id | yes | app_… |
redirect_uri | yes | exact match against a registered URI |
code_challenge | yes | base64url(sha256(verifier)) |
code_challenge_method | yes | S256 |
state | yes | CSRF token you generate and later verify |
requested_allocation_mc | no | pre-fills the spend cap the user edits |
features | no | comma 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
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
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.
The consent screen
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.