API Reference¶
Illustrative mutation fragments
The management mutations on this page are non-standalone fragments. Before adapting them, follow this site's Example Quality Contract and complete Quickstart lifecycle. Do not treat HTTP success or management readback alone as runtime proof.
The LoxiLB Inference Gateway management API is served under
/netlox/v1 on port 11111. This page catalogs the published endpoint families
and highlights contracts that require special handling.
- Production base URL:
https://gateway.example.com/netlox/v1 - Protected credential:
Authorization: Bearer <management-token> - Default media type:
application/json - Load-balancer merge patch:
application/merge-patch+jsonor JSON
Development-source behavior
Authentication-plane separation, raw-handler authorization, and the independent AI-key store described here are implemented in the current development source but have not completed release qualification. Confirm the exact Swagger served by the image you deploy.
Contract hierarchy¶
api/swagger.ymldefines the generated OpenAPI 2.0 surface, models, parameters, and declared security.- Handler and middleware code decides conditional behavior that Swagger cannot express, such as first-user bootstrap and raw-route authorization.
api/swagger-extras.ymlsupplies companion raw-handler contracts. The published companion guide covers KV inventory and AI-key patch.- Runnable
cicd/scenarios are validation evidence for selected flows; they are not a complete API contract.
The generated selected-source API schema model ledger classifies every definition added since the public documentation baseline, including direct operation models, nested components, shared envelopes, and companion-spec errors. It also records the exact required and optional fields from the frozen Swagger union.
Do not infer that a declared path is operational. Operations marked
x-not-implemented: true have no wired handler and return 501.
The Quickstart is the canonical runnable workflow for readiness, authenticated create, independent traffic validation, metrics, and exact cleanup. This reference describes contracts and links to that workflow rather than maintaining a second copy of the commands.
The documentation uses the selected source pair in Verification Status. A declared response schema is source metadata; it is not proof that every handler or generated binder returns that response. Follow the tested Quickstart for its exact response assertions.
Authentication and public exceptions¶
The primary Swagger applies BearerAuth globally. Client authorization must be verified through the deployment's qualified
management endpoint.
Swagger security does not enable an authenticator
With none of those modes configured, the current authenticator returns an unrestricted
principal and protected-looking operations are callable without credentials. Protect port 11111 and verify an unauthenticated configuration read is rejected.
Explicit public or conditional operations are:
| Operation | Runtime purpose |
|---|---|
GET /meta |
Generated POST-field metadata |
GET /metrics |
Prometheus scrape; export still depends on metrics configuration |
GET /version |
Product and build identity |
Prepare a reusable protected header:
export CONTROL_API="https://gateway.example.com/netlox/v1"
install -m 600 /dev/null ./control-plane.headers
printf 'Authorization: Bearer %s\n' "$CONTROL_PLANE_TOKEN" > ./control-plane.headers
Published endpoint families¶
The patterns below list the endpoint families covered by this guide.
Plural braces such as {key} stand for the concrete path parameters shown in
the Swagger document.
| Area | Methods and path families | Purpose / status |
|---|---|---|
| Configuration lifecycle | POST /config/import, GET /config/export, GET /config/snapshot, POST /config/restore, POST /config/persist |
Import/export, transactional snapshot/restore, and durable persistence |
| Recovery and capability status | GET /status/ready, GET /status/capabilities, GET /diagnostics, GET/PUT /maintenance |
Main-only configuration readiness, optional launch-environment capability readiness, bounded diagnostics, and operator configuration-write gate; absent from Gateway v0.9.8.9-rc.1 |
| API metadata | GET /meta |
Public generated metadata for POST operations |
| Load balancers | POST /config/loadbalancer, GET/DELETE /config/loadbalancer/all, and GET/PATCH/DELETE id/name/VIP/host-key variants |
Core L4/L7 and AI service rules, status, and statistics |
| L7 policy | GET/POST /config/l7policy, GET/DELETE /config/l7policy/id/{id} |
L7 policy lifecycle |
| Certificates and SNI | POST /config/cert, GET/PUT/DELETE /config/cert/{certId}, GET/POST/DELETE /sni/certificates |
TLS certificate and SNI mapping lifecycle. POST /config/cert answers 201 with the certId the certificate is stored under, including one the gateway minted because the request named none. A certificate entry has a usage (server, ca, client); ca and client entries serve the backend leg, see Backend TLS |
| HTTP tracing | POST /config/trace/enable, POST /config/trace/disable, GET /config/trace/status, GET/POST /config/trace/otlp, catalog/parser paths |
Trace control, OTLP exporter, and parser assignment |
| L4 tracing | POST /config/l4trace/enable, POST /config/l4trace/disable, GET /config/l4trace/status, PUT /config/l4trace/sampling, POST /config/l4trace/stats/reset |
L4 event tracing and sampling control |
| Connection and routing state | GET /config/conntrack/all, GET /config/port/all, GET/POST/DELETE /config/route... |
Conntrack, interfaces, and static routes |
| Sessions | GET/POST/DELETE /config/session..., GET/POST/DELETE /config/sessionulcl... |
Session and ULCL session configuration |
| Policy and mirroring | GET/POST/DELETE /config/policy..., GET/POST/DELETE /config/mirror... |
Packet policy and mirror lifecycle |
| Interface addresses | GET/POST/DELETE /config/ipv4address..., GET/POST/DELETE /config/ipv6address... |
IPv4 and IPv6 address management |
| L2 neighbor state | GET/POST/DELETE /config/neighbor..., /config/fdb..., /config/vlan... |
Neighbor, FDB, VLAN, and VLAN-member lifecycle |
| VXLAN | GET/POST/DELETE /config/tunnel/vxlan... including peer paths |
VXLAN tunnels and peers |
| CI and endpoint state | GET/POST /config/cistate..., GET/POST/DELETE /config/endpoint..., POST /config/endpointhoststate |
Cluster-instance and endpoint health/configuration state |
| Firewall and filtering | GET/POST/DELETE /config/firewall..., /config/ipfilter..., GET/POST/DELETE/PUT /config/securityrate... |
Firewall, IP filter, and unified security-rate configuration/reset |
| Node status | GET /status/process, GET /status/device, GET /status/filesystem |
Process, device, and filesystem status |
| Runtime parameters | GET/POST /config/params |
Runtime parameters such as log level |
| IPsec | GET/POST /config/ipsec, tunnel, action, peer-config, SA, stats, certificate, validation, and CA-certificate paths |
IPsec global state, tunnels, actions, SAs, stats, and certificate lifecycle |
| BGP | Neighbor, defined-set, policy-definition, apply-policy, and global paths under /config/bgp |
BGP neighbors and policy configuration |
| Prometheus | GET /metrics, GET/POST/DELETE /config/metrics |
Public scrape plus protected export configuration |
| GPU and workers | POST /config/gpu/enable, POST /config/gpu/disable, GET /config/gpu/status, cleanup, GET/POST /config/worker/metrics |
Worker telemetry ingestion and status |
| Product identity | GET /version |
Public product, version, and build identity |
| BFD | GET/POST/DELETE /config/bfd... |
BFD session lifecycle |
| Logs | GET /logs, GET /log-archives, GET /log-archives/{filename} |
Filtered live logs and archive download |
| CORS | GET/POST /config/cors..., DELETE /config/cors/{cors_url} |
CORS origin lifecycle |
| AI keys, JWT, and quotas | API-key paths; GET/POST /config/ai/jwtauthprofile; DELETE /config/ai/jwtauthprofile/{name}; tenant, user, and defaults rate-limit paths |
Data-plane credentials and the quota ladder; independent from management authentication |
| Engine and KV discovery | GET /config/ai/model-profiles[/{profile_id}]; GET .../kvexactstatus |
Read-only published profile discovery and dedicated desired/enforced KV binding status; current main, REST-only |
| Sockmap control | POST .../sockmapreset |
Close this service's currently accelerated connections without changing sockMapMode; current main, REST-only |
Configuration lifecycle and recovery operations¶
Treat snapshot, restore, persistence, readiness, diagnostics, and maintenance as one recovery lifecycle rather than independent convenience endpoints.
| Operation | Typed result | Contract boundary |
|---|---|---|
GET /config/snapshot |
Snapshot document | Captures the current configuration with schema and checksum; a bare capture has no persisted lineage generation. |
POST /config/restore (commit: false) |
RestoreResult |
Parses, migrates, checks dependencies, and plans without mutation; success is not proof that apply-time validation will pass. |
POST /config/restore (commit: true) |
RestoreResult |
Preserves pre-state, applies, verifies, and rolls back on failure; inspect persisted separately because write-through can fail after the live restore succeeds. |
POST /config/persist |
PersistResult |
Atomically writes the active configuration and returns identity, coverage, and monotonic generation. |
GET /status/ready |
ReadyStatus |
Returns the same typed body with HTTP 200 or 503; covers configuration recovery, not GPU, inference, or complete data-plane health. |
GET /status/capabilities |
CapabilityStatusList |
Returns HTTP 200 with per-capability ready verdicts for optional features gated by the launch environment. It is not overall health and does not affect /status/ready. |
GET /diagnostics |
DiagnosticsStatus |
Bounded version, readiness, maintenance, eBPF, map, and dependency context; sanitize output before sharing. |
GET/PUT /maintenance |
MaintenanceStatus |
Reports configuration-write gating and observed drain state. Inference refusal depends on the attached data path and admission mode; verify affected services independently. |
The recovery endpoints are implemented in the selected Gateway source; Gateway
v0.9.8.9-rc.1 includes snapshot, restore, and persist but not readiness, diagnostics, or
maintenance, and it does not include the capability surface. See
Persistence, Backup, and Restore and
Readiness, Capabilities, Diagnostics, and Maintenance
for sequencing and validation gates.
Optional capability readiness¶
Current Gateway main exposes a REST-only preflight for optional features whose availability is decided by the Gateway process environment rather than by a request body:
curl --fail-with-body --silent --show-error \
--header @control-plane.headers \
"$CONTROL_API/status/capabilities" \
> capabilities.json
jq -e '
.capabilities[] |
select(.name == "kv_exact_vllm") |
.ready == true
' capabilities.json
The endpoint always returns HTTP 200 for an authorized request; readiness lives in each entry.
An absent name means the build does not know that capability, which is different from a present
entry with ready=false. Clients must tolerate capability names they do not recognize.
The current known capability is kv_exact_vllm. It uses the same predicate as rule admission:
a nonempty LLB_KV_NONE_HASH_SEED of at most 23 bytes is required and must match vLLM's
PYTHONHASHSEED. An unready entry carries KV_EXACT_SEED_UNSET or
KV_EXACT_SEED_TOO_LONG; attempting to create a vLLM KV-exact rule is then refused with HTTP
412 and the same operator-facing reason. This surface does not establish tokenizer, engine,
event-stream, or data-plane readiness.
Worker metric updates do not make a plain sel: 9 rule capacity-aware. That path uses
prefix-affinity, conversation-affinity, and healthy-endpoint fallbacks without consuming pushed
worker metrics. Telemetry ingestion is separate from placement behavior.
Worker telemetry contract¶
Enable GPU monitoring before publishing worker telemetry:
curl --fail-with-body --silent --show-error \
--request POST "$CONTROL_API/config/gpu/enable" \
--header @control-plane.headers
Then publish one worker sample:
curl --fail-with-body --silent --show-error \
--request POST "$CONTROL_API/config/worker/metrics" \
--header @control-plane.headers \
--header 'Content-Type: application/json' \
--data '{
"endpoint_ip": "198.51.100.11:8000",
"queued_requests": 3,
"swapped_requests": 0,
"kv_cache_usage_perc": 62,
"num_gpu_blocks": 8192,
"timestamp": "2026-08-27T00:00:00Z"
}'
| Field | Required | Meaning |
|---|---|---|
endpoint_ip |
Yes | Worker address in IP:port form |
queued_requests |
Yes | Non-negative running-plus-waiting queue depth |
kv_cache_usage_perc |
Yes | KV-cache utilization on a 0–100 integer scale |
swapped_requests |
No | Non-negative preemption/swap delta |
num_gpu_blocks |
No | Static block count reported by the serving engine |
timestamp |
No | RFC 3339 collection time |
GET /config/worker/metrics returns workers[] containing these entries and a
monitoring_enabled boolean. A successful update proves telemetry ingestion only; it does not
prove least-loaded placement.
Load-balancer rules¶
Every AI routing feature is expressed through a load-balancer rule.
mode: 4 (fullproxy) is required for request-aware AI routing.
| Method | Path | Important behavior |
|---|---|---|
POST |
/config/loadbalancer |
Create a service from serviceArguments, endpoints, and optional secondaryIPs; for a rule that exists, replace it (see Replacing a rule) |
GET |
/config/loadbalancer/all |
List services; optional projectId filtering is not an authorization boundary |
DELETE |
/config/loadbalancer/all |
Deletes all rules; avoid on shared gateways |
GET |
/config/loadbalancer/id/{id} |
Read one rule by opaque ID |
GET/DELETE |
/config/loadbalancer/externalipaddress/{ip}/port/{port}/protocol/{proto} |
Read or delete by composite key |
PATCH |
Same VIP key | RFC 7386 merge patch for supported L4 rules; fullproxy/L7 and immutable-field changes are rejected |
GET |
Same VIP key plus /status or /stats |
Read lifecycle state or service counters |
GET |
Same VIP key plus /kvexactstatus |
Read strict/legacy KV binding identity, desired/enforced state, reason codes, and fence position; it is not configuration replay data |
POST |
Same VIP key plus /sockmapreset |
Close currently accelerated connections only; configuration stays unchanged |
DELETE |
Name, host-keyed, or port-range variants | Repeat every path, host, and model component used at creation |
model_name, path_prefix, and path_match_mode can be part of the exact
rule key. Omitting model_name matches only a model-less rule; it is not a
wildcard deletion.
Replacing a rule¶
A POST for a rule that exists replaces it. A request that changes nothing is answered
409 lbrule-exists.
A field the request omits takes its default, except the fields a replace keeps: id, the
administrative state, projectId, annotations, the secondary VIPs, api_key_auth,
backend_protocol, half_close_mode, the fc_* fields, pd_cache_threshold and
pd_balance_abs_threshold.
What a replace does to a FullProxy rule depends on what changed:
| What changed | Effect |
|---|---|
fc_*, half_close_mode, the backend TLS policy |
Applied in place |
| Anything else, on a rule with a CHWBL selector | Applied in place |
| Anything else, on other rules | The listening socket is kept. The rule's endpoint pool is built again: requests waiting in its capacity queue are ended, and session and conversation affinity and the rule's counts start over |
A replace the gateway refuses leaves the rule as it was: it reads back with the values it had and keeps serving.
Refusals of a create or a replace¶
| Status | Meaning | What to do |
|---|---|---|
400 naming externalIP |
The VIP of a FullProxy rule is not an address of the gateway host and is in no subnet the gateway can claim, so the listener has nothing to bind | Use an address the host holds, or one in a subnet of the gateway that it holds as cluster master |
400 naming tls_ciphers |
The TLS library does not take the cipher string | Name at least one TLS 1.3 ciphersuite and one TLS 1.2 cipher; see the configuration reference |
409 lbrule-exists |
The rule exists and the request changes nothing | Nothing to do; a rename that would change the rule's cluster instance or VIP handling is also answered 409 |
412 with reason LB_DATAPLANE_INSTALL_FAILED |
The data plane did not install the rule for a reason no request body changes, for example certificate or CRL material on the host that cannot be loaded | Read the data plane log of the gateway, correct the host-side cause, and send the request again |
A FullProxy rule on a gateway that is the cluster standby is not refused when its VIP is with the master: it is stored, and its listener comes up when the gateway takes the VIP over.
curl --fail-with-body --silent --show-error \
--request POST "$CONTROL_API/config/loadbalancer" \
--header @control-plane.headers \
--header 'Content-Type: application/json' \
--data '{
"serviceArguments": {
"externalIP": "192.0.2.20",
"port": 8080,
"protocol": "tcp",
"sel": 0,
"mode": 4,
"model_name": "example-model"
},
"endpoints": [
{"endpointIP":"198.51.100.20","targetPort":8000,"weight":1}
]
}'
See Configuration Reference for the full field contract.
Current kvModelProfile and kvExactApiMode are REST-only load-balancer fields. Discover the
profile with GET /config/ai/model-profiles, create or replace the rule, then verify the separate
kvexactstatus response. See
Model Profiles and KV-Exact Readiness.
AI keys and tenant quotas¶
| Method | Path | Purpose |
|---|---|---|
POST |
/config/ai/apikey |
Generate a key, or register development-contract api_key material |
GET |
/config/ai/apikey?tenant_id=... |
List summaries; never return raw key or stored hash |
GET |
/config/ai/apikey/{key_id} |
Read one summary, including disabled keys |
PATCH |
/config/ai/apikey/{key_id} |
Raw-handler update of allowed_models, enabled, rate_limit_rps, burst_size, and/or tokens_per_min |
DELETE |
/config/ai/apikey/{key_id} |
Permanently delete and evict the key |
POST |
/config/ai/tenant/ratelimit |
Set tenant RPS, aggregate TPM, burst, and per-model TPM |
GET |
/config/ai/tenant/ratelimit/{tenant_id} |
Read tenant and model limits |
POST |
/config/ai/user/ratelimit |
Replace explicit user RPS/TPM and user-model TPM rows |
GET |
/config/ai/user/ratelimit/{tenant_id} |
List explicit user rows for a tenant |
GET/DELETE |
/config/ai/user/ratelimit/{tenant_id}/{user_id} |
Read or remove one user's explicit row |
POST |
/config/ai/ratelimit/defaults |
Replace global or rule-scoped defaults and optional shared-VIP limits |
GET/DELETE |
/config/ai/ratelimit/defaults/{scope} |
Read or remove a global or rule defaults row |
GET/POST |
/config/ai/jwtauthprofile |
List desired JWT profiles or create/replace one |
DELETE |
/config/ai/jwtauthprofile/{name} |
Delete an unreferenced profile; referenced profiles return 409 |
These routes exist independently of --userservice. Their storage comes from
the PostgreSQL service configured by --aikey-db-*:
- no
--aikey-db-host: key/quota routes return503 ai_key_store_unconfigured; - configured service unavailable during initialization: routes return
503 ai_key_store_unavailable; - no management auth mode: the routes are callable without a credential even if the key store itself is healthy.
The api_key_auth field has five user-visible states: omitted, disabled,
required, jwt, and apikey-or-jwt. Omitted preserves backend-owned
X-Api-Key; disabled strips it without validation; required validates it
against the key store; JWT modes require jwt_auth_profile. The declaration is
independent of sse_mode and pd_disagg_mode. A required policy that cannot
be evaluated returns 503 policy_store_unavailable; an unknown key returns
401 invalid_api_key. Require backend receipt delta 0 for both.
Per-key tokens_per_min reserves a request budget before backend admission and
settles it from response usage. The selected primary Swagger describes both
stages. Confirm the
active protocol path and release evidence before making deployment claims.
See API Key Management and AI Key Store Operations. JWT profile and claim behavior is in Data-Plane Authentication and JWT.
Product identity and capability discovery¶
GET /version returns version, buildInfo, and product without bearer
authentication. The inference distribution reports
product: "loxilb-inference-gateway"; older or upstream builds may omit the
field.
curl --fail-with-body --silent --show-error \
"$CONTROL_API/version" | jq '{product, version, buildInfo}'
Use the product value only as an initial hint. Verify required paths and schema fields before applying configuration, especially across mixed versions.
Cleanup¶
Related pages¶
- Management API Authentication
- swagger-extras
- Configuration Reference
- API Key Management
- Log API Operations
- Model Profiles and KV-Exact Readiness
- Sockmap Acceleration
Selected-source contract notes¶
The source pair in Verification Status declares
EndPointHostState.epPort as an integer from 0 to 65535 with explicit
x-nullable: false; its Go field remains a value integer. That annotation
alone is not a new runtime null-rejection test. Inspect the deployed binder
and response before relying on an input-error contract.
The current snapshot declaration uses schema 1.12, including JWT profiles,
network identity, half-close policy, BGP policy assignments and audit-sink
configuration. See Backup and Restore for
coverage and external-secret boundaries. The current BGP startup declaration
reuses an identical running core and reconciles SetNextHopSelf; a running
ASN/router-ID/listen-port change is refused with 400. Review a scoped
snapshot replacement instead of treating startup as a general replacement.
These are source contracts, not installed-host recovery results.
An L7 FORWARD target selects within the listener's base endpoint pool.
Endpoint references restrict selection to those base-pool members, with
round-robin or weighted round-robin selection and shared health/accounting;
poolId does not resolve an independent pool. P/D rules enable event-stream
detection even when sse_mode is false. Other rules use the explicit SSE
opt-in described in SSE and Quota Management.