Skip to content

GLM-5.2 on OpenRouter: Configure Routing and Verify Tools

Independent research — not an official Z.ai publication.Identity and provider disclosure

GLM-5.2 request flowing through OpenRouter model, parameter and privacy filters to a dynamic provider or a pinned FP8 endpoint

Original editorial diagram of the tested routing choices. It is not an OpenRouter, Z.ai, Ionstream or Novita product screen. The later receipt image is rendered from the sanitized live responses.

OpenRouter gives one model slug to multiple inference backends. That convenience changes the deployment contract. The string z-ai/glm-5.2 can remain constant while the selected provider, precision, context limit, parameter support, latency and token price change.

A working HTTP 200 therefore answers only the first question. Production code also needs to prove which provider ran the request, whether every required parameter survived routing, whether fallback is allowed, what the selected route cost, and how the application behaves when no endpoint qualifies.

This guide supplies that verification layer. It uses raw, dependency-free Python so framework behavior cannot hide the request. If you need a client adapter, use the companion LangChain GLM-5.2 setup after this route contract passes.

  1. Separate the model from the route
  2. Copy the minimal tested request
  3. Inspect the live endpoint catalog
  4. Choose dynamic, ordered or pinned routing
  5. Read the Docker receipts
  6. Validate a tool call
  7. Reconstruct selected-route cost
  8. Apply privacy filters deliberately
  9. Troubleshoot by failure layer
  10. Promote a deployment contract
  11. Review practical questions
  12. Audit sources and method

Use these three identifiers exactly:

Layer Value What it selects
API base https://openrouter.ai/api/v1 OpenRouter’s OpenAI-compatible gateway
Model ID z-ai/glm-5.2 The GLM-5.2 model group inside that gateway
Credential OPENROUTER_API_KEY Your OpenRouter account and spend boundary

Do not send the OpenRouter slug to Z.ai’s first-party endpoint, and do not send a Z.ai Coding Plan key to OpenRouter. Coding Plan is a different subscription product with a supported-tool policy. The Coding Plan versus API guide keeps those commercial routes separate.

Z.ai’s GLM-5.2 guide documents the publisher’s text modality, one-million-token context, 128K maximum output, reasoning, function calling, caching and structured output. OpenRouter’s model view groups third-party endpoints under that model. A grouped model page does not make every endpoint identical to the first-party API.

Keep the key outside code:

Set the gateway credential without printing it
export OPENROUTER_API_KEY="your-openrouter-api-key"
test -n "$OPENROUTER_API_KEY" && echo "OPENROUTER_API_KEY is set"

This standard-library script reproduces the successful dynamic text profile:

verify_glm52_openrouter.py
import json
import os
import urllib.request
url = "https://openrouter.ai/api/v1/chat/completions"
payload = {
"model": "z-ai/glm-5.2",
"messages": [
{
"role": "user",
"content": (
"Return exactly OPENROUTER_DEFAULT_OK "
"and no other text."
),
}
],
"temperature": 0,
"max_tokens": 128,
"reasoning": {"effort": "none", "exclude": True},
"provider": {
"allow_fallbacks": True,
"require_parameters": True,
"data_collection": "deny",
"sort": "latency",
},
}
request = urllib.request.Request(
url,
data=json.dumps(payload).encode(),
method="POST",
headers={
"Authorization": f"Bearer {os.environ['OPENROUTER_API_KEY']}",
"Content-Type": "application/json",
"HTTP-Referer": "https://example.com/",
"X-OpenRouter-Title": "GLM-5.2 route check",
},
)
with urllib.request.urlopen(request, timeout=60) as response:
body = json.load(response)
choice = body["choices"][0]
content = (choice["message"].get("content") or "").strip()
assert content == "OPENROUTER_DEFAULT_OK"
assert choice["finish_reason"] == "stop"
assert body["model"] == "z-ai/glm-5.2"
assert body.get("provider")
print(
{
"model": body["model"],
"provider": body["provider"],
"finish_reason": choice["finish_reason"],
"usage": body.get("usage"),
}
)

OpenRouter’s quickstart documents the base URL, Bearer authentication and optional attribution headers. The script adds application checks that the generic quickstart cannot know: exact content, finish reason, reported model, selected provider and usage.

