Skip to main content
Chappie gives you programmatic control over which model handles each conversation and live visibility into how much of your usage quota remains. Models are fetched from the server at runtime, so your app always reflects the latest available options rather than a hard-coded list. Usage data arrives both as an on-demand snapshot from the rate-limits endpoint and as a mid-stream event during active responses.

Default Model

The default model is gpt-5.5. ChappieClient.defaultModel exposes this constant if you want to reference it programmatically:

Listing Available Models

Call models() to fetch the server’s current model list. The results are sorted by the server-assigned priority field, so the best available model appears first.

Filtering Models

Pass a ChappieModelFilter to narrow the list to models that match your requirements:
ChappieModelFilter accepts any combination of:
Bool?
Include only models the API accepts for ChappieResponseRequest. Set this to true for any model you plan to use with send or stream.
String?
Filter by input modality string, e.g. "text". A model is included if its inputModalities array contains this value.
Bool?
Include only models that support (or don’t support) the web search tool.
Bool?
Include only models that support (or don’t support) parallel tool calls.
String?
Include only models that list the given reasoning effort level in their supportedReasoningLevels array.

Selecting a Model

Change the active model for a client instance at any time. All subsequent turns will use the new model until you change it again.
selectModel(_:) is @discardableResult — it returns the new ChappieClientContext snapshot, but you can ignore it if you only need the side effect.

Best Available and Fallback Helpers

Two convenience methods resolve a model from the live list without you having to iterate manually:
Both methods default to filtering for supportedInAPI: true and inputModality: "text". Pass a custom ChappieModelFilter to change the criteria.

ChappieModel Properties

Each ChappieModel in the returned array exposes the following properties:

Checking Usage Limits

Call usageLimits() to fetch a live ChappieUsageLimitSnapshot from the rate-limits endpoint:
ChappieUsageLimitSnapshot has three window fields:
  • primaryChappieUsageLimitWindow with usedPercent, windowMinutes, and resetsAt.
  • secondary — An additional window some plans expose (e.g., a monthly cap alongside an hourly cap).
  • creditsChappieCreditsSnapshot with hasCredits, unlimited, and balance.
You also receive a .usageLimits(snapshot) event mid-stream during active responses, so you can keep a live counter without an extra network call.

Account and Plan Info

Read account details and the current plan from the locally cached credential:
To refresh the plan from the server (which calls usageLimits() internally and updates the stored credential):

ChappiePlan Values

Plans are represented by ChappiePlan, a struct with rawValue and displayName properties. The SDK maps the following raw values to display names:
Unknown raw values are title-cased automatically (my_custom_planMy Custom Plan).

Handling Usage Limit Errors

When a request is rejected because the user has hit their quota, the SDK throws ChappieClientError.usageLimitReached(_:) with a ChappieUsageLimit payload. The payload includes the plan, a reset timestamp, and a human-readable message.
ChappieUsageLimit exposes:
ChappiePlan?
The plan associated with the limit that was reached.
Date?
When the quota window resets. Display this to users so they know how long to wait.
TimeInterval?
The same reset as a countdown in seconds, when available.
String?
A human-readable message from the server describing the limit.
String?
The name of the active limit bucket that was reached (sourced from the x-codex-active-limit response header).
Rate-limit errors on streaming responses are thrown from the for try await loop, not returned as an event. Always wrap streaming iterations in a do/catch and handle ChappieClientError.usageLimitReached alongside your other error cases.