Authentication
The two credentials every Fleeex call carries, your app API key and the end-user id you vouch for.
Every call the SDK makes carries two pieces of identity. Getting them right is what makes metering correct and per-user.
| Credential | SDK option | Sent as | Identifies |
|---|---|---|---|
| API key | apiKey | Authorization: Bearer <key> | Your app. |
| End-user id | userId | x-fleeex-user: <id> | The end user the call is for. |
const client = new FleeexClient({
apiKey: process.env.FLEEEX_API_KEY!, // flx_…
userId: "user-123",
});The API key (flx_…)
- It authenticates your app. Issue and rotate keys from your Fleeex account (the dashboard, or control plane).
- It's a server-side secret. A leaked key impersonates your app, so never ship it in a browser, mobile bundle, or public repo. Keep it in an environment variable or a secrets manager.
A key is minted for one of two worlds, decided when it is issued and never changed. A
live key (flx_…) spends real money; a test key (flx_test_…) spends a fake balance and
calls no model provider. The prefix tells you which, and no gesture promotes one to the
other. See Sandbox.
The user id (x-fleeex-user)
- This is your own identifier for the end user, whatever your app already uses. Fleeex trusts your app for its own users' identity, and the id never crosses your app boundary.
- It's what makes usage and billing per user: each
(app, user)pair maps to a wallet identity.
The value becomes part of a storage key, so it is bounded. Send something that fits, or
the request is a 400 that names the rule (and never echoes your value back):
| Rule | Value |
|---|---|
| Length | 1 to 256 characters, trimmed; blank counts as absent |
| Charset | printable ASCII, no whitespace |
An email (254 characters at most), a UUID, or any opaque provider id all fit comfortably.
Which routes need it: the proxy, getBalance(), getConnection() and
getUsageSummary() all require it, and answer their own 400 when it's absent.
GET /v1/models deliberately does not, because the catalog is a property of your app
rather than of one of its end users, so a client can enumerate models before it has a
user. See Choosing a model.
One FleeexClient is bound to one userId. Handling many users? Create a client per
user (they're cheap), or set the header per request with the raw OpenAI SDK (see
Drop back to raw OpenAI).
Control plane vs. data plane
The SDK operates on the data plane: proxied AI calls and read-only billing helpers, authenticated by the app API key. Managing the account itself (funding the wallet, creating apps, issuing keys) is a separate control plane, the dashboard. So an app key can spend against a wallet but can never top it up or mint new keys.
Tracing a call
Every response carries an x-correlation-id, and the same id appears in the
error envelope. Send your own to tie a Fleeex
call to a request in your own logs:
const client = new FleeexClient({
apiKey,
userId,
defaultHeaders: { "x-correlation-id": requestId },
});It's the only handle that ties a failure you saw to the server-side record of it, so log it whenever you catch an error.
Your value is kept only if it's at most 64 characters of A–Z a–z 0–9 _ . : -; anything
else is silently replaced by a fresh id. So read the id back off the response rather than
assuming the one you sent was used. A UUID or a trace id fits; a URL or a JSON blob does
not.
Next
- Quickstart: make a call.
- Choosing a model: which models your app may call.
- Balance and payments: read the balance and handle the
402top-up flow.