# Personal subscriptions Source: https://docs.getlilac.com/billing/subscription-rates Lilac personal subscriptions bundle monthly included model usage with live per-model discounts. Personal subscriptions are monthly plans for individual, non-commercial inference. Each plan includes a monthly pool of dollar-denominated model usage that runs against the same [OpenAI-compatible inference API](/inference/openai-compatibility) as prepaid credits. Eligible models can consume that included usage at lower rates when compatible GPU supply is more idle. At the deepest idle-supply discount, the same included usage covers up to four times the standard model usage. Higher plans include more monthly usage and more concurrency. See the public [subscriptions page](https://getlilac.com/subscriptions), or start and manage a plan from [console.getlilac.com/plans](https://console.getlilac.com/plans). Personal subscriptions are for **individual, non-commercial use only**. They are not available for organization billing, and one plan is allowed per user. Commercial workloads, shared access, or abuse may result in suspension. ## Plans | Plan | Price | Included monthly usage | Concurrency | | ----- | ------------- | ---------------------- | ----------- | | Basic | \$10 / month | \$20 of model usage | 2 | | Pro | \$30 / month | \$75 of model usage | 3 | | Max | \$100 / month | \$300 of model usage | 4 | Included usage is **dollar-denominated model usage**. It pays for the same per-token rates as credits, but comes from your subscription balance instead of prepaid credits. It is tracked separately from credits and does not roll over. ## Live per-model discounts While you're spending from included subscription usage, each model also has a **live discount** based on current supply. The discount applies to how much included usage a request consumes: | Supply state | Discount | Usage multiplier | | ------------ | -------- | ---------------- | | Low | 0% off | 1.00× | | Medium | 25% off | 0.75× | | High | 50% off | 0.50× | | Surplus | 75% off | 0.25× | Discounts refresh approximately every 10 minutes and are locked in **when a request starts**. They are not guaranteed to stay the same between requests. Stacked with included usage, Max can deliver up to **12× the model usage per subscription dollar** versus credits: \$100 buys \$300 of included usage (3×), and a model at a 75% subscription discount stretches that 4× further. Pro delivers up to **10×** at its 2.5× included-usage multiplier. ### Example A Max subscriber pays \$100/month and receives \$300 of included model usage. If GLM is currently 75% off for subscriptions, a request that would normally use \$1.00 of model usage uses \$0.25 from the subscription balance. ## Where to check current discounts * **Billing page:** the "Live subscription discounts" panel. * **Model cards and model detail pages:** shown on personal accounts. * **Playground:** the model picker when you're in Subscription mode. * **Public status endpoint:** `GET /status` returns the top-level `current_subscription_supply_updated_at` plus per-model fields: * Top-level: * `current_subscription_supply_updated_at` * Per model: * `current_subscription_supply_state` * `current_subscription_discount_percent` * `current_subscription_credit_multiplier` ## Usage controls Included usage is constrained by the monthly billing period plus two reset windows. The 5-hour and 7-day windows start when your first subscription-funded request is admitted after no active window exists, then reset at the shown reset time. All windows are visible in the billing page usage panel. | Window | Cap | | ------- | ---------------------------------------------------------------------------- | | Monthly | 100% of plan's included usage (resets when the Stripe billing period renews) | | 7 days | 50% of plan's included usage | | 5 hours | 25% of plan's included usage | If a subscription window is exhausted, subscription-funded requests are blocked until that window resets. API keys with credit fallback enabled can continue on prepaid credits. ## Using subscriptions from the API Personal API keys can be set to one of two billing modes: * **Credits:** requests draw from prepaid credits. * **Subscription:** requests draw from your subscription's included usage at the current live discount. Subscription keys can optionally **fall back to prepaid credits** when subscription usage is unavailable. Fallback covers: * Monthly included usage exhausted * 5-hour or 7-day usage window exhausted The Playground does **not** fall back automatically. Switch between **Credits** and **Subscription** mode manually in the playground UI. ## Managing your plan * **Upgrades** are requested in Lilac and confirmed through Stripe. The new plan takes effect once Stripe confirms, and the price difference is **pro-rated** for the remainder of the current billing period. Included usage is recalculated at the new plan's included-usage multiplier (Basic 2×, Pro 2.5×, Max 3×) on what you've paid, minus what you've already used. For example: on Basic you pay \$10 and get \$20 of included usage. Upgrade to Pro halfway through the month for an extra \$20 and your included usage becomes 2.5 × \$30 = \$75, minus anything already spent. * **Downgrades** generally take effect at the next billing period. * **Payment methods, invoices, and cancellation** are handled through the Stripe customer portal linked from the billing page. Subscriptions require Stripe-supported recurring payment methods. Crypto and other one-time-only payment methods may be available for prepaid credits, but not for recurring subscriptions. ## FAQ No. Discounts depend on current supply for each model and can change at any time. The discount that applies to a request is the one in effect when the request starts. Requests stop drawing from subscription usage. If your API key has fallback to credits enabled, requests continue against your prepaid credit balance. Otherwise they are rate-limited until the relevant window resets. No. Subscription discounts apply only to subscription-funded requests. Requests paid with credits always bill at standard per-token rates. The console model pages, the billing page's "Live subscription discounts" panel, the playground model picker in Subscription mode, or the public `GET /status` endpoint. ## Related * [API Keys](/inference/api-keys) * [Pricing](/inference/pricing) * [Usage & Billing](/inference/usage) * [Status endpoint](/inference/status) # Dedicated GPUs Source: https://docs.getlilac.com/dedicated-gpus/overview Source dedicated GPU virtual machines, bare-metal nodes, and private multi-node clusters through Lilac's network. Lilac helps teams source dedicated GPU capacity when reserved hardware is a better fit than the pay-per-token [serverless inference](/inference/quickstart) network. ## What Lilac offers Capacity sourced through Lilac's network of GPU providers: * **Dedicated GPU virtual machines** for reserved workloads. * **Bare-metal GPU nodes** where full hardware control is required. * **Private multi-node clusters** for distributed training and larger deployments. Lilac coordinates sourcing across this network. Underlying machines and facilities are operated by the providers Lilac works with. ## Who it is for Teams whose workloads require: * Reserved, non-shared capacity. * A specific GPU architecture or interconnect. * Multi-node topology. * A particular region. * A defined start date and term. For workloads that do not require reserved hardware, see [serverless inference](/inference/quickstart). ## How requesting capacity works Share GPU type, topology, region, start date, and term. Lilac compares available capacity across its network and surfaces options based on technical and commercial fit. Lilac coordinates commercial details, access, and handoff into your environment. Provisioning is not instant or self-service. Lilac remains the point of contact during the deployment and coordinates issues and escalations. ## Pricing and availability Final pricing and availability depend on configuration, region, start date, and term. Indicative pricing on the marketing site is not a fixed quote and specific hardware is not universally available. See current indicative options on the [dedicated GPUs page](https://getlilac.com/dedicated-gpus). ## Talk to us Share the workload, model, throughput, region, and term. We'll come back with options. Or email [contact@getlilac.com](mailto:contact@getlilac.com). ## Related * [Serverless inference quickstart](/inference/quickstart) * [Inference pricing](/inference/pricing) * [Dedicated GPUs marketing page](https://getlilac.com/dedicated-gpus) # API Keys Source: https://docs.getlilac.com/inference/api-keys Create, rotate, and manage API keys that authenticate your inference requests to the Lilac API. Each key is scoped to an organization. API keys authenticate your inference requests. Each key is scoped to an organization. ## Creating an API Key Navigate to [console.getlilac.com](https://console.getlilac.com) and select your organization. Click **API Keys** in the sidebar. Click **Create API Key**, give it a name, and copy the key immediately. API keys are only shown once at creation. Store it securely — you cannot retrieve it later. ## Using Your API Key Include your API key in the `Authorization` header: ```bash theme={null} Authorization: Bearer your-lilac-api-key ``` Or pass it directly to the OpenAI SDK: ```python theme={null} from openai import OpenAI client = OpenAI( base_url="https://api.getlilac.com/v1", api_key="your-lilac-api-key", ) ``` ## Revoking a Key To revoke a key, go to **API Keys** in the dashboard and click **Delete** next to the key you want to remove. Revoked keys stop working immediately. ## Best Practices * Create separate keys for different environments (development, staging, production). * Rotate keys periodically. * Never commit keys to version control — use environment variables instead. * Revoke keys immediately if they may have been exposed. # Chat Completions Source: https://docs.getlilac.com/inference/chat-completions Use the OpenAI-compatible chat completions endpoint to generate model responses from conversation history, with streaming and tool calling. The chat completions endpoint is fully compatible with the OpenAI chat completions API. Lilac serves models via a customized fork of [vLLM](https://docs.vllm.ai/) tuned for idle-GPU scheduling and shared warm endpoints, so you get access to both standard OpenAI parameters and vLLM-specific extras. ## Endpoint ``` POST https://api.getlilac.com/v1/chat/completions ``` ## Basic Example ```python theme={null} from openai import OpenAI client = OpenAI( base_url="https://api.getlilac.com/v1", api_key="your-lilac-api-key", ) response = client.chat.completions.create( model="moonshotai/kimi-k2.6", messages=[ {"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "What is GPU inference?"}, ], ) print(response.choices[0].message.content) ``` ```javascript theme={null} import OpenAI from "openai"; const client = new OpenAI({ baseURL: "https://api.getlilac.com/v1", apiKey: "your-lilac-api-key", }); const response = await client.chat.completions.create({ model: "moonshotai/kimi-k2.6", messages: [ { role: "system", content: "You are a helpful assistant." }, { role: "user", content: "What is GPU inference?" }, ], }); console.log(response.choices[0].message.content); ``` ```bash theme={null} curl https://api.getlilac.com/v1/chat/completions \ -H "Authorization: Bearer your-lilac-api-key" \ -H "Content-Type: application/json" \ -d '{ "model": "moonshotai/kimi-k2.6", "messages": [ {"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "What is GPU inference?"} ] }' ``` ## Request Parameters ### Required | Parameter | Type | Description | | ---------- | -------- | ------------------------------------------------------------------------------------------------------ | | `model` | `string` | Model ID (e.g., `moonshotai/kimi-k2.6`). See [Models](/inference/models). | | `messages` | `array` | Conversation history. Each message has a `role` (`system`, `user`, `assistant`, `tool`) and `content`. | ### Sampling | Parameter | Type | Default | Description | | ------------- | --------- | ------- | --------------------------------------------------------------------------- | | `temperature` | `float` | `1.0` | Sampling temperature (0–2). Lower values are more deterministic. | | `top_p` | `float` | `1.0` | Nucleus sampling — considers tokens with cumulative probability >= `top_p`. | | `top_k` | `integer` | `-1` | Limits sampling to the top K tokens. `-1` disables. | | `min_p` | `float` | `0.0` | Minimum relative probability threshold for token consideration. | | `seed` | `integer` | `null` | Seed for deterministic sampling (best effort). | ### Output | Parameter | Type | Default | Description | | ----------------------- | ------------------- | --------------- | ------------------------------------------------------------------------- | | `max_tokens` | `integer` | model-dependent | Maximum tokens to generate. | | `max_completion_tokens` | `integer` | `null` | Upper bound including reasoning tokens. Preferred for reasoning models. | | `n` | `integer` | `1` | Number of completions to generate. | | `stop` | `string` or `array` | `null` | Up to 4 sequences where generation stops. | | `stream` | `boolean` | `false` | Stream partial token deltas via SSE. | | `stream_options` | `object` | `null` | Options like `{"include_usage": true}` to get token counts in the stream. | ### Penalties | Parameter | Type | Default | Description | | -------------------- | -------- | ------- | -------------------------------------------------------------- | | `frequency_penalty` | `float` | `0.0` | Penalizes tokens by frequency in output so far (-2.0 to 2.0). | | `presence_penalty` | `float` | `0.0` | Penalizes tokens that have appeared at all (-2.0 to 2.0). | | `repetition_penalty` | `float` | `1.0` | Multiplicative penalty on repeated tokens. `1.0` = no penalty. | | `logit_bias` | `object` | `null` | Map of token ID → bias value (-100 to 100). | ### Log Probabilities | Parameter | Type | Default | Description | | -------------- | --------- | ------- | ------------------------------------------------------------------------------------------ | | `logprobs` | `boolean` | `false` | Return log probabilities of output tokens. | | `top_logprobs` | `integer` | `null` | Number of most likely tokens to return at each position (0–20). Requires `logprobs: true`. | ### Tool Calling | Parameter | Type | Default | Description | | ------------- | -------------------- | -------- | ----------------------------------------------------------------------------------------- | | `tools` | `array` | `null` | List of tool definitions with `type: "function"` and a function schema. | | `tool_choice` | `string` or `object` | `"auto"` | `"none"`, `"auto"`, `"required"`, or `{"type": "function", "function": {"name": "..."}}`. | ### Structured Output | Parameter | Type | Default | Description | | ----------------- | -------- | ------- | -------------------------------------------------------------------------------------------------- | | `response_format` | `object` | `null` | `{"type": "text"}`, `{"type": "json_object"}`, or `{"type": "json_schema", "json_schema": {...}}`. | ### Reasoning | Parameter | Type | Default | Description | | ---------------------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------- | | `chat_template_kwargs` | `object` | `null` | Toggles model behavior exposed by the chat template. Used to enable or disable chain-of-thought reasoning — see below. | Some models (like Kimi K2.6 and GLM 5.2) include chain-of-thought reasoning by default. When reasoning is active, the model's chain-of-thought is returned in a separate `reasoning` field on the response message. Reasoning tokens are included in `completion_tokens` and count toward your usage — including all reasoning controls below. These are **model-specific chat-template controls**, not universal OpenAI parameters. The exact key and accepted values depend on each model's chat template. #### Per-model reasoning controls | Model | Control | Values | Default | | ---------- | ------------------------------------------------------------- | ------------------------------------- | ---------- | | Kimi K2.6 | `chat_template_kwargs.thinking` | `true` \| `false` | on | | GLM 5.2 | `reasoning_effort` or `chat_template_kwargs.reasoning_effort` | `max` \| `high` | `high` | | GLM 5.2 | `chat_template_kwargs.enable_thinking` | `true` \| `false` | on | | Gemma 4 | `chat_template_kwargs.enable_thinking` | `true` \| `false` | off | | MiniMax M3 | `chat_template_kwargs.thinking_mode` | `adaptive` \| `enabled` \| `disabled` | `adaptive` | Notes: * **GLM 5.2** supports `reasoning_effort` with two levels — `high` (default) and `max`. `max` is the opt-in highest-quality mode for long-horizon agentic and complex problem-solving tasks, at the cost of higher latency and token usage. You can send `reasoning_effort` either as a top-level field (OpenAI-style) or inside `chat_template_kwargs`. Disable thinking entirely with `chat_template_kwargs.enable_thinking: false`; when thinking is disabled, `reasoning_effort` has no effect. * **MiniMax M3** does not use a boolean toggle. It accepts `thinking_mode` with three values: `adaptive` (default — the model decides), `enabled` (always think), and `disabled` (never think). * Defaults differ per model: Kimi K2.6 and GLM 5.2 have reasoning **on** by default; Gemma 4 has reasoning **off** by default; MiniMax M3 is **adaptive** by default. See the [Models](/inference/models) page for per-model details. #### Thinking toggle keys The key that toggles reasoning is defined by each model's chat template, not by the API, so it differs per model family: | Key | Models that honor it | | ------------------------------------------------------- | ------------------------------------------------------------------------ | | `thinking` (bool) | Moonshot chat templates — e.g. Kimi K2.6 | | `enable_thinking` (bool) | Z.ai GLM / Google Gemma / SGLang-style templates — e.g. GLM 5.x, Gemma 4 | | `reasoning_effort` (`max` \| `high`) | GLM 5.2 — also accepted as a top-level field | | `thinking_mode` (`adaptive` \| `enabled` \| `disabled`) | MiniMax M3 | Unknown keys inside `chat_template_kwargs` are silently ignored by chat templates, so **the safe, forward-compatible approach is to send both keys**. This works across all current Lilac models and any future model whose template uses either convention: ```json theme={null} { "chat_template_kwargs": { "thinking": false, "enable_thinking": false } } ``` ```python theme={null} # Disable reasoning (works for both Moonshot- and GLM-style templates) response = client.chat.completions.create( model="moonshotai/kimi-k2.6", messages=[{"role": "user", "content": "What is 2+2?"}], extra_body={ "chat_template_kwargs": { "thinking": False, "enable_thinking": False, } }, ) ``` ```javascript theme={null} const response = await client.chat.completions.create({ model: "moonshotai/kimi-k2.6", messages: [ { role: "user", content: "What is 2+2?" } ], chat_template_kwargs: { thinking: false, enable_thinking: false, }, }); ``` ```bash theme={null} curl https://api.getlilac.com/v1/chat/completions \ -H "Authorization: Bearer your-lilac-api-key" \ -H "Content-Type: application/json" \ -d '{ "model": "moonshotai/kimi-k2.6", "messages": [ {"role": "user", "content": "What is 2+2?"} ], "chat_template_kwargs": { "thinking": false, "enable_thinking": false } }' ``` If you're targeting a single model on purpose (e.g. for minimal payloads) and want to use only the key its template actually honors, see the per-model notes on the [Models](/inference/models) page. **GLM 5.x chain-of-thought leakage.** Even with the correct toggle key, GLM 5.x models on the current vLLM build may still leak chain-of-thought into the `content` field, terminated by a bare `` marker — see [vllm-project/vllm#31319](https://github.com/vllm-project/vllm/issues/31319). Clients that require hard-suppressed output should post-process the response: when reasoning is disabled, discard everything in `content` up to and including the first `` marker. Disabling reasoning can significantly reduce token costs for straightforward queries where chain-of-thought isn't needed. Reasoning tokens always count toward `completion_tokens` and your billed usage. ## Streaming Enable streaming to receive tokens as they're generated: ```python theme={null} stream = client.chat.completions.create( model="moonshotai/kimi-k2.6", messages=[ {"role": "user", "content": "Write a haiku about GPUs."} ], stream=True, ) for chunk in stream: if chunk.choices[0].delta.content: print(chunk.choices[0].delta.content, end="") ``` ```javascript theme={null} const stream = await client.chat.completions.create({ model: "moonshotai/kimi-k2.6", messages: [ { role: "user", content: "Write a haiku about GPUs." } ], stream: true, }); for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta?.content || ""); } ``` ## Vision Pass images as URLs or base64 data URIs in the `content` array: ```python theme={null} response = client.chat.completions.create( model="moonshotai/kimi-k2.6", messages=[ { "role": "user", "content": [ {"type": "text", "text": "Describe this image."}, { "type": "image_url", "image_url": { "url": "https://example.com/image.jpg", "detail": "auto" } } ] } ], ) print(response.choices[0].message.content) ``` ```javascript theme={null} const response = await client.chat.completions.create({ model: "moonshotai/kimi-k2.6", messages: [ { role: "user", content: [ { type: "text", text: "Describe this image." }, { type: "image_url", image_url: { url: "https://example.com/image.jpg", detail: "auto", }, }, ], }, ], }); console.log(response.choices[0].message.content); ``` ```bash theme={null} curl https://api.getlilac.com/v1/chat/completions \ -H "Authorization: Bearer your-lilac-api-key" \ -H "Content-Type: application/json" \ -d '{ "model": "moonshotai/kimi-k2.6", "messages": [ { "role": "user", "content": [ {"type": "text", "text": "Describe this image."}, {"type": "image_url", "image_url": {"url": "https://example.com/image.jpg", "detail": "auto"}} ] } ] }' ``` ## Tool Calling ```python theme={null} response = client.chat.completions.create( model="moonshotai/kimi-k2.6", messages=[ {"role": "user", "content": "What's the weather in SF?"} ], tools=[ { "type": "function", "function": { "name": "get_weather", "description": "Get current weather for a location", "parameters": { "type": "object", "properties": { "location": {"type": "string"} }, "required": ["location"] } } } ], ) tool_call = response.choices[0].message.tool_calls[0] print(tool_call.function.name) # "get_weather" print(tool_call.function.arguments) # '{"location": "San Francisco"}' ``` ## Structured Output Force the model to return valid JSON matching a schema: ```python theme={null} response = client.chat.completions.create( model="moonshotai/kimi-k2.6", messages=[ {"role": "user", "content": "List 3 programming languages and their year of creation."} ], response_format={ "type": "json_schema", "json_schema": { "name": "languages", "schema": { "type": "object", "properties": { "languages": { "type": "array", "items": { "type": "object", "properties": { "name": {"type": "string"}, "year": {"type": "integer"} }, "required": ["name", "year"] } } }, "required": ["languages"] } } }, ) ``` ## Response Format ```json theme={null} { "id": "chatcmpl-abc123", "object": "chat.completion", "created": 1717000000, "model": "moonshotai/kimi-k2.6", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "GPU inference is the process of...", "reasoning": "The user is asking about...", "tool_calls": [] }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 25, "completion_tokens": 42, "total_tokens": 67 } } ``` The `reasoning` field is present when the model uses chain-of-thought reasoning. It is not counted separately in the response — reasoning tokens are included in `completion_tokens`. # Completions (Legacy) Source: https://docs.getlilac.com/inference/completions Use the legacy completions endpoint to generate text from a raw prompt string. For new integrations, use the chat completions endpoint instead. The legacy completions endpoint generates text from a raw prompt string. For conversational use cases, prefer [Chat Completions](/inference/chat-completions) instead. This is a legacy endpoint maintained for backward compatibility. Use `/v1/chat/completions` for new integrations. ## Endpoint ``` POST https://api.getlilac.com/v1/completions ``` ## Example ```python theme={null} from openai import OpenAI client = OpenAI( base_url="https://api.getlilac.com/v1", api_key="your-lilac-api-key", ) response = client.completions.create( model="moonshotai/kimi-k2.6", prompt="The capital of France is", max_tokens=50, ) print(response.choices[0].text) ``` ```javascript theme={null} import OpenAI from "openai"; const client = new OpenAI({ baseURL: "https://api.getlilac.com/v1", apiKey: "your-lilac-api-key", }); const response = await client.completions.create({ model: "moonshotai/kimi-k2.6", prompt: "The capital of France is", max_tokens: 50, }); console.log(response.choices[0].text); ``` ```bash theme={null} curl https://api.getlilac.com/v1/completions \ -H "Authorization: Bearer your-lilac-api-key" \ -H "Content-Type: application/json" \ -d '{ "model": "moonshotai/kimi-k2.6", "prompt": "The capital of France is", "max_tokens": 50 }' ``` ## Request Parameters ### Required | Parameter | Type | Description | | --------- | ------------------- | ---------------------------------------------------------------- | | `model` | `string` | Model ID (e.g., `moonshotai/kimi-k2.6`). | | `prompt` | `string` or `array` | The input text to complete. Can be a string or array of strings. | ### Sampling | Parameter | Type | Default | Description | | ------------- | --------- | ------- | --------------------------------------- | | `temperature` | `float` | `1.0` | Sampling temperature (0–2). | | `top_p` | `float` | `1.0` | Nucleus sampling threshold. | | `top_k` | `integer` | `-1` | Limits sampling to the top K tokens. | | `min_p` | `float` | `0.0` | Minimum relative probability threshold. | | `seed` | `integer` | `null` | Seed for deterministic sampling. | ### Output | Parameter | Type | Default | Description | | ------------ | ------------------- | ------- | --------------------------------------------------- | | `max_tokens` | `integer` | `16` | Maximum tokens to generate. | | `n` | `integer` | `1` | Number of completions per prompt. | | `stop` | `string` or `array` | `null` | Up to 4 stop sequences. | | `stream` | `boolean` | `false` | Stream partial results via SSE. | | `echo` | `boolean` | `false` | Return the prompt concatenated with the completion. | ### Penalties | Parameter | Type | Default | Description | | -------------------- | -------- | ------- | -------------------------------------------- | | `frequency_penalty` | `float` | `0.0` | Penalizes tokens by frequency (-2.0 to 2.0). | | `presence_penalty` | `float` | `0.0` | Penalizes tokens by presence (-2.0 to 2.0). | | `repetition_penalty` | `float` | `1.0` | Multiplicative penalty on repeated tokens. | | `logit_bias` | `object` | `null` | Map of token ID → bias value (-100 to 100). | ### Log Probabilities | Parameter | Type | Default | Description | | ---------- | --------- | ------- | ----------------------------------------------------- | | `logprobs` | `integer` | `null` | Return log probabilities of the top N tokens (max 5). | ## Response Format ```json theme={null} { "id": "cmpl-abc123", "object": "text_completion", "created": 1717000000, "model": "moonshotai/kimi-k2.6", "choices": [ { "index": 0, "text": " Paris, which is known for...", "finish_reason": "stop" } ], "usage": { "prompt_tokens": 7, "completion_tokens": 15, "total_tokens": 22 } } ``` # Connect to local coding tools Source: https://docs.getlilac.com/inference/local-tools Connect Lilac inference to OpenCode, Continue, Cursor, and other OpenAI-compatible AI coding assistants running in your local development environment. Lilac is available as a native provider in [OpenCode](https://opencode.ai), so OpenCode is the recommended way to use Lilac in your local coding environment. Lilac's API is also fully OpenAI-compatible, so you can use it with other tools like Continue, Cursor, or any client that supports a custom OpenAI-compatible endpoint. ## Prerequisites Before you start, make sure you have: * A Lilac account with credits loaded — [sign up here](https://console.getlilac.com) * A Lilac API key — [create one in the dashboard](https://console.getlilac.com) * [OpenCode](https://opencode.ai) or another local coding tool Don't have an API key yet? See the [API keys](/inference/api-keys) page for instructions on creating and managing keys. ## OpenCode OpenCode ships with Lilac as a built-in provider — no custom JSON config required. ```bash theme={null} opencode ``` Type `/connect`. Select **Lilac** from the provider list. Paste your Lilac API key from the [dashboard](https://console.getlilac.com). Recommended: * GLM 5.2 *(recommended for coding and agents)* * Kimi K2.6 * MiniMax M3 * Gemma 4 31B IT ### Troubleshooting OpenCode If Lilac does not show up in OpenCode, refresh the model list: ```bash theme={null} opencode models lilac --refresh ``` Then restart OpenCode and try `/connect` again. ## Other tools For tools that don't have a native Lilac integration, use Lilac's OpenAI-compatible endpoint with a custom API configuration. ### What you need to configure Every tool that supports a custom API will ask you for three things. Here are the exact values to use: | Setting | Value | | --------------------------- | ----------------------------------------------------------------------- | | **API endpoint / Base URL** | `https://api.getlilac.com/v1` | | **API key** | Your Lilac API key (from the [dashboard](https://console.getlilac.com)) | | **Model name** | `moonshotai/kimi-k2.6` *(example — swap for the model you want to use)* | Model name examples: * `zai-org/glm-5.2` *(recommended for coding and agents)* * `moonshotai/kimi-k2.6` * `minimaxai/minimax-m3` * `google/gemma-4-31b-it` `moonshotai/kimi-k2.6` is used as an example throughout this section. Replace it with the full model ID of whichever model you want to use — see [Supported Models](/inference/models) for the complete list. You must use the **exact** model ID, including any vendor prefix (e.g. `moonshotai/`, `zai-org/`, `google/`, `minimaxai/`). Shorthand names like `glm` or `k2.6` will not work. ### Step-by-step setup Open your coding tool and look for settings related to **AI provider**, **API configuration**, **custom model**, or **OpenAI-compatible endpoint**. This is usually in the tool's settings or preferences menu. Enter the following as the base URL or API endpoint: ```text theme={null} https://api.getlilac.com/v1 ``` Make sure you include `/v1` at the end. Omitting it will cause requests to fail. Paste your Lilac API key into the API key field. This is the key you copied when you created it in the [dashboard](https://console.getlilac.com). Store your API key as an environment variable (e.g., `LILAC_API_KEY`) rather than pasting it directly into config files that might get committed to version control. Enter the full model ID for the model you want to use. For example: ```text theme={null} moonshotai/kimi-k2.6 ``` `moonshotai/kimi-k2.6` is just an example — replace it with the ID of whichever model you want to use (e.g. `zai-org/glm-5.2`, `minimaxai/minimax-m3`, `google/gemma-4-31b-it`). See [Supported Models](/inference/models) for the full list. Do not omit or change any part of the identifier, including the vendor prefix. Send a test message to confirm everything is working. If you get a response, you're all set. If you get an error, double-check: 1. The base URL is exactly `https://api.getlilac.com/v1` (with `/v1`) 2. Your API key is correct and hasn't been revoked 3. The model name is the exact full identifier of a [supported model](/inference/models) (e.g. `moonshotai/kimi-k2.6`) 4. Your account has a positive credit balance ### Quick reference If your tool uses a config file or environment variables, here's what to set: ```bash theme={null} # Environment variables export OPENAI_API_BASE=https://api.getlilac.com/v1 export OPENAI_API_KEY=your-lilac-api-key ``` ```json theme={null} { "apiBase": "https://api.getlilac.com/v1", "apiKey": "your-lilac-api-key", "model": "moonshotai/kimi-k2.6" } ``` `moonshotai/kimi-k2.6` is shown here as an example. Substitute the full ID of the model you want to use — see [Supported Models](/inference/models). Variable names differ by tool. The examples above use common conventions — check your tool's documentation for the exact names. ## Common issues Run `opencode models lilac --refresh`, then restart OpenCode and try `/connect` again. Your API key is missing, incorrect, or has been revoked. Generate a new key from the [dashboard](https://console.getlilac.com) and try again. The base URL is likely wrong. Make sure it is `https://api.getlilac.com/v1` — including the `/v1` path. The model name must be the full identifier of a [supported model](/inference/models) — for example `moonshotai/kimi-k2.6`. Check for typos, extra spaces, or a missing vendor prefix. Confirm your machine has internet access and that no firewall or proxy is blocking requests to `api.getlilac.com`. Your account balance is zero. Add credits in the [dashboard billing page](https://console.getlilac.com) before making requests. # Supported Models Source: https://docs.getlilac.com/inference/models Browse all models available on Lilac including Kimi K2.6, GLM 5.2, Gemma 4, and MiniMax M3 with context lengths, capabilities, and per-token pricing. ## Available Models Lilac currently supports the following models. We're actively adding more — [reach out](mailto:contact@getlilac.com) if there's a model you'd like to see. | Model | Model ID | Context Length | Quantization | Input Price | Cache Read Price | Output Price | | ---------- | ----------------------- | ---------------- | ------------ | ----------------- | ----------------- | ----------------- | | Kimi K2.6 | `moonshotai/kimi-k2.6` | 262,144 tokens | INT4 | \$0.70 / M tokens | \$0.16 / M tokens | \$3.50 / M tokens | | GLM 5.2 | `zai-org/glm-5.2` | 524,288 tokens | FP8/NVFP4 | \$0.90 / M tokens | \$0.17 / M tokens | \$3.00 / M tokens | | Gemma 4 | `google/gemma-4-31b-it` | 262,100 tokens | FP8 | \$0.11 / M tokens | — | \$0.35 / M tokens | | MiniMax M3 | `minimaxai/minimax-m3` | 1,048,576 tokens | FP8 | \$0.28 / M tokens | \$0.05 / M tokens | \$1.10 / M tokens | **Cache read** is the rate for repeated input tokens served from cache. It's billed at a lower rate than standard input tokens on supported models. Models that don't support cached input tokens are marked with `—`. More models are coming soon. Request a model by emailing [contact@getlilac.com](mailto:contact@getlilac.com). *** ## Kimi K2.6 Moonshot AI's flagship multimodal reasoning model. 1T total parameters (32B activated) with a Mixture-of-Experts architecture. Model card, benchmarks, and deployment guides. ### Capabilities | Capability | Status | Details | | ------------------------ | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Text input** | Supported | Chat, instructions, system prompts | | **Image input** | Supported | Native multimodal — pass images via `image_url` in messages | | **Text output** | Supported | Completions, structured JSON, tool calls | | **Reasoning (thinking)** | On by default | Chain-of-thought returned in `reasoning` field. Kimi K2.6's Moonshot chat template honors `chat_template_kwargs: {"thinking": false}` (the `enable_thinking` key is ignored here). For forward compatibility across models, see the [Reasoning section](/inference/chat-completions#reasoning). | | **Tool calling** | Supported | Function definitions with automatic argument extraction | | **Structured output** | Supported | `response_format` with `json_object` or `json_schema` | ### Recommended Parameters From the [Kimi K2.6 model card](https://huggingface.co/moonshotai/Kimi-K2.6): | Mode | Temperature | Top P | | ---------------------- | ----------- | ------ | | Thinking (default) | `1.0` | `0.95` | | Instant (thinking off) | `0.6` | `0.95` | ### Vision Kimi K2.6 natively supports image inputs. Pass images as base64 data URIs or URLs in the `content` array: ```python theme={null} response = client.chat.completions.create( model="moonshotai/kimi-k2.6", messages=[ { "role": "user", "content": [ {"type": "text", "text": "Describe this image."}, { "type": "image_url", "image_url": { "url": "https://example.com/image.jpg", "detail": "auto" } } ] } ], ) ``` ```bash theme={null} curl https://api.getlilac.com/v1/chat/completions \ -H "Authorization: Bearer your-lilac-api-key" \ -H "Content-Type: application/json" \ -d '{ "model": "moonshotai/kimi-k2.6", "messages": [ { "role": "user", "content": [ {"type": "text", "text": "Describe this image."}, {"type": "image_url", "image_url": {"url": "https://example.com/image.jpg", "detail": "auto"}} ] } ] }' ``` You can also pass base64-encoded images: ```python theme={null} import base64 with open("image.png", "rb") as f: image_b64 = base64.b64encode(f.read()).decode() response = client.chat.completions.create( model="moonshotai/kimi-k2.6", messages=[ { "role": "user", "content": [ {"type": "text", "text": "What's in this image?"}, { "type": "image_url", "image_url": {"url": f"data:image/png;base64,{image_b64}"} } ] } ], ) ``` *** ## GLM 5.2 Z.ai's GLM 5.2 is a frontier-scale MoE reasoning and coding model for long-horizon agentic work. Lilac serves GLM 5.2 with a 524k-token context window, tool calling, structured output, and configurable reasoning effort. Model card, benchmarks, and deployment guides. ### Capabilities | Capability | Status | Details | | ------------------------ | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Text input** | Supported | Chat, instructions, system prompts | | **Text output** | Supported | Completions, structured JSON, tool calls | | **Image input** | Not supported | GLM 5.2 is text-only | | **Reasoning (thinking)** | On by default | Chain-of-thought returned in `reasoning` field. GLM 5.2 honors `chat_template_kwargs: {"enable_thinking": false}` to disable thinking, and supports a `reasoning_effort` control with two levels — `max` and `high`. See the [Reasoning section](/inference/chat-completions#reasoning) for forward-compatible toggles. | | **Tool calling** | Supported | Function definitions with automatic argument extraction — strong performance on agentic tasks | | **Structured output** | Supported | `response_format` with `json_object` or `json_schema` | ### Reasoning effort GLM 5.2 exposes two reasoning effort levels: * `high` — the default when reasoning is enabled. Good balance of quality, latency, and token usage for most coding and reasoning tasks. * `max` — highest-quality reasoning for long-horizon agentic and complex problem-solving tasks. Higher latency and token usage than `high`. Notes: * Disable thinking entirely with `chat_template_kwargs.enable_thinking: false`. When thinking is disabled, `reasoning_effort` has no effect. * `reasoning_effort` can be sent either as a top-level field (OpenAI-style) or inside `chat_template_kwargs` (vLLM extra-body form). Both are accepted. ### Example requests ```bash theme={null} curl https://api.getlilac.com/v1/chat/completions \ -H "Authorization: Bearer your-lilac-api-key" \ -H "Content-Type: application/json" \ -d '{ "model": "zai-org/glm-5.2", "messages": [ {"role": "user", "content": "Plan a migration for this service."} ], "reasoning_effort": "high" }' ``` ```bash theme={null} curl https://api.getlilac.com/v1/chat/completions \ -H "Authorization: Bearer your-lilac-api-key" \ -H "Content-Type: application/json" \ -d '{ "model": "zai-org/glm-5.2", "messages": [ {"role": "user", "content": "Plan a migration for this service."} ], "chat_template_kwargs": { "reasoning_effort": "high" } }' ``` ```bash theme={null} curl https://api.getlilac.com/v1/chat/completions \ -H "Authorization: Bearer your-lilac-api-key" \ -H "Content-Type: application/json" \ -d '{ "model": "zai-org/glm-5.2", "messages": [ {"role": "user", "content": "Answer directly: what is 2+2?"} ], "chat_template_kwargs": { "enable_thinking": false } }' ``` ```python theme={null} response = client.chat.completions.create( model="zai-org/glm-5.2", messages=[ {"role": "user", "content": "Plan a migration for this service."} ], extra_body={ "chat_template_kwargs": { "reasoning_effort": "high" } }, ) ``` ### Thinking controls **Preserved thinking is off by default.** GLM 5.2's effective default on Lilac is to clear previous assistant thinking blocks between turns. To preserve thinking across turns, use `chat_template_kwargs.clear_thinking: false` on Lilac. This is equivalent to vLLM-native chat-template control. Lilac does not currently consume Z.ai's top-level `thinking` object — in particular, top-level `thinking.clear_thinking` is ignored. For conceptual background, see [Z.ai's preserved thinking docs](https://docs.z.ai/guides/capabilities/thinking-mode#preserved-thinking). ```json theme={null} { "model": "zai-org/glm-5.2", "messages": [...], "chat_template_kwargs": { "clear_thinking": false } } ``` ```json theme={null} { "model": "zai-org/glm-5.2", "messages": [...], "chat_template_kwargs": { "enable_thinking": true, "reasoning_effort": "max", "clear_thinking": false } } ``` ```json theme={null} { "model": "zai-org/glm-5.2", "messages": [...], "reasoning_effort": "none" } ``` *** ## Gemma 4 Google's open-weight multimodal model. 31B parameters with native support for text, image, and video inputs. 262K context window with FP8 precision. Released under the Gemma license. Model card, benchmarks, and deployment guides. ### Capabilities | Capability | Status | Details | | ------------------------ | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Text input** | Supported | Chat, instructions, system prompts | | **Image input** | Supported | Native multimodal — pass images via `image_url` in messages | | **Video input** | Supported | Pass video frames as a sequence of images | | **Text output** | Supported | Completions, structured JSON | | **Reasoning (thinking)** | Off by default | Chain-of-thought returned in `reasoning` field when enabled. Gemma 4's chat template honors `chat_template_kwargs: {"enable_thinking": true}` (the `thinking` key is ignored here). Unlike Kimi K2.6 and GLM 5.2, thinking is **off by default** — you must opt in. See the [Reasoning section](/inference/chat-completions#reasoning) for the forward-compatible form. | | **Tool calling** | Supported | Function definitions with automatic argument extraction | | **Structured output** | Supported | `response_format` with `json_object` or `json_schema` | **Gemma 4 chain-of-thought may leak into `content`.** vLLM's Gemma 4 reasoning parser can fail to populate the `reasoning` field when special tokens are stripped before the parser runs — see [vllm-project/vllm#38855](https://github.com/vllm-project/vllm/issues/38855). When reasoning is enabled, clients that require a clean split should post-process by treating text inside `<|channel|>thought ... <|channel|>` markers as reasoning. **Structured output caveat.** On current vLLM builds, combining `--reasoning-parser gemma4` with `enable_thinking: false` can silently disable xgrammar-backed structured output — see [vllm-project/vllm#39130](https://github.com/vllm-project/vllm/issues/39130). If you rely on `response_format: json_schema` with Gemma 4, leave thinking enabled or validate output client-side. ### Enabling reasoning Gemma 4 is the only model in the catalog where reasoning is off by default. To turn it on, use the forward-compatible form recommended in the [Reasoning section](/inference/chat-completions#reasoning): ```python theme={null} response = client.chat.completions.create( model="google/gemma-4-31b-it", messages=[{"role": "user", "content": "Prove there are infinitely many primes."}], extra_body={ "chat_template_kwargs": { "thinking": True, "enable_thinking": True, } }, ) ``` ```bash theme={null} curl https://api.getlilac.com/v1/chat/completions \ -H "Authorization: Bearer your-lilac-api-key" \ -H "Content-Type: application/json" \ -d '{ "model": "google/gemma-4-31b-it", "messages": [ {"role": "user", "content": "Prove there are infinitely many primes."} ], "chat_template_kwargs": { "thinking": true, "enable_thinking": true } }' ``` ### Vision Gemma 4 natively supports image inputs. Pass images as base64 data URIs or URLs in the `content` array: ```python theme={null} response = client.chat.completions.create( model="google/gemma-4-31b-it", messages=[ { "role": "user", "content": [ {"type": "text", "text": "Describe this image."}, { "type": "image_url", "image_url": { "url": "https://example.com/image.jpg", "detail": "auto" } } ] } ], ) ``` ```bash theme={null} curl https://api.getlilac.com/v1/chat/completions \ -H "Authorization: Bearer your-lilac-api-key" \ -H "Content-Type: application/json" \ -d '{ "model": "google/gemma-4-31b-it", "messages": [ { "role": "user", "content": [ {"type": "text", "text": "Describe this image."}, {"type": "image_url", "image_url": {"url": "https://example.com/image.jpg", "detail": "auto"}} ] } ] }' ``` ### Video Gemma 4 can process video by accepting a sequence of frames as images. Extract frames from your video and pass them as multiple `image_url` entries: ```python theme={null} import base64 import cv2 # Extract frames from video video = cv2.VideoCapture("video.mp4") frames = [] while video.isOpened(): ret, frame = video.read() if not ret: break _, buffer = cv2.imencode(".jpg", frame) frames.append(base64.b64encode(buffer).decode()) video.release() # Sample frames to fit context window sampled = frames[::len(frames) // 8][:8] response = client.chat.completions.create( model="google/gemma-4-31b-it", messages=[ { "role": "user", "content": [ {"type": "text", "text": "Describe what happens in this video."}, *[ { "type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{frame}"} } for frame in sampled ] ] } ], ) ``` ```bash theme={null} curl https://api.getlilac.com/v1/chat/completions \ -H "Authorization: Bearer your-lilac-api-key" \ -H "Content-Type: application/json" \ -d '{ "model": "google/gemma-4-31b-it", "messages": [ { "role": "user", "content": [ {"type": "text", "text": "Describe what happens in this video."}, {"type": "image_url", "image_url": {"url": "data:image/jpeg;base64,FRAME_1_BASE64"}}, {"type": "image_url", "image_url": {"url": "data:image/jpeg;base64,FRAME_2_BASE64"}} ] } ] }' ``` *** ## MiniMax M3 MiniMax M3 is a frontier MoE model for coding, agents, and long-context reasoning. Lilac serves MiniMax M3 with a 1M-token context window, tool calling, structured output, and per-request thinking modes. Model card, benchmarks, and deployment guides. ### Capabilities | Capability | Status | Details | | ------------------------ | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | **Text input** | Supported | Chat, instructions, system prompts | | **Text output** | Supported | Completions, structured JSON, tool calls | | **Image input** | Supported | Native multimodal — pass images via `image_url` in messages | | **Video input** | Supported | Pass video frames as a sequence of images | | **Reasoning (thinking)** | Supported | Per-request thinking modes via `chat_template_kwargs.thinking_mode`. See the [Reasoning section](/inference/chat-completions#reasoning) for details. | | **Tool calling** | Supported | Function definitions with automatic argument extraction | | **Structured output** | Supported | `response_format` with `json_object` or `json_schema` | ### Limits | Limit | Value | | -------------- | ---------------- | | Context length | 1,048,576 tokens | ### Thinking modes MiniMax M3 uses a single `thinking_mode` control instead of a boolean toggle: | Mode | Behavior | | ---------- | ---------------------------------------------------------------------------- | | `adaptive` | Default when unset. The model decides whether to think based on the request. | | `enabled` | Always think. Best for complex reasoning and multi-step agents. | | `disabled` | No thinking. Best for latency-sensitive requests. | `thinking_mode` is passed inside `chat_template_kwargs`: ```json theme={null} { "chat_template_kwargs": { "thinking_mode": "adaptive" } } ``` ### Example requests ```bash theme={null} curl https://api.getlilac.com/v1/chat/completions \ -H "Authorization: Bearer your-lilac-api-key" \ -H "Content-Type: application/json" \ -d '{ "model": "minimaxai/minimax-m3", "messages": [ {"role": "user", "content": "Analyze this large codebase summary."} ], "chat_template_kwargs": { "thinking_mode": "adaptive" } }' ``` ```bash theme={null} curl https://api.getlilac.com/v1/chat/completions \ -H "Authorization: Bearer your-lilac-api-key" \ -H "Content-Type: application/json" \ -d '{ "model": "minimaxai/minimax-m3", "messages": [ {"role": "user", "content": "Solve this multi-step planning problem."} ], "chat_template_kwargs": { "thinking_mode": "enabled" } }' ``` ```bash theme={null} curl https://api.getlilac.com/v1/chat/completions \ -H "Authorization: Bearer your-lilac-api-key" \ -H "Content-Type: application/json" \ -d '{ "model": "minimaxai/minimax-m3", "messages": [ {"role": "user", "content": "Give me a concise answer."} ], "chat_template_kwargs": { "thinking_mode": "disabled" } }' ``` ```python theme={null} response = client.chat.completions.create( model="minimaxai/minimax-m3", messages=[ {"role": "user", "content": "Solve this multi-step planning problem."} ], extra_body={ "chat_template_kwargs": { "thinking_mode": "enabled" } }, ) ``` ### Vision MiniMax M3 natively supports image inputs. Pass images as base64 data URIs or URLs in the `content` array: ```python theme={null} response = client.chat.completions.create( model="minimaxai/minimax-m3", messages=[ { "role": "user", "content": [ {"type": "text", "text": "Describe this image."}, { "type": "image_url", "image_url": { "url": "https://example.com/image.jpg", "detail": "auto" } } ] } ], ) ``` ```bash theme={null} curl https://api.getlilac.com/v1/chat/completions \ -H "Authorization: Bearer your-lilac-api-key" \ -H "Content-Type: application/json" \ -d '{ "model": "minimaxai/minimax-m3", "messages": [ { "role": "user", "content": [ {"type": "text", "text": "Describe this image."}, {"type": "image_url", "image_url": {"url": "https://example.com/image.jpg", "detail": "auto"}} ] } ] }' ``` ### Video MiniMax M3 can process video by accepting a sequence of frames as images. Extract frames from your video and pass them as multiple `image_url` entries: ```python theme={null} import base64 import cv2 # Extract frames from video video = cv2.VideoCapture("video.mp4") frames = [] while video.isOpened(): ret, frame = video.read() if not ret: break _, buffer = cv2.imencode(".jpg", frame) frames.append(base64.b64encode(buffer).decode()) video.release() # Sample frames to fit context window sampled = frames[::len(frames) // 8][:8] response = client.chat.completions.create( model="minimaxai/minimax-m3", messages=[ { "role": "user", "content": [ {"type": "text", "text": "Describe what happens in this video."}, *[ { "type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{frame}"} } for frame in sampled ] ] } ], ) ``` ```bash theme={null} curl https://api.getlilac.com/v1/chat/completions \ -H "Authorization: Bearer your-lilac-api-key" \ -H "Content-Type: application/json" \ -d '{ "model": "minimaxai/minimax-m3", "messages": [ { "role": "user", "content": [ {"type": "text", "text": "Describe what happens in this video."}, {"type": "image_url", "image_url": {"url": "data:image/jpeg;base64,FRAME_1_BASE64"}}, {"type": "image_url", "image_url": {"url": "data:image/jpeg;base64,FRAME_2_BASE64"}} ] } ] }' ``` *** ## Listing Models via API ```python theme={null} from openai import OpenAI client = OpenAI( base_url="https://api.getlilac.com/v1", api_key="your-lilac-api-key", ) models = client.models.list() for model in models: print(model.id) ``` ```javascript theme={null} import OpenAI from "openai"; const client = new OpenAI({ baseURL: "https://api.getlilac.com/v1", apiKey: "your-lilac-api-key", }); const models = await client.models.list(); for await (const model of models) { console.log(model.id); } ``` ```bash theme={null} curl https://api.getlilac.com/v1/models \ -H "Authorization: Bearer your-lilac-api-key" ``` # OpenAI Compatibility Source: https://docs.getlilac.com/inference/openai-compatibility Learn which OpenAI API features Lilac supports and how to migrate from OpenAI by changing just the base URL and API key in your existing code. Lilac provides an OpenAI-compatible API. If you're already using the OpenAI SDK, you only need to change the base URL and API key. ## Migrating from OpenAI ```python theme={null} from openai import OpenAI # Before (OpenAI) client = OpenAI(api_key="sk-...") # After (Lilac) — just change base_url and api_key client = OpenAI( base_url="https://api.getlilac.com/v1", api_key="your-lilac-api-key", ) # Everything else stays the same response = client.chat.completions.create( model="moonshotai/kimi-k2.6", messages=[{"role": "user", "content": "Hello!"}], ) ``` ```javascript theme={null} import OpenAI from "openai"; // Before (OpenAI) const client = new OpenAI({ apiKey: "sk-..." }); // After (Lilac) — just change baseURL and apiKey const client = new OpenAI({ baseURL: "https://api.getlilac.com/v1", apiKey: "your-lilac-api-key", }); ``` ## Supported Endpoints | Endpoint | Status | | --------------------------- | ------------------ | | `POST /v1/chat/completions` | Supported | | `POST /v1/completions` | Supported (legacy) | | `POST /v1/responses` | Supported | | `GET /v1/models` | Supported | ## Supported Features | Feature | Status | | ----------------------------------- | --------- | | Chat completions | Supported | | Streaming | Supported | | System messages | Supported | | Vision (image inputs) | Supported | | Tool / function calling | Supported | | Structured output (JSON mode) | Supported | | Reasoning (thinking on/off) | Supported | | Temperature, top\_p, top\_k, min\_p | Supported | | Frequency & presence penalties | Supported | | Log probabilities | Supported | | Seed (deterministic sampling) | Supported | | Stop sequences | Supported | | Multiple choices (n) | Supported | ## Not Yet Supported The following OpenAI features are not currently available: * Embeddings * Audio * Fine-tuning * Assistants API * Batch API * File uploads We're actively expanding API coverage. [Let us know](mailto:contact@getlilac.com) which features matter most to you. # Organizations & Invites Source: https://docs.getlilac.com/inference/organizations Manage your Lilac organization, invite team members by email, assign owner or member roles, and control API key and billing access. Organizations are the top-level grouping in Lilac. Every API key, billing account, and usage metric belongs to an organization. This page covers how to invite teammates and manage membership. ## Inviting Members Organization owners can invite anyone by email address. The invitee receives an email with a link to join your organization. Navigate to [console.getlilac.com](https://console.getlilac.com), click your **profile** in the bottom-left corner, then select **Organization Settings**. Click the **Members** tab. You'll see a list of current members and their roles. Click **Invite member**. Enter the person's email address and choose a role: | Role | Capabilities | | ---------- | ------------------------------------------------------------------------------------------------------------ | | **Owner** | Full access: invite/remove members, manage billing, create and revoke API keys, update organization settings | | **Member** | Use existing API keys, view usage and billing, cannot invite members or manage organization settings | Click **Send invite**. The invitee will receive an email with a unique invite link. ## Accepting an Invite When someone invites you to an organization, you'll receive an email with a link like: ``` https://console.getlilac.com/accept-invite?invite_code=abc123 ``` ### If you already have a Lilac account Click the link, sign in, and the invite is applied automatically. You'll be redirected to the dashboard under the new organization. ### If you don't have a Lilac account yet Click the link and choose **Sign up** to create an account. The invite code is carried through the signup flow — once your account is created, you'll be added to the organization automatically. You can also sign in with an existing account and accept the invite from there. ### From the dashboard If you're already signed in and have a pending invite, you'll see it in one of two places: * **User Settings → Invitations** — view, accept, or reject invites sent to your email * **After sign-in** — if you have no organization yet, pending invites appear on the organization selection screen ## Managing Pending Invites Organization owners can view and revoke pending invites: 1. Click your **profile** in the bottom-left corner, then select **Organization Settings → Members** 2. You'll see a list of outstanding invites with the email, role, and expiration 3. Click **Revoke** to cancel an invite before it's accepted Invites expire after a set period. If an invite expires, the person will need to be re-invited. ## Removing Members Organization owners can remove members from **Organization Settings → Members** (click your **profile** in the bottom-left corner, then select Organization Settings): 1. Find the member in the list 2. Click **Remove** 3. The member loses access immediately — their API keys are revoked and they can no longer view the organization's resources Removed members can be re-invited later if needed. ## Switching Organizations If you belong to multiple organizations, use the organization switcher in the top-left corner of the dashboard to toggle between them. Each organization has its own API keys, billing, and usage data. ## Next Steps Create and manage API keys for your organization. Understand per-token pricing and manage your credits. Monitor token usage across your organization. # Inference Pricing Source: https://docs.getlilac.com/inference/pricing Lilac offers pay-per-token inference pricing with no minimums or contracts. See per-model rates for input and output tokens powered by idle GPUs. Lilac uses simple per-token pricing. You pay only for what you use — no contracts, no minimums, no reserved capacity fees. ## How It Works Lilac routes your inference requests to idle enterprise GPUs. Because these GPUs are already powered on and paid for by their owners, we can offer inference at significantly lower prices than dedicated cloud providers. ## Current Pricing | Model | Input | Cache Read | Output | | ---------- | ----------------- | ----------------- | ----------------- | | Kimi K2.6 | \$0.70 / M tokens | \$0.16 / M tokens | \$3.50 / M tokens | | GLM 5.2 | \$0.90 / M tokens | \$0.17 / M tokens | \$3.00 / M tokens | | Gemma 4 | \$0.11 / M tokens | — | \$0.35 / M tokens | | MiniMax M3 | \$0.28 / M tokens | \$0.05 / M tokens | \$1.10 / M tokens | Pricing is per million tokens. A typical chat message is 50–200 tokens. ### Cache read pricing When repeated input tokens (such as system prompts or shared context) are served from cache, they're billed at the **cache read** rate instead of the standard input rate. Cache read pricing only applies to models that support cached input tokens — models without cache support are marked with `—` and bill all input tokens at the standard input rate. ## What's Included * No cold start fees * No request fees * No minimum spend * No contract or commitment * Streaming at no extra cost ## Adding Credits Lilac uses a credit-based billing system. Add credits through the **Billing** section of your dashboard. You can also configure auto top-up to automatically add credits when your balance drops below a threshold. Open [console.getlilac.com](https://console.getlilac.com) and navigate to **Billing** in the sidebar. Click **Add Credits** and complete the Stripe checkout to load your account. Toggle **Auto Top-Up** to automatically refill credits when your balance runs low. ## Enterprise billing If you're an enterprise customer and prefer monthly invoicing over prepaid credits, reach out to us at [contact@getlilac.com](mailto:contact@getlilac.com) to set up a monthly billing arrangement. # Inference Quickstart Source: https://docs.getlilac.com/inference/quickstart Get started with the Lilac inference API in under five minutes. Create an account, add credits, generate an API key, and send your first request. Get up and running with Lilac's inference API in four steps. Sign up at [console.getlilac.com](https://console.getlilac.com) with your email or Google account. Create an organization to manage your team's API keys and billing. Lilac uses prepaid credits. Navigate to **Billing** in the dashboard, click **Add Credits**, and complete the Stripe checkout to load your account. You need a positive credit balance before you can make API requests. You can add as little as \$5.00. See [Pricing](/inference/pricing) for per-token rates. Go to **API Keys** in the dashboard and create a new key. Copy it — you won't be able to see it again. Keep your API key secret. Do not commit it to version control or share it publicly. Point any OpenAI-compatible SDK at `api.getlilac.com` and use your Lilac API key: ```python theme={null} from openai import OpenAI client = OpenAI( base_url="https://api.getlilac.com/v1", api_key="your-lilac-api-key", ) response = client.chat.completions.create( model="moonshotai/kimi-k2.6", messages=[ {"role": "user", "content": "Hello!"} ], ) print(response.choices[0].message.content) ``` ```javascript theme={null} import OpenAI from "openai"; const client = new OpenAI({ baseURL: "https://api.getlilac.com/v1", apiKey: "your-lilac-api-key", }); const response = await client.chat.completions.create({ model: "moonshotai/kimi-k2.6", messages: [ { role: "user", content: "Hello!" } ], }); console.log(response.choices[0].message.content); ``` ```bash theme={null} curl https://api.getlilac.com/v1/chat/completions \ -H "Authorization: Bearer your-lilac-api-key" \ -H "Content-Type: application/json" \ -d '{ "model": "moonshotai/kimi-k2.6", "messages": [ {"role": "user", "content": "Hello!"} ] }' ``` That's it. Your requests are now routing to idle enterprise GPUs at a fraction of the cost of dedicated providers. ## Next steps See available models and their pricing. Understand per-token pricing and manage your credits. Learn what's supported from the OpenAI API spec. # API Rate Limits and 429 Handling Source: https://docs.getlilac.com/inference/rate-limits Default per-organization rate limits for the Lilac inference API, how 429 Too Many Requests responses work, and recommended retry and backoff behavior. The Lilac API applies a default rate limit per organization to keep shared inference capacity fair across customers. ## Default Limit * **200 requests per minute per organization.** This limit applies to all Lilac API requests, including inference calls (chat completions, completions, and responses). ## 429 Too Many Requests Requests above the limit may receive an HTTP `429 Too Many Requests` response. When this happens: * Back off and retry later. * If a `Retry-After` header or `retry_after` field is present, respect it. * Use exponential backoff for automated clients. ### Example ```bash theme={null} curl -i https://api.getlilac.com/v1/chat/completions \ -H "Authorization: Bearer your-lilac-api-key" \ -H "Content-Type: application/json" \ -d '{ "model": "moonshotai/kimi-k2.6", "messages": [{"role": "user", "content": "hi"}] }' # HTTP/1.1 429 Too Many Requests # Retry-After: 12 ``` When using the OpenAI SDK, `429` responses are surfaced as `RateLimitError` (Python) / `RateLimitError` (JS). The SDK will retry transient errors with exponential backoff by default — keep that behavior or implement your own. ## Higher Limits Need more than 200 requests per minute? Contact [Lilac support](mailto:contact@getlilac.com) or [book a call with the founders](https://calendly.com/d/ctxy-jd8-585/lilac-support) to discuss higher limits. # Responses API Source: https://docs.getlilac.com/inference/responses Use the responses endpoint, OpenAI's newer API format, to generate structured output and call tools with built-in support for JSON schemas. The responses endpoint is OpenAI's newer API format with built-in support for structured output and tool calling. ## Endpoint ``` POST https://api.getlilac.com/v1/responses ``` ## Example ```python theme={null} from openai import OpenAI client = OpenAI( base_url="https://api.getlilac.com/v1", api_key="your-lilac-api-key", ) response = client.responses.create( model="moonshotai/kimi-k2.6", input="Explain GPU inference in two sentences.", ) print(response.output_text) ``` ```javascript theme={null} import OpenAI from "openai"; const client = new OpenAI({ baseURL: "https://api.getlilac.com/v1", apiKey: "your-lilac-api-key", }); const response = await client.responses.create({ model: "moonshotai/kimi-k2.6", input: "Explain GPU inference in two sentences.", }); console.log(response.output_text); ``` ```bash theme={null} curl https://api.getlilac.com/v1/responses \ -H "Authorization: Bearer your-lilac-api-key" \ -H "Content-Type: application/json" \ -d '{ "model": "moonshotai/kimi-k2.6", "input": "Explain GPU inference in two sentences." }' ``` ## Request Parameters ### Required | Parameter | Type | Description | | --------- | ------------------- | -------------------------------------------------------------------------------- | | `model` | `string` | Model ID (e.g., `moonshotai/kimi-k2.6`). | | `input` | `string` or `array` | User prompt as a string, or conversation history as an array of message objects. | ### Sampling | Parameter | Type | Default | Description | | ------------------- | --------- | ------- | -------------------------------------------------------- | | `instructions` | `string` | `null` | System-level instructions for the model. | | `temperature` | `float` | `1.0` | Sampling temperature (0–2). | | `top_p` | `float` | `1.0` | Nucleus sampling threshold. | | `max_output_tokens` | `integer` | `null` | Maximum tokens to generate (including reasoning tokens). | | `stream` | `boolean` | `false` | Stream the response via SSE. | ### Structured Output | Parameter | Type | Default | Description | | --------- | -------- | ------- | ------------------------------------------------------------- | | `text` | `object` | `null` | Structured output format with JSON Schema. See example below. | ### Tools The responses endpoint uses a **flat tool format** — `name`, `description`, and `parameters` are top-level fields, not nested under `function`. | Parameter | Type | Default | Description | | --------- | ------- | ------- | -------------------------------------------- | | `tools` | `array` | `null` | List of tool definitions (see format below). | The tool format differs from `/v1/chat/completions`. See the [tool calling example](#tool-calling) below for the correct format. ### Reasoning Models with reasoning (like Kimi K2.6 and GLM 5.2) include chain-of-thought by default. The response includes a `reasoning` output item containing the model's thinking. Reasoning tokens count toward your usage. Disabling reasoning is not currently supported on the `/v1/responses` endpoint. To control reasoning, use [Chat Completions](/inference/chat-completions) with `chat_template_kwargs: {"thinking": false}` instead. ## Structured Output Force the model to return JSON matching a schema: ```python theme={null} response = client.responses.create( model="moonshotai/kimi-k2.6", input="Give me a color with its name and hex code.", text={ "format": { "type": "json_schema", "name": "color", "schema": { "type": "object", "properties": { "name": {"type": "string"}, "hex": {"type": "string"} }, "required": ["name", "hex"] } } }, ) print(response.output_text) # {"name": "Teal", "hex": "#008080"} ``` ```javascript theme={null} const response = await client.responses.create({ model: "moonshotai/kimi-k2.6", input: "Give me a color with its name and hex code.", text: { format: { type: "json_schema", name: "color", schema: { type: "object", properties: { name: { type: "string" }, hex: { type: "string" }, }, required: ["name", "hex"], }, }, }, }); console.log(response.output_text); ``` ```bash theme={null} curl https://api.getlilac.com/v1/responses \ -H "Authorization: Bearer your-lilac-api-key" \ -H "Content-Type: application/json" \ -d '{ "model": "moonshotai/kimi-k2.6", "input": "Give me a color with its name and hex code.", "text": { "format": { "type": "json_schema", "name": "color", "schema": { "type": "object", "properties": { "name": {"type": "string"}, "hex": {"type": "string"} }, "required": ["name", "hex"] } } } }' ``` ## Tool Calling The responses endpoint uses a flat tool format where `name`, `description`, and `parameters` are at the top level: ```python theme={null} response = client.responses.create( model="moonshotai/kimi-k2.6", input="What's the weather in NYC?", tools=[ { "type": "function", "name": "get_weather", "description": "Get current weather for a location", "parameters": { "type": "object", "properties": { "location": {"type": "string"} }, "required": ["location"] } } ], ) for item in response.output: if item.type == "function_call": print(f"{item.name}({item.arguments})") # get_weather({"location": "NYC"}) ``` ```javascript theme={null} const response = await client.responses.create({ model: "moonshotai/kimi-k2.6", input: "What's the weather in NYC?", tools: [ { type: "function", name: "get_weather", description: "Get current weather for a location", parameters: { type: "object", properties: { location: { type: "string" }, }, required: ["location"], }, }, ], }); for (const item of response.output) { if (item.type === "function_call") { console.log(`${item.name}(${item.arguments})`); } } ``` ```bash theme={null} curl https://api.getlilac.com/v1/responses \ -H "Authorization: Bearer your-lilac-api-key" \ -H "Content-Type: application/json" \ -d '{ "model": "moonshotai/kimi-k2.6", "input": "What is the weather in NYC?", "tools": [ { "type": "function", "name": "get_weather", "description": "Get current weather for a location", "parameters": { "type": "object", "properties": { "location": {"type": "string"} }, "required": ["location"] } } ] }' ``` ## With Instructions Use `instructions` to set system-level context: ```python theme={null} response = client.responses.create( model="moonshotai/kimi-k2.6", input="Give me a color", instructions="Always respond in JSON with 'name' and 'hex' fields.", max_output_tokens=50, ) ``` ```bash theme={null} curl https://api.getlilac.com/v1/responses \ -H "Authorization: Bearer your-lilac-api-key" \ -H "Content-Type: application/json" \ -d '{ "model": "moonshotai/kimi-k2.6", "input": "Give me a color", "instructions": "Always respond in JSON with name and hex fields.", "max_output_tokens": 50 }' ``` ## Differences from Chat Completions | Feature | Chat Completions | Responses | | ----------------- | ------------------------------------------- | ----------------------------------------------- | | Input format | `messages` array | `input` string or array | | Tool format | Nested under `function` | Flat (name/description/parameters at top level) | | Max tokens param | `max_tokens` | `max_output_tokens` | | Structured output | `response_format` | `text.format` | | Disable reasoning | `chat_template_kwargs: {"thinking": false}` | Not supported | | System prompt | `system` role message | `instructions` parameter | # API Status and Model Performance Source: https://docs.getlilac.com/inference/status Query the public Lilac status endpoint for live model uptime, throughput, and time-to-first-token metrics across configurable aggregation windows. The status endpoint returns recent live model performance and availability snapshots for the Lilac API. It is public and does **not** require authentication. ## Endpoint ``` GET https://api.getlilac.com/status ``` ## Query Parameters | Parameter | Type | Description | | --------- | -------- | --------------------------------------------------------------------------------------------------------------------------- | | `window` | `string` | Optional time window for aggregation. Supported values: `5m`, `1h`, `24h`, `30d`. We recommend explicitly passing `window`. | ## Example ```bash theme={null} curl "https://api.getlilac.com/status?window=5m" ``` ## Response ```json theme={null} { "updated_at": "2025-01-15T18:42:11Z", "window": "5m", "window_secs": 300, "stale": false, "models": [ { "id": "moonshotai/kimi-k2.6", "name": "Kimi K2.6", "tps": 142.7, "ttfb_seconds": 0.41, "uptime_pct": 99.8 } ] } ``` ### Fields | Field | Type | Description | | ----------------------- | ----------------- | ---------------------------------------------------------------------------------------------- | | `updated_at` | `string` | Timestamp for the snapshot. | | `window` | `string` | Aggregation window used. | | `window_secs` | `integer` | Aggregation window in seconds. | | `stale` | `boolean` | Whether the data may be stale. | | `models` | `array` | Array of model status entries. | | `models[].id` | `string` | Model ID. | | `models[].name` | `string` | Display name. | | `models[].tps` | `float` \| `null` | Average throughput in tokens/sec. `null` when not enough recent data exists. | | `models[].ttfb_seconds` | `float` \| `null` | Average time to first token, in seconds. `null` when not enough recent data exists. | | `models[].uptime_pct` | `float` \| `null` | Request success percentage for the selected window. `null` when not enough recent data exists. | Low-traffic models may return `null` metrics for shorter windows. If you see `null` values, retry with a wider window such as `1h`, `24h`, or `30d`. # Usage & Billing Source: https://docs.getlilac.com/inference/usage Monitor your token consumption, view per-model cost breakdowns, and manage prepaid credit billing from the Lilac dashboard in real time. Lilac tracks usage per request at the token level. You can monitor consumption and costs from the dashboard. ## Viewing Usage Navigate to **Billing** in the dashboard to see: * **Token usage over time** — prompt and completion tokens, broken down by day * **Per-model breakdown** — usage and estimated cost for each model * **Per-key breakdown** — usage attributed to individual API keys ## How Usage is Calculated Each request records: | Metric | Description | | ----------------- | --------------------------------- | | Prompt tokens | Tokens in your input messages | | Completion tokens | Tokens generated by the model | | Total tokens | Sum of prompt + completion tokens | Your cost is calculated as: ``` cost = (prompt_tokens × input_price) + (completion_tokens × output_price) ``` See [Pricing](/inference/pricing) for current per-token rates. ## Invoices Invoices are generated monthly and available in the **Billing** section of your dashboard. Each invoice includes a full breakdown of usage by model and API key. ## Managing Spend * **Credit balance** — visible at the top of the Billing page * **Auto top-up** — automatically add credits when your balance drops below a threshold * **Per-key tracking** — create separate API keys for different projects or environments to track spend independently ## Enterprise billing Enterprise customers can opt into monthly invoicing instead of prepaid credits. With monthly billing, you are invoiced at the end of each billing cycle for your usage — no need to maintain a credit balance. To set up monthly invoicing, contact us at [contact@getlilac.com](mailto:contact@getlilac.com). # Bare-metal partnerships Source: https://docs.getlilac.com/suppliers/bare-metal Work with Lilac to connect current or planned bare-metal GPU capacity with suitable customer demand. If you operate current or planned bare-metal GPU capacity, Lilac can be another route to customers with real infrastructure requirements. We find potential demand, assess whether each opportunity fits the capacity, and provide the software and VM layer between the customer and the machines. This is a direct capacity relationship. It is separate from the [Kubernetes operator program](/suppliers/operator/overview), which contributes idle cluster capacity to Lilac's shared inference network. ## What Lilac brings * **Demand discovery.** We look for potential customers through the YC community and our broader AI network. * **Contextual assessment.** Available company, funding, and workload context helps us assess technical fit and the risk profile of potential demand. * **Software and VM layer.** We provide the layer that turns compatible bare-metal capacity into an environment a customer can use. * **Coordination.** We help move a suitable opportunity through technical scoping, commercial alignment, deployment, and support. Our assessment is contextual diligence, not a formal credit rating. It does not guarantee placement, customer performance, or payment, and it does not eliminate counterparty risk. ## How responsibilities divide | Capacity partner | Lilac | | --------------------------------------------------- | ----------------------------------------------------- | | Operates the hardware and network | Finds and evaluates potential demand | | Shares capacity, access, and commercial constraints | Assesses technical fit and available customer context | | Provides hardware operations and escalation | Provides the software and VM layer | | Defines remote-hands and support coverage | Coordinates the technical and support path | The technical scope, commercial terms, and support responsibilities are agreed before a deployment moves forward. ## From capacity to deployment Share the hardware, topology, volume, region, lead time, and access model. Lilac compares the capacity with opportunities coming through its network. We review technical requirements, commercial fit, and available customer context with the capacity partner. If the opportunity works for everyone involved, the parties agree the scope and terms before the software layer is deployed. ## What we consider * Hardware, topology, and volume * Region, interconnect, and access model * Lead time, term, and deployment workflow * Support coverage, remote hands, and escalation * Customer background, funding context, and workload profile These inputs help both sides decide whether an opportunity is a good fit. They are not a fixed qualification checklist. ## Talk to us Share your fleet and timeline. We will start with the capacity you actually have and the customers it could serve well. Or email [contact@getlilac.com](mailto:contact@getlilac.com). ## Related * [Supplier program overview](/suppliers/overview) * [Dedicated GPUs for customers](/dedicated-gpus/overview) * [Suppliers marketing page](https://getlilac.com/suppliers) # Kubernetes operator onboarding Source: https://docs.getlilac.com/suppliers/getting-started Create a supplier account, share your cluster details, complete onboarding, and install the Kubernetes operator. This guide covers onboarding for the [Kubernetes operator program](/suppliers/operator/overview). It does not apply to [bare-metal partnerships](/suppliers/bare-metal), which use a separate technical and commercial process. Operator onboarding involves creating an account, submitting a brief intake form, and meeting with our team to get your cluster connected. Sign up at [console.getlilac.com](https://console.getlilac.com) using your email or Google account. Create an organization for your team — this is where you'll manage clusters, API keys, and revenue. Use the same organization for all your clusters. You can invite team members later from **Settings > Members**. Fill out the supplier intake form so we can understand your infrastructure and match workloads to your hardware. Tell us about your GPU fleet — hardware, location, availability, and capacity. We'll review your submission and follow up within one business day. Schedule a 30-minute onboarding call with our team. We'll walk through the operator installation, help you configure your first GPU pool, and answer any questions. Pick a time that works for you. During this meeting, we'll also upgrade your account to supplier status, which unlocks the supplier dashboard and cluster management features. After onboarding, you'll install the Lilac GPU operator in your Kubernetes cluster. The operator handles everything — GPU discovery, workload scheduling, health monitoring, and preemption. See the full installation guide: [Operator Installation](/suppliers/operator/installation). ## What Happens During Onboarding During the onboarding call, our team will: 1. **Review your infrastructure** — confirm GPU types, cluster topology, and availability windows 2. **Activate your supplier account** — flip your organization to supplier mode, unlocking the supplier dashboard 3. **Walk through operator setup** — help you deploy the operator and create your first GPU pool 4. **Configure scheduling** — set up availability windows so Lilac only uses GPUs when you want 5. **Test the connection** — verify the operator syncs with the Lilac control plane Come to the onboarding call with `kubectl` access to your cluster ready. This lets us do a live install together if you'd like. ## After Onboarding Once onboarded, your supplier dashboard shows: * **Cluster status** — connected, degraded, or offline * **GPU utilization** — idle, tenant, and Lilac workload breakdown * **Revenue** — real-time token counts and earnings * **Workload history** — what ran on your hardware and when You're in full control. Adjust availability windows, capacity limits, and preemption settings at any time through GPU pool configuration. # Operator cluster monitoring Source: https://docs.getlilac.com/suppliers/monitoring Monitor Kubernetes operator connectivity, workload activity, and cluster health through the Lilac dashboard and Kubernetes tools. Monitor your cluster's connection status and workloads using the Lilac dashboard and Kubernetes tools. ## Dashboard The **Clusters** section of the [Lilac console](https://console.getlilac.com) shows: ### Cluster Status | Status | Meaning | | ------------- | -------------------------------------------------------------------------- | | **Connected** | Operator is syncing normally with the control plane | | **Degraded** | Sync has failed recently — operator will retry on next cycle | | **Draining** | Disconnected for 10+ minutes — inference pods are being gracefully removed | ### Workload Activity * Desired vs. reported workloads per pool * Workload details: GPU count, pod phase, ready status, restart counts * Draining workload counts * Model assignments (which models are running on which nodes) ### GPU Allocation * Per-pool breakdown of tenant vs. Lilac GPU usage * Node details (GPU product, total GPUs) * Last sync timestamps and lease expiration Detailed usage statistics (tokens processed, revenue earned) are sent in your monthly report. See [Revenue & Payouts](/suppliers/revenue) for details. ## Kubernetes Monitoring ### Check Pool Status ```bash theme={null} kubectl get gpupool -n lilac-system ``` ### View Operator Logs ```bash theme={null} kubectl logs -n lilac-system deploy/lilac-gpu-operator -f ``` Key log events to watch: | Event | Meaning | | ------------------------------- | --------------------------------------- | | `control plane sync successful` | Normal sync completed | | `workload created` | New inference pod deployed | | `preemption triggered` | GPUs being reclaimed for your workloads | | `workload drained` | Inference pod gracefully removed | | `sync failed` | Control plane unreachable — will retry | ### View Running Inference Pods ```bash theme={null} kubectl get pods -n lilac-system -l app.kubernetes.io/managed-by=lilac ``` ### Kubernetes Events The operator emits Kubernetes events for key state transitions: | Event | Description | | -------------------------- | ------------------------------------------------- | | `PoolCleanedUp` | All managed workloads deleted from pool | | `ControlPlaneDegraded` | Control plane stopped responding | | `ControlPlaneDisconnected` | Disconnect timeout elapsed, draining workloads | | `WorkloadPreempted` | Workload evicted after grace period | | `WorkloadDraining` | Draining began (includes reason and grace period) | View events: ```bash theme={null} kubectl get events -n lilac-system --sort-by='.lastTimestamp' ``` # GPU Pool Configuration Source: https://docs.getlilac.com/suppliers/operator/gpu-pools Define GPU pool custom resources to control which nodes, how many GPUs, availability schedules, and preemption rules Lilac uses in your cluster. A **GPU pool** is a custom resource that tells the operator which GPUs in your cluster are available for Lilac inference workloads. You control everything — which nodes, how many GPUs, what hours, and how preemption works. ## Creating a GPU Pool ### Quickstart Apply a basic `GPUPool` resource to your cluster: ```yaml theme={null} apiVersion: gpu.getlilac.com/v1alpha1 kind: GPUPool metadata: name: b200-gpu-pool namespace: lilac-system spec: nodeSelector: nvidia.com/gpu.product: B200 cache: enabled: true capacity: 1000Gi workloads: inference: true ``` ```bash theme={null} kubectl apply -f gpu-pool.yaml ``` ### Fully featured example Use a fuller manifest when you want to cap the number of GPUs, define availability windows, or configure preemption behavior: ```yaml theme={null} apiVersion: gpu.getlilac.com/v1alpha1 kind: GPUPool metadata: name: b200-gpu-pool namespace: lilac-system spec: nodeSelector: nvidia.com/gpu.product: B200 capacity: maxGPUs: 64 maxUtilizationPct: 75 schedule: mode: scheduled timezone: America/New_York windows: - days: [mon, tue, wed, thu, fri] start: "18:00" end: "08:00" - days: [sat, sun] # all day preemption: gracePeriod: 30s priority: tenant cache: enabled: true capacity: 1000Gi hfTokenSecretRef: name: huggingface key: token workloads: inference: true ``` ## Model Cache Setting up a model cache is optional, but highly recommended. The cache keeps downloaded model weights on each node so repeat cold starts do not need to fetch everything from Hugging Face again. With a warm cache, cold starts can be reduced by up to 80%, which lets idle GPUs start serving workloads and earning money more quickly. A 1 TB cache is a good baseline and is included in the initial example above. For larger GPUs such as H200s, B200s, and B300s, use 2 TB or more for the fastest cold starts because those GPUs typically serve larger models. ### Starting from scratch If you are creating a new `GPUPool`, include `cache` in the resource: ```yaml theme={null} apiVersion: gpu.getlilac.com/v1alpha1 kind: GPUPool metadata: name: b200-gpu-pool namespace: lilac-system spec: nodeSelector: nvidia.com/gpu.product: B200 cache: enabled: true capacity: 1000Gi workloads: inference: true ``` ### Modify an existing GPU pool If you already have a `GPUPool`, patch it to enable the cache: ```bash theme={null} kubectl -n lilac-system patch gpupool b200-gpu-pool --type merge -p '{ "spec": { "cache": { "enabled": true, "capacity": "1000Gi" } } }' ``` ## Hugging Face Token Setting up a Hugging Face token is optional, but highly recommended. The token avoids Hugging Face rate limits for unauthenticated downloads and allows models to download at full speed. Generate a [Hugging Face access token](https://huggingface.co/settings/tokens), then create a Kubernetes Secret in the same namespace as your `GPUPool`: ```bash theme={null} kubectl -n {GPU pool namespace} create secret generic huggingface --from-literal=token={hf_token} ``` For the examples below, the GPU pool namespace is `lilac-system`. ### Starting from scratch If you are creating a new `GPUPool`, include `hfTokenSecretRef` in the resource: ```yaml theme={null} apiVersion: gpu.getlilac.com/v1alpha1 kind: GPUPool metadata: name: b200-gpu-pool namespace: lilac-system spec: nodeSelector: nvidia.com/gpu.product: B200 hfTokenSecretRef: name: huggingface key: token workloads: inference: true ``` Apply it with: ```bash theme={null} kubectl apply -f gpu-pool.yaml ``` ### Modify an existing GPU pool If you already have a `GPUPool`, patch it to attach the Hugging Face token secret: ```bash theme={null} kubectl -n lilac-system patch gpupool b200-gpu-pool --type merge -p '{ "spec": { "hfTokenSecretRef": { "name": "huggingface", "key": "token" } } }' ``` ## Configuration Reference ### `nodeSelector` Standard Kubernetes label selector. Only nodes matching these labels are included in the pool. ```yaml theme={null} nodeSelector: nvidia.com/gpu.product: B200 # GPU model topology.kubernetes.io/zone: us-east-1a # Optional: limit to a zone ``` ### `capacity` Control how much of your GPU fleet Lilac can use. | Field | Type | Description | | ------------------- | --------------- | ----------------------------------------------------------------------------------------------- | | `maxGPUs` | integer | Maximum number of GPUs Lilac can use across all nodes | | `maxUtilizationPct` | integer (0–100) | Maximum percentage of matching GPUs Lilac can consume. If omitted, no percentage cap is applied | ### `schedule` Define when GPUs are available for Lilac workloads. | Mode | Behavior | | ----------- | ------------------------------------------------------ | | `always` | GPUs are always available (respecting capacity limits) | | `scheduled` | GPUs are only available during defined time windows | ```yaml theme={null} schedule: mode: scheduled timezone: America/New_York windows: - days: [mon, tue, wed, thu, fri] start: "18:00" end: "08:00" - days: [sat, sun] # all day — omit start/end ``` Use `mode: always` if you have dedicated GPUs that aren't used for other workloads. Use `mode: scheduled` to share GPUs between your workloads (daytime) and Lilac (evenings/weekends). ### `preemption` Controls what happens when your workloads need GPUs back. | Field | Type | Description | | ------------- | -------- | ---------------------------------------------------------------------------- | | `gracePeriod` | duration | Time given to inference pods to finish in-flight requests before termination | | `priority` | string | `tenant` means your workloads always take priority | ### `cache` Configures a shared Hugging Face model cache on each node in the pool. Omitting this block disables caching, so vLLM pods download model weights from Hugging Face on every cold start. | Field | Type | Description | | ------------------ | -------- | ---------------------------------------------------------------------------------------------------------------- | | `enabled` | boolean | Enable the shared model cache and cache pruner. Defaults to `true` when `cache` is configured | | `capacity` | quantity | Default per-node cache size. Use `1000Gi` as a baseline, or more for larger GPUs such as H200s, B200s, and B300s | | `retention.maxAge` | duration | Evict cached models older than this duration. Defaults to `720h` | | `overrides` | array | Per-node cache capacity overrides selected by node labels | ```yaml theme={null} cache: enabled: true capacity: 1000Gi ``` ### `hfTokenSecretRef` References the Kubernetes Secret key that stores your Hugging Face access token. | Field | Type | Description | | ------ | ------ | -------------------------------------------------- | | `name` | string | Secret name in the same namespace as the `GPUPool` | | `key` | string | Secret key containing the Hugging Face token | ```yaml theme={null} hfTokenSecretRef: name: huggingface key: token ``` ### `workloads` Toggle which workload types this pool accepts. | Field | Type | Description | | ----------- | ------- | -------------------------------------- | | `inference` | boolean | Allow inference workloads on this pool | ## Multiple Pools You can create multiple GPU pools for different hardware or schedules: ```yaml theme={null} # Pool for A100 GPUs — always available apiVersion: gpu.getlilac.com/v1alpha1 kind: GPUPool metadata: name: dedicated-a100s namespace: lilac-system spec: nodeSelector: nvidia.com/gpu.product: A100 capacity: maxGPUs: 4 schedule: mode: always preemption: gracePeriod: 30s priority: tenant workloads: inference: true ``` ## Checking Pool Status ```bash theme={null} kubectl get gpupool -n lilac-system ``` ``` NAME PHASE GPUS IDLE WORKLOADS AGE b200-gpu-pool Active 8 6 3 2d dedicated-a100s Active 4 4 2 1d ``` For detailed status: ```bash theme={null} kubectl describe gpupool b200-gpu-pool -n lilac-system ``` # How the Operator Works Source: https://docs.getlilac.com/suppliers/operator/how-it-works Understand the Lilac GPU operator architecture, its 30-second sync loop with the control plane, and how it manages inference pods on idle GPUs. The Lilac GPU operator is a Kubernetes controller that runs inside your cluster. It discovers idle GPUs, communicates with the Lilac control plane, and manages inference workload pods — all without touching your existing workloads. ## Architecture ```mermaid theme={null} graph LR A[GPU Operator] -->|Discovers idle GPUs| B[Your Cluster Nodes] A -->|Syncs state every 30s| C[Lilac Control Plane] C -->|Assigns workloads| A A -->|Creates/drains| D[vLLM Inference Pods] E[Inference Users] -->|API requests| C C -->|Routes traffic| D ``` ## The Sync Loop The operator runs a reconciliation loop every **30 seconds** for each GPU pool: Is the current time within the pool's availability window? If not, the operator skips this pool. The operator scans nodes matching the pool's `nodeSelector` and counts available GPUs, distinguishing between your pods and Lilac inference pods. Applies your configured limits — `maxGPUs` and `maxUtilizationPct` — to determine how many GPUs Lilac can use. Sends a full state snapshot (node inventory, running workloads, draining workloads) to the Lilac control plane and receives back a desired state with workload assignments. Creates new inference pods for assigned workloads, drains pods that are no longer needed, and cleans up any pods that have drifted from the desired spec. ## Connection States The operator maintains a connection state with the control plane: | State | Meaning | | ------------- | -------------------------------------------------------------------------- | | **Connected** | Syncing normally | | **Degraded** | Sync failed, retrying on next cycle | | **Draining** | Disconnected for over 10 minutes — gracefully shutting down inference pods | A single successful sync returns the operator from Degraded to Connected. ## Preemption When your workloads need GPUs back, the operator handles it automatically. See [Preemption](/suppliers/operator/preemption) for details on how this works. ## What Gets Deployed When the control plane assigns a workload, the operator creates a pod running [vLLM](https://docs.vllm.ai/) — a high-performance inference engine. Each pod: * Runs a single model * Uses one or more GPUs on a single node * Is labeled and managed by the operator * Is automatically cleaned up when no longer needed Your existing pods, namespaces, and resources are never modified. # Operator Installation Source: https://docs.getlilac.com/suppliers/operator/installation Install the Lilac GPU operator in your Kubernetes cluster using Helm. Covers prerequisites, namespace setup, chart configuration, and verification. This guide walks through installing the Lilac GPU operator in your cluster. The operator is deployed via a Helm chart hosted on AWS ECR. ## Prerequisites * [Kubernetes 1.28+](https://kubernetes.io/docs/setup/) — if you're running a single node and aren't already in a Kubernetes cluster, [k3s](https://docs.k3s.io/quick-start) is a lightweight option that's easier to set up and connect * [`kubectl`](https://kubernetes.io/docs/tasks/tools/#kubectl) configured with cluster admin access * [`helm` v3](https://helm.sh/docs/intro/install/) * NVIDIA GPU nodes with the [NVIDIA GPU Operator](https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/latest/getting-started.html) installed * A Lilac supplier API key (generated during [onboarding](/suppliers/getting-started)) ## Install with Helm ```bash theme={null} kubectl create namespace lilac-system ``` ```bash theme={null} helm install lilac-gpu-operator \ oci://public.ecr.aws/lilac/lilac-gpu-operator \ --version 0.3.5 \ --namespace lilac-system \ --set apiKey="YOUR_SUPPLIER_API_KEY" \ --set clusterName="my-gpu-cluster" ``` If you hit AWS Public ECR rate limits while installing or pulling the operator image, use our Docker Hub mirror instead. Keep the same command and values, but replace `oci://public.ecr.aws/lilac/lilac-gpu-operator` with `oci://docker.io/getlilac/lilac-gpu-operator`. Replace `my-gpu-cluster` with a name that identifies this cluster in your dashboard. The Helm chart automatically creates the API key secret, control plane config, CRDs, RBAC, and service accounts. No manual setup required. ```bash theme={null} kubectl get pods -n lilac-system ``` You should see the operator pod running: ``` NAME READY STATUS RESTARTS AGE lilac-gpu-operator-... 1/1 Running 0 30s ``` Apply a basic `GPUPool` to tell the operator which GPUs to manage. Save the following as `gpu-pool.yaml` and apply it: ```yaml theme={null} apiVersion: gpu.getlilac.com/v1alpha1 kind: GPUPool metadata: name: b200-gpu-pool namespace: lilac-system spec: nodeSelector: nvidia.com/gpu.product: B200 cache: enabled: true capacity: 1000Gi workloads: inference: true ``` ```bash theme={null} kubectl apply -f gpu-pool.yaml ``` See [GPU Pool Configuration](/suppliers/operator/gpu-pools) for more advanced setups, including time-based schedules, preemption policies, per-node cache overrides, and Hugging Face token configuration. ## Verify Control Plane Connection Check the operator logs to confirm it connected to the Lilac control plane: ```bash theme={null} kubectl logs -n lilac-system deploy/lilac-gpu-operator ``` Look for a log line like: ``` INFO control plane sync successful cluster_id=abc123 ``` Your cluster should also appear as **Connected** in the Lilac dashboard within 30 seconds. ## Helm Values | Value | Required | Default | Description | | -------------------- | -------- | -------------------------- | ------------------------------------------ | | `apiKey` | Yes | — | Supplier API key from the Lilac dashboard | | `clusterName` | Yes | — | Human-readable name for your cluster | | `controlPlaneUrl` | No | `https://api.getlilac.com` | Control plane URL | | `disconnectTimeout` | No | `10m` | Time before cluster is marked disconnected | | `image.tag` | No | Chart app version | Override the operator image tag | | `resources.limits` | No | `cpu: 500m, memory: 128Mi` | Resource limits for the operator pod | | `resources.requests` | No | `cpu: 10m, memory: 64Mi` | Resource requests for the operator pod | ## Upgrading To upgrade your operator to the latest version, run: ```bash theme={null} helm upgrade --install lilac-gpu-operator \ oci://public.ecr.aws/lilac/lilac-gpu-operator \ --version 0.3.5 \ --namespace lilac-system \ --reuse-values ``` ## Uninstalling ```bash theme={null} helm uninstall lilac-gpu-operator --namespace lilac-system ``` Uninstalling the operator will drain all Lilac inference workloads from your cluster. Your own workloads are not affected. ## Next Steps Define which GPUs Lilac can use and when. Understand the sync loop and architecture. # Kubernetes operator program Source: https://docs.getlilac.com/suppliers/operator/overview Contribute idle GPU capacity to Lilac's shared inference network from an existing Kubernetes cluster. Lilac's Kubernetes operator lets suppliers make idle GPUs available to the shared inference network without displacing their own workloads. The operator starts inference workloads when eligible capacity is idle and steps aside when the cluster needs those GPUs back. This program is for idle capacity in Kubernetes clusters. For a direct relationship around current or planned bare-metal capacity, see [Bare-metal partnerships](/suppliers/bare-metal). ## How it works Your existing jobs retain priority. Lilac uses only the capacity made eligible through your GPU pool configuration. The operator detects eligible GPUs, starts inference pods, and serves traffic from Lilac's inference network. You receive 70% of the gross inference revenue processed on your hardware. Lilac retains 30%. When your workloads need the GPUs, the operator drains Lilac inference pods according to the configured preemption policy. ## Revenue model | | | | ------------------ | -------------------------------------- | | **Supplier share** | 70% of gross token revenue | | **Lilac share** | 30% | | **Payout basis** | Tokens processed on your hardware | | **Reporting** | Supplier dashboard and monthly reports | ## Requirements * A Kubernetes cluster with supported GPUs * `kubectl` access to the cluster * A Lilac supplier account Create an account, share your cluster details, and schedule onboarding. ## Related * [How the operator works](/suppliers/operator/how-it-works) * [GPU pool configuration](/suppliers/operator/gpu-pools) * [Preemption](/suppliers/operator/preemption) * [Revenue and payouts](/suppliers/revenue) # GPU Preemption Source: https://docs.getlilac.com/suppliers/operator/preemption Learn how the Lilac operator gracefully reclaims GPUs when your workloads need them back, using LIFO eviction and configurable grace periods. Your workloads always come first. When your cluster needs GPUs that Lilac is currently using, the operator automatically and gracefully reclaims them. ## How Preemption Works When the operator detects that your workloads need GPUs, it: 1. **Selects inference pods to evict** — using last-in-first-out (LIFO) ordering, the most recently created Lilac pods are evicted first 2. **Initiates graceful drain** — the selected pods receive a shutdown signal and are given the configured `gracePeriod` to finish in-flight requests 3. **Force-deletes if needed** — pods that haven't terminated after the grace period are force-deleted 4. **Reports to control plane** — the operator notifies Lilac so traffic is rerouted to other available GPUs across the network This entire process typically completes in under 60 seconds. ## Preemption Triggers | Trigger | Description | | ---------------------- | -------------------------------------------------------------------- | | **Tenant reclaim** | Your pod needs a GPU that Lilac is currently using | | **Schedule inactive** | The availability window has closed | | **Inference disabled** | You set `workloads.inference: false` on the pool | | **Disconnected** | The operator lost contact with the control plane for over 10 minutes | | **Scale down** | The control plane decided to reduce workloads on your cluster | | **Unhealthy** | The health tracker detected issues with a workload pod | ## Grace Period The `gracePeriod` in your GPU pool config controls how long inference pods have to finish in-flight requests: ```yaml theme={null} preemption: gracePeriod: 30s # Default: 30 seconds priority: tenant # Your workloads always win ``` 30 seconds is usually plenty for inference requests to complete. Increase this if you serve very long completions (e.g., large max\_tokens values). ## What Happens to In-Flight Requests When an inference pod is preempted: * **Completed requests** are returned normally * **Streaming requests** receive a clean stream termination * **New requests** are automatically routed to other GPUs in the Lilac network — users experience no downtime ## Zero Impact on Your Workloads The operator never modifies, evicts, or interferes with your pods. It only manages pods it created (labeled as Lilac inference workloads). Your workload scheduling, resource requests, and priority classes are untouched. # Operator revenue and payouts Source: https://docs.getlilac.com/suppliers/revenue Understand how earnings, reporting, and payouts work for suppliers in the Kubernetes operator program. In the Kubernetes operator program, you earn revenue for every inference token processed on your GPUs. Lilac handles pricing, billing, and collection, while you provide the capacity. ## Revenue Split | | Share | | ---------------------- | ----- | | **You (the supplier)** | 70% | | **Lilac** | 30% | Revenue is calculated per token based on the model being served: ``` your_payout = tokens_processed × model_token_price × 0.70 ``` ## What Drives Revenue Your earnings depend on three factors: 1. **GPU availability** — more GPU-hours available means more potential revenue 2. **Inference demand** — Lilac routes traffic to the best available GPUs across the network 3. **Model pricing** — higher-priced models generate more revenue per token ## Monthly Reporting At the end of each month, Lilac sends you a report with your earnings breakdown: * **Total tokens processed** — prompt + completion tokens across all models * **Per-cluster breakdown** — earnings by cluster and model * **Gross revenue** — total token revenue before the split * **Your payout** — your 70% share ## Payouts Payouts are sent monthly after your earnings report is generated. During onboarding, we'll collect your payment details: * **Wire transfer** — provide your bank wire information * **ACH** — provide your ACH routing and account numbers For questions about payouts or to update your payment information, email [contact@getlilac.com](mailto:contact@getlilac.com). ## Maximizing Revenue The more GPU-hours you make available, the more you earn. Consider widening your availability windows or dedicating idle nodes full-time to maximize revenue. * **Extend availability windows** — evenings, weekends, and holidays tend to have high inference demand * **Add more pools** — if you have different GPU types, create separate pools for each * **Minimize preemption** — stable availability lets Lilac route more consistent traffic to your cluster