Skip to content
lumalabs.ai
LLM Inference

LLM Inference

Luma's hosted LLM inference API — OpenAI-compatible chat completions for GLM models, built for LLM routers and resellers.

Luma offers hosted LLM inference for GLM models through an OpenAI-compatible API. The endpoint is a drop-in replacement for the OpenAI Chat Completions API — point your existing client at Luma’s base URL, swap in a Luma-issued API key, and the same request and response shapes work out of the box.

This API is designed for LLM routers and resellers who need high-throughput token inference with postpaid billing.


EnvironmentBase URL
Productionhttps://inference.lumalabs.ai

All requests are sent to https://inference.lumalabs.ai/v1/....


Every request must include a Bearer token in the Authorization header. API keys are issued by Luma when your inference account is provisioned.

Terminal window
curl https://inference.lumalabs.ai/v1/chat/completions \
-H "Authorization: Bearer $LLM_INFERENCE_API_KEY" \
-H "Content-Type: application/json" \
-d '{...}'

Treat your API key as a secret — never expose it in client-side code or public repositories. If a key is compromised, contact Luma support to rotate it immediately.


The following models are available on the LLM Inference API. Each model is served at FP8 quantization on Luma’s GPU infrastructure.

ModelContext windowMax outputQuantizationFeatures
glm-5.2262,14432,768FP8Tools, JSON mode, structured outputs

GLM 5.2 is a general-purpose large language model with strong tool-calling and agentic capabilities. It supports function/tool calls, JSON mode, and structured output formats.

Supported sampling parameters: temperature, top_p, max_tokens, stop, frequency_penalty, presence_penalty, seed.

Context window: 262,144 tokens (256K). Max output: 32,768 tokens.


The POST /v1/chat/completions endpoint is fully OpenAI-compatible. Send a list of messages, pick a model, and receive a completion — either as a single JSON response or a stream of server-sent events.

Terminal window
curl https://inference.lumalabs.ai/v1/chat/completions \
-H "Authorization: Bearer $LLM_INFERENCE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "glm-5.2",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Explain prefix caching in one sentence."}
],
"max_tokens": 100
}'
{
"id": "chatcmpl-be40cbc6-...",
"object": "chat.completion",
"created": 1767225600,
"model": "glm-5.2",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Prefix caching stores the computed attention key-value pairs for a prompt's beginning so repeated prompts skip recomputation, reducing latency and cost."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 25,
"completion_tokens": 32,
"total_tokens": 57,
"prompt_tokens_details": {
"cached_tokens": 0
}
}
}

Set "stream": true to receive the response as a stream of server-sent events (SSE). Each chunk contains a delta with incremental content. The final chunk includes the usage object with token counts.

Terminal window
curl https://inference.lumalabs.ai/v1/chat/completions \
-H "Authorization: Bearer $LLM_INFERENCE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "glm-5.2",
"messages": [
{"role": "user", "content": "Write a haiku about GPUs."}
],
"stream": true,
"stream_options": {"include_usage": true}
}'
data: {"id":"chatcmpl-be40cbc6-...","object":"chat.completion.chunk","created":1767225600,"model":"glm-5.2","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}
data: {"id":"chatcmpl-be40cbc6-...","object":"chat.completion.chunk","created":1767225600,"model":"glm-5.2","choices":[{"index":0,"delta":{"content":"Silicon"},"finish_reason":null}]}
data: {"id":"chatcmpl-be40cbc6-...","object":"chat.completion.chunk","created":1767225600,"model":"glm-5.2","choices":[{"index":0,"delta":{"content":" whirrs,"},"finish_reason":null}]}
...
data: {"id":"chatcmpl-be40cbc6-...","object":"chat.completion.chunk","created":1767225600,"model":"glm-5.2","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":12,"completion_tokens":14,"total_tokens":26,"prompt_tokens_details":{"cached_tokens":0}}}
data: [DONE]

Because the API is OpenAI-compatible, you can use the official OpenAI SDKs by setting the base URL to Luma’s inference endpoint:

from openai import OpenAI
client = OpenAI(
api_key="your-llm-inference-api-key",
base_url="https://inference.lumalabs.ai/v1",
)
response = client.chat.completions.create(
model="glm-5.2",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What is 2 + 2?"},
],
max_tokens=50,
)
print(response.choices[0].message.content)

GLM 5.2 supports OpenAI-compatible function/tool calling. Define tools in the request, and the model can choose to call them:

Terminal window
curl https://inference.lumalabs.ai/v1/chat/completions \
-H "Authorization: Bearer $LLM_INFERENCE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "glm-5.2",
"messages": [
{"role": "user", "content": "What is the weather in Tokyo?"}
],
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a city",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "The city name"}
},
"required": ["city"]
}
}
}]
}'
{
"id": "chatcmpl-be40cbc6-...",
"object": "chat.completion",
"model": "glm-5.2",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_abc123",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\": \"Tokyo\"}"
}
}
]
},
"finish_reason": "tool_calls"
}
],
"usage": {
"prompt_tokens": 50,
"completion_tokens": 20,
"total_tokens": 70,
"prompt_tokens_details": {
"cached_tokens": 0
}
}
}

