Fleeexdocs

Choosing a model

Pass an alias rather than a versioned provider id, and ask which models your app may call instead of hardcoding a list.

Two things about model are where an OpenAI habit stops being true: which ids exist, and which of them your app is allowed to call. Neither is guessable, and both are answerable with one request.

Pass an alias

Send a stable public name such as nova-lite rather than the versioned provider id it resolves to (amazon.nova-lite-v1:0). Both are valid values for model, but the alias is the one that survives the next model revision: Fleeex re-points it, and your code doesn't change.

await client.chat.completions.create({
  model: "nova-lite", // not "amazon.nova-lite-v1:0"
  messages: [{ role: "user", content: "Hello!" }],
});

The response echoes the resolved id, in completion.model and on every chunk of a stream. That's what OpenAI does when a family name resolves to a dated snapshot, and it's the only way a caller using an alias can see which model actually answered and was charged. Your usage events record the resolved id too, so billing history stays auditable across a re-point.

Which models you may call depends on your app

Model licences don't all permit resale, so the catalog records a resale right per model, and the proprietary families are reserved for FlexCorp's own apps. A third-party app neither sees them in the catalog nor may call them.

So if the list is shorter than you expected, that is the reason. It isn't a bug, and it isn't something a retry, a different key, or a funded wallet changes:

  • GET /v1/models omits what your app may not use, rather than listing it and refusing it. Everything it returns is callable.
  • Asking for a reserved model by name is a 403 with code MODEL_NOT_ENTITLED, naming the model and the remedy. It reaches no provider and reserves nothing.
  • A model nobody serves is a different answer: a 400 on a completion, a 404 on GET /v1/models/{model}.

Open-weight models and Amazon Nova carry no such restriction and are open to any app, which is why every example on this site uses nova-lite.

List the models you may call

GET /v1/models answers in OpenAI's own list shape, scoped to the app your key belongs to. FleeexClient wraps chat completions only, so list with the OpenAI client (already a peer dependency) pointed at the same base URL.

Unlike a completion, discovery needs no x-fleeex-user: 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.

catalog.ts
import OpenAI from "openai";
 
const catalog = new OpenAI({
  apiKey: process.env.FLEEEX_API_KEY!,
  baseURL: "https://api.fleeex.dev/v1", // note the trailing /v1
  // no x-fleeex-user: deliberately not required here
});
 
const page = await catalog.models.list();
for await (const model of page) {
  console.log(model.id, model.owned_by); // e.g. "nova-lite" "amazon"
}

Aliases are listed next to the ids they resolve to. Both are usable values for model, the way a provider lists a family name next to a dated snapshot. Hiding the alias would make the list wrong.

FieldValue
idWhat to send as model: a catalog id, or an alias that resolves to one.
object"model".
createdAlways 0. Fleeex records no creation date for a catalog entry, and a fabricated one would both claim a moment nobody knows and make an otherwise identical response change on every request.
owned_byDerived from the provider prefix of the resolved id (anthropic.claude-… → anthropic), so an alias reports the provider that owns the model it points at.

Nothing Fleeex-specific (price, margin, resale right) appears here. The body is OpenAI's exact key set, because a strict client decoder fails on an unknown property.

Describe one model

const model = await catalog.models.retrieve("nova-lite"); // alias or provider id

The two failure modes are deliberately different answers:

AnswerMeaning
404No model or alias by that name is served here. Check for a typo.
403 MODEL_NOT_ENTITLEDThe model is real, and reserved for other apps.

The list omits the reserved one because a list is "what you can use". A caller that asks about a specific model is told which of the two situations it's in, instead of hunting for a typo that doesn't exist.