reasoning.effort: "none" kept all three successful acceptance calls at zero reported reasoning tokens. That is useful for a mechanically checkable marker. It is not a recommendation for hard reasoning tasks. See the GLM-5.2 reasoning-effort map before raising effort and output budgets.

Check availability before a paid call:

Read current GLM-5.2 endpoint metadata
curl -fsS \
"https://openrouter.ai/api/v1/models/z-ai/glm-5.2/endpoints" |
jq '{
id: .data.id,
endpoints: [
.data.endpoints[] |
{
tag,
provider_name,
status,
quantization,
context_length,
max_completion_tokens,
supported_parameters,
pricing
}
]
}'

Our dated snapshot contained:

Catalog field July 30 observation
Endpoints / named providers 33 / 29
Context minimum / median / maximum 96,890 / 1,048,576 / 1,048,576
Endpoints at or above one million context 24
FP4 / FP8 / unspecified precision 9 / 16 / 8
tools / tool_choice declared 33 / 32
structured outputs declared 27
parallel_tool_calls declared 1
reasoning effort declared 33

Those differences are operational. A one-million-token prompt can fail if the selected endpoint advertises only 96,890 tokens. A request with parallel_tool_calls has a much smaller eligible pool than a request with one tool. require_parameters: true asks the router to exclude endpoints that do not declare the fields you sent; it does not convert catalog metadata into a guaranteed successful call.

The endpoint feed also contained a maximum-completion outlier of 1,048,576. Do not turn that field into a model claim. Z.ai’s first-party page says 128K maximum output. Until a selected provider contract and a bounded test prove otherwise, cap output at the smaller verified limit.

OpenRouter’s provider-routing reference defines three useful operating modes.

Dynamic latency-oriented profile
{
"provider": {
"sort": "latency",
"allow_fallbacks": true,
"require_parameters": true,
"data_collection": "deny"
}
}

Use this for prototypes and workloads where availability matters more than a fixed backend. Record response.provider, token usage and cost on every call. Do not assume the next call will select the same provider.

Ordered preference with normal fallback
{
"provider": {
"order": ["novita/fp8"],
"allow_fallbacks": true,
"require_parameters": true,
"data_collection": "deny"
}
}

This expresses a preference, not a pin. If the named endpoint cannot serve the request, OpenRouter may continue through its remaining eligible list. That is often the correct production compromise when the application can tolerate provider drift.

Exact endpoint profile used in the live text test
{
"provider": {
"only": ["novita/fp8"],
"allow_fallbacks": false,
"require_parameters": true,
"data_collection": "deny"
}
}

Use the full provider/variant slug when precision or an endpoint-specific contract matters. Use a base slug such as novita when every variant from that provider is acceptable. Failing closed trades uptime for reproducibility: the application receives an error instead of silently moving to another backend.

Sanitized Docker receipt showing GLM-5.2 dynamic and pinned OpenRouter text calls, a successful dynamic tool call, a pinned tool routing failure, catalog counts and reported costs

Actual evidence view generated from the sanitized archive. It contains no API key, Authorization header, cookie, response ID, tool-call ID, hidden reasoning, raw provider error message, balance or account metadata.

Case Provider policy Result Time Reported cost
Dynamic text latency sort, fallback on Ionstream; exact marker 7.920 s $0.0000516
Pinned text only novita/fp8 Novita; exact marker 1.826 s $0.0000313472
Dynamic tool latency sort, fallback on Ionstream; exact call 1.338 s $0.00017768
Pinned tool only novita/fp8 HTTP 404; no eligible endpoint 0.581 s not reported
Invalid provider only nonexistent slug expected HTTP 404 0.600 s not reported
Invalid model nonexistent model ID expected HTTP 400 1.341 s not reported

The values are single observations. They do not establish latency percentiles, uptime, output quality or a winner. The useful result is structural: dynamic routing could satisfy the forced tool call, while the exact endpoint could satisfy the text call but not that tool request at the same test time.

The public endpoint record for novita/fp8 declared tools and tool_choice. The pinned request still produced a classified no-endpoint/provider/tool error. That discrepancy is why production acceptance must send the real combination of model, tool schema, routing policy and privacy fields. Catalog inspection alone is insufficient.

Download the sanitized JSON receipt.

The successful dynamic request forced one synthetic function:

