Kimi (subscription) kimi¶
Moonshot's Kimi coding backend spoken with a Kimi subscription from the shared pool.
Routes are kimi/<model> over plain openai-chat; the pinned model
is kimi/kimi-for-coding. Who may spend the account is the
entitlement decision; the account itself is a
subscription. Not to be confused with
moonshot, the API-key platform route.
How we sign in¶
Kimi has no local CLI that can mint or refresh a subscription credential: the grant
comes out of the kimi.com OAuth sign-in in a real browser. On this fleet that browser is
Weles's, on Weles's own host: Weles exposes the sign-in as
POST /reauth on its worker API, drives its stored sign-in row for the account,
and writes the minted grant into the Skarbiec vault at
provider:kimi:<subscription>. The proof is the vault bundle at a higher
revision and a refresh that answers refreshed — never the login's own exit
status.
Drivers: brama subscription login kimi --by weles --reason "<why>" on the
host Weles runs on
(cli), the renewal
loop, Brama Desktop, or a signed donation through
POST /v1/subscription-pool
(donation).
The grant on disk¶
The simplest of the three subscription shapes — a flat OAuth object:
{
"access_token": "<short-lived bearer>",
"refresh_token": "<rotating refresh token>",
"expires_at": 1756150000
}
expires_at is epoch seconds, written back on every refresh from the token
endpoint's expires_in; the gateway also accepts expiresAt,
expires and expiry, and reads the access token's JWT
exp claim when the blob states nothing
(src/gateway/oauth_refresh.rs). The item carries the discovery tags
(brama:subscription, brama:agent:<agent>,
brama:provider:kimi, brama:id:<id>); the agent tag only records
who banked the account. Losing the brama:subscription mark makes the account
unroutable, and /readyz names it under unroutable_accounts.
How a request presents it¶
At final use the gateway redeems the vault item through the local entitlements router,
reduces it to the access token, and sends
Authorization: Bearer <access_token> — nothing provider-specific beyond
that. No copy of the token outlives the request.
Refresh¶
Once a token expires the gateway posts grant_type=refresh_token with the stored
refresh token and the public client id
17e5f671-d194-4dfb-9706-5516cb48c098 to
https://auth.kimi.com/api/oauth/token, form-encoded. The answer is read whole.
Completion and response handling follow the core request contract.
Each brama maintain pass refreshes every active
credential whose stated expiry has passed, single-flighted per subscription; a
token is used until that instant. The refresh token rotates on issue, so a refreshed grant that cannot be written
back to the vault is a failed refresh. brama subscription refresh kimi --reason
"<why>" forces the same path now and journals the reason. Refreshing
costs no plan quota.
When the provider disowns the grant¶
A refused refresh is definitive only on the provider's own evidence —
invalid_grant, invalid_token, revoked,
unauthorized_client, or a 401/403 with no stated reason. That records
credential.state: needs_reauthorization with the provider's sentence as
cause, blocks the account for 30 minutes, lists it burnt, and waits
for the sign-in above; everything else is transient and left for the next sweep
(subscription,
runbook).
Plan usage¶
Kimi publishes a free usage report at
https://api.kimi.com/coding/v1/usages, issued to exactly the OAuth bearer the
chat route already presents — reading it costs no quota. The ledger records each window
with its instant and source
(subscription).
Endpoints¶
| Chat | https://api.kimi.com/coding/v1/chat/completions |
| Model discovery | https://api.kimi.com/coding/v1/models, widening the pinned row kimi-for-coding |
| Token endpoint | https://auth.kimi.com/api/oauth/token (form wire) |
| Usage report | https://api.kimi.com/coding/v1/usages |
| Trusted host | api.kimi.com |
| Base URL override | BRAMA_PROVIDER_KIMI_BASE_URL, validated with the refusals in provider |