Billing is postpaid and metered — you are billed for actual token usage after the billing period closes, with no prepaid balance required.

At the end of each billing period, your usage is reported as monthly totals broken down by model with the following dimensions:

FieldDescription
ModelThe model ID (e.g. glm-5.2)
Input tokensTotal uncached input tokens
Cached input tokensTotal cached input tokens billed at the cached input rate
Output tokensTotal output (completion) tokens
Total chargeTotal charge for the billing period

These totals match your invoice exactly — every token counted in the monthly report appears on your bill.

Every response (streaming and non-streaming) includes a usage object:

{
"usage": {
"prompt_tokens": 1000,
"completion_tokens": 500,
"total_tokens": 1500,
"prompt_tokens_details": {
"cached_tokens": 600
}
}
}
FieldDescription
prompt_tokensTotal input tokens (includes cached tokens)
completion_tokensTotal output tokens generated
total_tokensprompt_tokens + completion_tokens
prompt_tokens_details.cached_tokensPortion of prompt_tokens served from cache

To compute the billable input tokens yourself: uncached_input = prompt_tokens - cached_tokens.


The API enforces two independent layers of rate limiting. Both return HTTP 429, but the response headers tell you which layer you hit and how to handle it.

LayerTriggerX-Luma-Shed headerRetry-After
Per-key limitYour API key’s RPM/TPM allowance exceededabsentPresent — wait the indicated seconds
Fleet capacityThe GPU fleet is overloadedcapacity1

Check the X-Luma-Shed response header to determine which limit you hit:

  • No X-Luma-Shed header — you hit your per-key RPM or TPM limit. Wait for the Retry-After duration, then retry. If this happens frequently, your key’s limits may need adjusting — contact Luma to request a higher allowance.
  • X-Luma-Shed: capacity — the fleet is under pressure. Back off collectively with jitter, then retry. This is a transient condition that resolves as capacity frees up.
import time
import random
import requests
def chat_with_retry(messages, max_retries=5):
url = "https://inference.lumalabs.ai/v1/chat/completions"
headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
}
payload = {"model": "glm-5.2", "messages": messages}
for attempt in range(max_retries):
response = requests.post(url, headers=headers, json=payload)
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", "5"))
jitter = random.uniform(0, retry_after * 0.3)
time.sleep(retry_after + jitter)
continue
response.raise_for_status()
return response.json()
raise Exception("Max retries exceeded")

Per-key RPM (requests per minute) and TPM (tokens per minute) limits are set when your account is provisioned and can be adjusted based on your traffic profile. Check your current limits with Luma support or contact sales to request changes.


The API uses standard HTTP status codes. All error responses follow the OpenAI error format:

{
"error": {
"message": "Human-readable error description",
"type": "invalid_request_error",
"param": null,
"code": "429"
}
}
StatusMeaningRetryable?
200Success
400Invalid request parametersNo — fix the request
401Invalid or missing API keyNo — fix auth
429Rate limited or capacity shedYes — see above
500Internal server errorYes — retry with backoff
503Service unavailableYes — retry with backoff
typeWhen
invalid_request_errorMalformed or invalid request parameters
auth_errorMissing, invalid, or revoked API key
rate_limit_errorRPM/TPM limit or fleet capacity exceeded
server_errorUnexpected internal error

There are two ways a stream can end abnormally after content has started flowing:

  • Stream stops without an error frame (mid-stream stop): The connection ends without a data: [DONE] sentinel and without an error frame. An OpenAI-compatible client reads this as a clean end of stream — the partial content looks complete from the client’s perspective. Treat the response as incomplete.

  • Stream terminates with an error frame (mid-stream error): The stream emits an error event instead of [DONE], then closes. No data: [DONE] is ever sent on this path:

data: {"error":{"message":"...","type":"server_error","code":"500"}}

Is this the same as the Luma Agents image/video API?

Section titled “Is this the same as the Luma Agents image/video API?”

No. The LLM Inference API is a separate product for text/chat LLM inference. It uses a different base URL (inference.lumalabs.ai), different API keys, and postpaid billing. The Luma Agents API covers image and video generation.

Yes. Set the base URL to https://inference.lumalabs.ai/v1 and use your Luma-issued API key. The request and response shapes are OpenAI-compatible.

No. Requests that return a 429 (rate limited) or are rejected before the first byte are never billed. Only requests that return a 200 response are metered. Mid-stream failures may have generated billable tokens before the failure; those are reconciled server-side and appear in your monthly usage report.

Contact sales to provision an inference account. Keys are issued during onboarding.