Tool definition and forced selection
{
"tools": [
{
"type": "function",
"function": {
"name": "lookup_ticket",
"description": "Read one synthetic routing fixture.",
"parameters": {
"type": "object",
"properties": {
"ticket_id": {
"type": "string",
"description": "Exact synthetic ticket identifier."
}
},
"required": ["ticket_id"],
"additionalProperties": false
}
}
}
],
"tool_choice": {
"type": "function",
"function": {"name": "lookup_ticket"}
}
}

The application accepted only:

Observed validated call
{
"finish_reason": "tool_calls",
"provider": "Ionstream",
"tool": {
"name": "lookup_ticket",
"arguments": {"ticket_id": "ROUTE-730"}
}
}

That response proves tool selection and argument serialization. It does not prove execution. Your application must parse the argument string, reject unknown keys, validate types and business rules, authorize the action, execute it with time and spend limits, append the matching tool result, and validate the model’s final answer. The complete GLM-5.2 tool loop covers that second half.

OpenRouter’s tool guide also says tool definitions belong in the follow-up request so the router can validate the schema again. Keep reasoning details and the assistant tool-call message intact when the selected model requires them.

The top-level catalog snapshot displayed $0.6944/M input, $0.12896/M cached input and $2.1824/M output. Those were discounted, changing gateway values, not a universal backend rate. The same day’s public model page displayed another price, reinforcing the need to date every quote.

The dynamic text receipt lets us infer the actual selected-route arithmetic:

Ionstream text receipt
18 input × $1.40 / 1M = $0.0000252
6 output × $4.40 / 1M = $0.0000264
reported total $0.0000516

The pinned Novita text receipt matched its catalog entry:

Pinned Novita text receipt
20 input × $0.6944 / 1M = $0.0000138880
8 output × $2.1824 / 1M = $0.0000174592
reported total $0.0000313472

For a hypothetical 100,000 uncached input and 10,000 output tokens:

Same workload, two observed price shapes
pinned snapshot = 100,000 × $0.6944/M + 10,000 × $2.1824/M
= $0.091264
dynamic text rate = 100,000 × $1.40/M + 10,000 × $4.40/M
= $0.184000
difference = $0.092736, or 101.61% above the lower route

This does not say the pinned route is always cheaper. Dynamic routing can change backend, price and discount. Credit-purchase fees, taxes, retries, cache eligibility and future promotions are also outside the arithmetic. Use the response’s usage.cost for per-call telemetry and the GLM-5.2 cost calculator for workload scenarios.

The live tests sent:

{
"data_collection": "deny"
}

OpenRouter’s routing docs describe that as a filter for providers that may store or use request data. Its data-collection page says gateway prompt/response logging and product-improvement use are opt-in, while request metadata such as token counts and latency remains stored. Downstream providers still have their own policies.

For a stricter retention requirement, OpenRouter exposes:

{
"data_collection": "deny",
"zdr": true
}

We did not send that stronger combination in this run. Test it with your actual model parameters because it can shrink the eligible endpoint pool. The ZDR documentation also warns that inference routing controls do not automatically cover optional third-party plugins or server tools. A web-search plugin can have a different processor and retention path from the selected model endpoint.

Never log the API key, Authorization header, prompt, raw provider error body or hidden reasoning by default. Keep only the fields needed to explain an incident: internal request correlation, selected model and provider, route policy version, status, finish reason, token counts, cost, retry count and a redacted error category.

Symptom Likely layer Safe next check
HTTP 401 Missing, invalid or disabled OpenRouter key Check variable presence without printing it; do not send a Z.ai key
HTTP 402 Insufficient account credit Stop automatic retries and require a budget decision
HTTP 400 for model Wrong slug or invalid field Use exactly z-ai/glm-5.2; compare the request with /models
HTTP 404 after only Invalid provider or no route satisfying that exact policy Inspect the full endpoint slug, tool fields and privacy filters; do not silently remove the pin
HTTP 429 Gateway or route rate limit Honor Retry-After, add jitter and cap retries
HTTP 502/503 Provider failure or no eligible provider Preserve policy evidence; retry only when the operation is idempotent
Empty content with length Reasoning or output consumed the cap Inspect reasoning-token usage and raise a bounded output budget
Tool works dynamically but fails pinned Selected endpoint cannot satisfy the full request now Decide whether to allow fallback or fail closed; do not call the tool without validation
Long prompt fails below one million Chosen endpoint has a smaller context contract Read endpoint metadata, count tokens and reserve output/tool overhead
Parallel tools fail Very small eligible pool Set parallel_tool_calls: false or pin the one verified route

