Concepts
Concepts
The objects Wind is built from, and how they relate.
Money everywhere is integer micro-cents, USD. 100_000_000 mc = $1.00 (1¢ = 1_000_000 mc). Money
fields end in _mc and responses also carry a _display string. IDs are prefixed
opaque strings.
Account
A Wind account (wac_…) has credentials (password or Google), optional MFA,
and a balance. “Developer” is a capability flag on the same account — it unlocks
app registration. There is no separate developer account.
App
An app_… is an OAuth client: client_id, client_secret, name, logo,
redirect_uris[] (exact-match, HTTPS), and an optional allowed_models[] —
leave it empty to allow any model Wind offers, or list models to restrict the
app to them (the list is also shown on the consent screen). Not a per-connection scope. Also default_max_tokens, a tier
(sandbox · limited-live · full-live), a provider_mode (mock / live), and a test_allowlist of who may test it. In sandbox it’s used by your test accounts — fake users with fake balances.
Connection
A conn_… is the grant — unique per (app, user). It holds
reserved_allocation_mc (non-refilling), consumed_mc, held_mc, an optional
velocity_limit_mc, and a status (active · exhausted · revoked · frozen). Grants
are persistent (no expiry) for now. The connection’s access token is the
connection.
Reserved allocation & holds
The user’s balance splits into available and reserved. Connecting moves
min(requested, available) from available → reserved, ring-fenced to that
connection. Each in-flight request places an authorization hold:
allocation_remaining = allocation_mc − consumed_mc − held_mc
Wind estimates a request’s max cost from counted input tokens + max_tokens at
the model’s rates (× multiplier, + ~5% margin). If it doesn’t fit
allocation_remaining, the call is rejected before any provider spend. On
completion the ledger records the actual cost and the remainder is released.
Holds auto-expire (~5 min) so a crashed request can’t strand funds.
Velocity limit
An optional per-connection cap on spend rate (e.g. $/day) within the allocation. Bounds how fast a compromised app can drain the cap.
Features
Dev-defined, lightly-registered, non-gating labels: a slug
([a-z0-9-]{1,40}), display_name, description (both surface on the consent
screen), and optional guardrails (max_cost_per_call_mc, max_tokens,
rate_limit, default_model). Send one as the X-Wind-Feature header, or call POST /v1/ai/features/{slug} to use the feature’s default_model; it lands
on LedgerEntry.feature and becomes the primary axis in your usage analytics.
Unregistered slugs still work — they show as “other”.
Ledger & the four numbers
Every request writes one immutable led_… row:
| Field | Meaning |
|---|---|
provider_cost_mc | what Wind paid the provider |
wind_fee_mc | Wind’s service fee |
dev_margin_mc | your multiplier margin |
user_charge_mc | what the user’s balance was debited |
Plus connection_id, feature, model, request_id, and status
(settled · reversed). Every analytics slice and every reversal derives from
this row.
Fees & multiplier pricing
user_charge = provider_cost × your_multiplier + wind_fee. One multiplier per
app for now; per-feature multipliers are a v2 feature policy.
Sandbox & the go-live ladder
An app is in sandbox until it’s promoted. Sandbox uses a fake per-account
balance and a mock or live models provider. Real money and real end users
only enter at limited-live. See Sandbox & going live.