OpenRouter’s error reference documents standard status classes and Retry-After handling. Our invalid model returned 400, while invalid and currently unsatisfied exact-provider policies returned 404. Treat the actual status plus a sanitized error category as evidence; do not retry every non-200 as if it were transient.

The LangChain route test documents another failure shape: reasoning consumed a small output cap and left no final text. A gateway response can be schema-valid and still fail the application predicate.

Promote a route only after acceptance tests

Section titled “Promote a route only after acceptance tests”

Use a versioned contract for every production route:

GLM-5.2 OpenRouter promotion gate
model: z-ai/glm-5.2
endpoint_catalog_checked_at: 2026-07-30T02:42:33+08:00
provider_policy:
mode: dynamic
sort: latency
allow_fallbacks: true
require_parameters: true
data_collection: deny
reasoning:
effort: none
required_checks:
exact_text: pass
exact_tool_schema: pass
selected_provider_recorded: pass
finish_reason_checked: pass
usage_and_cost_recorded: pass
negative_controls:
invalid_model_rejected: pass
invalid_provider_rejected: pass
limits:
timeout_seconds: 60
retries: 0
rollback:
trigger: route, cost, schema, privacy, or latency gate fails

The production version should add a representative prompt set, p50/p90 latency, tool-call validity rate, context limits, maximum accepted cost, privacy requirements and an explicit fallback decision. Freeze the route policy beside application code. A dashboard setting changed outside source control can otherwise alter behavior without a deploy.

Run the same suite after model, SDK, tool schema, provider order, privacy setting or endpoint revision changes. One successful marker validates connectivity; a release gate validates the user task.

No. OpenRouter is a third-party gateway that can route GLM-5.2 to multiple providers. Z.ai publishes the model and a separate first-party API. Compare the routes in the GLM-5.2 API provider guide.

Use z-ai/glm-5.2 with https://openrouter.ai/api/v1. The first-party Z.ai model ID is glm-5.2. Do not mix the two namespaces.

Yes. OpenRouter’s quickstart documents pointing the OpenAI SDK at its base URL. Still pass the provider policy as an extra request body and verify that your SDK preserves it on the wire.

Does require_parameters: true guarantee tool calling?

Section titled “Does require_parameters: true guarantee tool calling?”

No. It filters against declared endpoint support. Our exact endpoint advertised both tool fields, yet the forced pinned request returned a no-eligible-endpoint 404 while dynamic routing succeeded. Keep a live tool acceptance test.

Enable them when availability matters and your application can tolerate a different backend after recording and validating it. Disable them when precision, processor, region, privacy or reproducibility requires fail-closed behavior.

No. OpenRouter uses an OpenRouter key. Coding Plan credentials and quota belong to Z.ai’s supported coding-tool routes, not a general gateway.

Does one million context apply to every route?

Section titled “Does one million context apply to every route?”

No. The snapshot ranged from 96,890 to 1,048,576 context tokens, with 24 of 33 endpoints at or above one million. Reserve output and tool-schema overhead inside the selected endpoint’s limit.

Why did the pinned tool call fail if text worked?

Section titled “Why did the pinned tool call fail if text worked?”

The full eligibility calculation includes model, endpoint, provider policy, privacy fields, tool schema and requested parameters. Public metadata is a dated declaration, not proof that the combined request is currently routable. The 404 is a reason to choose fallback or stop—not to remove safety fields blindly.

Primary sources checked July 30, 2026:

We also screened the current AI HOT feed as an untrusted discovery source. Its eight new items did not establish a direct GLM-5.2 routing claim, so no news claim was transferred into this article.

The functional evidence came from a digest-pinned, outbound-only Docker container. The host’s known bridge-DNS failure was reproduced before using the approved host-network exception. Three successful paid calls, one pinned route boundary, two negative controls, two public catalogs and one provider registry request were archived after removing credentials and identifiers. The separate Verify LLM API scan returned CONSISTENT behavioral evidence but failed all six short output constraints; it is not identity proof or the deployment acceptance result.

The test did not run Z.ai direct, Novita direct, Coding Plan, a one-million token prompt, parallel tools, ZDR, streaming, load, quality evaluation or latency percentiles. Prices, discounts, endpoint counts and provider status can change after the check date.