OBLETHdocs

Management API

Every route of the Management API under /api/v1, with its query parameters and request-body fields.

28 min readUpdated for v2.4.0Edit on GitHub

Conventions

The gateway serves the Management API on the admin listener (OBLETH_ADMIN_LISTEN, default 0.0.0.0:9180). The dashboard uses the same routes. Keep the port on a private network; see Security.

TopicRule
AuthAuthorization: Bearer <OBLETH_ADMIN_TOKEN> on every route except the three public ones below; compared in constant time; wrong or missing is 401
BodyJSON, Content-Type: application/json
Audit actorEvery write records an audit row; the actor is the X-Obleth-Audit-Actor header, default admin
Errors{"error": "<message>"} with 400 invalid input or refused URL, 401, 403 protected target (the reserved control-plane tenant), 404 unknown id (also a nested id under the wrong parent), 409 name conflict, 502 saved in Postgres but the Redis cache update failed (run POST /api/v1/resync)
SecretsWrite-only. Responses carry api_key_set, auth_header_set, upstream_header_names, password_set, slack_webhook_set, jwt_set instead. Omit a secret on update to keep it
Partial updatesSettings bodies: an omitted field keeps its stored value. Resource PUTs note their own rules below
PaginationList routes return everything. Request logs page with before_ms + before_request_id; the audit log with before_id
TimeUsage reads take Unix milliseconds (since_ms, until_ms); the audit log and budgets use RFC 3339

Public and system routes:

MethodPathWhat it does
GET/api/v1/healthLiveness; plain-text ok. No auth
GET/api/v1/versionversion, git_sha, built_at (null for local builds). No auth
GET/api/v1/openapi.jsonGenerated OpenAPI document. No auth
POST/api/v1/resyncRebuild the Redis resolver cache (keys, models, aliases, MCP servers) from Postgres and prune stale entries
GET/api/v1/system/control-plane-keyThe dashboard's reserved data-plane secret, for its server side only

POST /api/v1/resync returns counts: keys, keys_pruned, models, model_names_pruned, mcp_servers, mcp_servers_pruned. It is the retry for any 502, and Settings › Data and backups › Reconcile cache runs it. See Redis layout.

curl -X POST http://localhost:9180/api/v1/resync -H "Authorization: Bearer $TOKEN"

Tenants and keys

MethodPathWhat it does
POST/api/v1/tenantsCreate a tenant
GET/api/v1/tenantsList tenants
GET/api/v1/tenants/{id}Get a tenant
PUT/api/v1/tenants/{id}Update its profile
DELETE/api/v1/tenants/{id}Delete a tenant and its keys
PATCH/api/v1/tenants/{id}/statusSet status
PATCH/api/v1/tenants/{id}/scheduleSet access hours and dates
PATCH/api/v1/tenants/{id}/budgetSet the tenant budget
PATCH/api/v1/tenants/{id}/allowlistSet the models it may use
PATCH/api/v1/tenants/{id}/guardrailsSet or clear its guardrails policy
PATCH/api/v1/tenants/{id}/compressionSet or clear its compression policy
PATCH/api/v1/tenants/{id}/weightSet its fairshare weight
PATCH/api/v1/tenants/{id}/groupMove it to another fairshare group
PUT/api/v1/tenants/{id}/quotaSet token rate and in-flight cap
PUT/api/v1/tenants/{id}/tracingSpan tracing on or off for all its keys
PUT/api/v1/tenants/{id}/syntheticMark it as benchmark or test traffic
POST/api/v1/tenants/{id}/keysCreate a key; the secret is returned once
GET/api/v1/keysList keys, never secrets; ?tenant_id= for one tenant
PUT/api/v1/keys/{id}Replace a key's settings
DELETE/api/v1/keys/{id}Delete a key
PUT/api/v1/keys/{id}/disabledTurn a key off or on
PUT/api/v1/keys/{id}/tenantMove a key to another tenant
PUT/api/v1/keys/{id}/tracingSpan tracing on or off for one key
PUT/api/v1/keys/{id}/end-user-fairsharePer-user fairshare on or off for one key; see One key, many people
GET/api/v1/keys/{id}/usageOne key's activity summary
GET/api/v1/budgets/usageEvery capped tenant and key budget with its use this period

Request bodies. Task pages: Tenants and keys, Quotas and rate limits, Guardrails.

RouteFieldNotes
POST /tenantsnameRequired
POST /tenantsweight, tokens_per_minute, max_in_flight, fairshare_group, syntheticOptional
PUT /tenants/{id}name, description, organization, contact_emailname required
…/statusstatusactive, suspended, archived; the last two refuse traffic with 403
…/scheduletimezoneIANA zone, default UTC
…/scheduleactive_from, active_untilRFC 3339 or null
…/scheduleweekly_windows[{day, start_min, end_min}]; day 0–6 from Sunday, minutes from local midnight
…/budgetbudget_tokens, budget_cost_usdCaps; null clears
…/budgetbudget_periodlifetime (default), monthly, term
…/budgetbudget_started_atDefaults to now when a cap is set
…/allowlistallowed_modelsModel names; empty permits all
…/guardrailspolicy{action, input_scanners, output_scanners, guard_model, ban_keywords, fail_open} or null
…/compressionpolicy{enabled, code_compaction, dedup, compact_logs, allow_lossy}, or null for the global defaults
…/weightweightInteger
…/groupfairshare_groupGroup name
…/quotatokens_per_minute, max_in_flighttokens_per_minute required
…/tracing (tenant)tracing_enabledBoolean
…/syntheticsyntheticBoolean; its traffic is recorded as benchmark
PUT /keys/{id}/disableddisabledBoolean
PUT /keys/{id}/tenanttenant_idTarget tenant; secret, settings and budget move with the key, past usage stays
PUT /keys/{id}/tracingtracing_enabledBoolean

Guardrails action is block, redact or log_only; input scanners are prompt_injection, pii, ban_keywords, harm; output scanners pii, ban_keywords, harm; fail_open defaults to true.

API keys

POST /api/v1/tenants/{id}/keys and PUT /api/v1/keys/{id} take the same body. PUT replaces every field, so send the current weight and max_in_flight to keep them.

FieldDefaultNotes
namerequiredDisplay name
description""
budget_tokens, budget_cost_usdnullKey caps; null is uncapped
budget_periodnull (lifetime)lifetime, monthly, term
budget_started_atnow, when a cap is setStart of the current term
weight100Share among the tenant's keys, minimum 1
max_in_flightnullThe key's cap within each model pool, minimum 1

Create returns {"key": {…}, "secret": "sk_…"}. The secret is sk_ plus 48 hex characters; only its SHA-256 hash and an 18-character prefix are stored. Keys with kind: "identity" are created by the gateway for a verified identity token (Identity tokens) and managed through the same routes.

GET /api/v1/budgets/usage returns one row per capped budget: scope (tenant or key), id, tenant_id, period, budget_tokens, budget_cost_usd, used_tokens, used_cost_usd, period_start, and resets_at (monthly only).

Per-key usage summary

GET /api/v1/keys/{id}/usage returns last_used_ms, last_model, last_status_code, and requests, token, cost, energy and CO2 totals over the window. GET /api/v1/usage/keys/summary returns the same row for every key with traffic, busiest first; idle keys are absent.

Query paramDefaultNotes
since_ms24 hours agoWindow for the totals. On the single-key route last_used_ms ignores it
tenant_idunsetBulk route only
limit1000Bulk route only; at most 10000
include_internalfalseInclude health probes and benchmark traffic

A key with no traffic returns zeros and last_used_ms: 0.

Usage and request logs

MethodPathWhat it does
GET/api/v1/usageTotals per tenant
GET/api/v1/usage/keysTotals per key
GET/api/v1/usage/keys/summaryPer-key activity summary in bulk
GET/api/v1/usage/modelsTotals and latency per model
GET/api/v1/usage/speedOutput speed per model, for the window or per hour or day
GET/api/v1/usage/seriesTime series of all traffic
GET/api/v1/usage/series/tenantsTime series per tenant
GET/api/v1/usage/series/modelsThroughput and latency series for one model
GET/api/v1/usage/breakdownTenants and keys driving one model (required)
GET/api/v1/usage/cacheResponse-cache hits and misses
GET/api/v1/usage/logsIndividual requests, newest first
GET/api/v1/usage/logs/histogramRequests and failures per bucket, with the log's filters
GET/api/v1/usage/logs/facetsBusiest values per dimension, with the log's filters
GET/api/v1/usage/logs/{request_id}/spansSpans recorded for one request
GET/api/v1/usage/dailyPermanent daily rollup over a date range
POST/api/v1/usage/compactDrop raw usage older than the retention window now
GET/api/v1/costsSpend per model
GET/api/v1/overview/summaryConfiguration counts and windowed usage totals
GET/api/v1/statsLive in-flight and queued counts of the answering replica
GET/api/v1/stats/dailyDaily MCP-call or knowledge-search counters

Usage reads exclude internal traffic (health probes and synthetic tenants' benchmark traffic) unless you pass include_internal=true.

Query paramRoutesDefaultNotes
since_msall reads24 hours agoLower bound, Unix ms
tenant_id, key_id, model/usage, /usage/keys, /usage/modelsunsetFilters
tenant_id, model/usage/cacheunsetFilters
group_by/usagetenantOnly tenant returns rows; use /usage/keys or /usage/models for the others
limit/usage/keysunsetBusiest first, at most 10000
limit/usage/breakdown100Busiest first, at most 1000
bucket_ms/usage/series…300000Minimum 60 s on /series, 10 s on the others; widened to at most 5000 buckets
tenant_id/usage/seriesunsetOne tenant
model/usage/series/models, /usage/breakdown—The model
kind, days/stats/daily—, 7kind is mcp or knowledge; days 1–40
until_ms/usage/speednowUpper bound, Unix ms (exclusive)
bucket/usage/speednonenone for one row per model over the window, hour or day for one per model per hour or day; hour over more than 31 days returns days
tz/usage/speedUTCIANA time zone the hours and days are cut in
tenant_id, key_id, model/usage/speedunsetFilters

/usage/speed rows carry bucket_ms (0 for a whole-window row), model, requests (every request, failed and cached included), rated (the requests a speed was measured on: successful, uncached and producing tokens), gen_tokens_per_sec (median, the same decode rate as /usage/models), slow_tokens_per_sec (the slowest tenth), prompt_tokens_per_sec and p50_ttft_ms.

Request logs

/usage/logs, /usage/logs/histogram and /usage/logs/facets share these filters. Task page: Observability.

Query paramDefaultNotes
since_ms, until_ms24 hours ago, openInclusive bounds, Unix ms
tenant_id, key_id, modelunsetExact match
request_typeunsetFor example chat, messages, embedding; see ClickHouse usage
session_id, device_idunsetExact match
parent_request_idunsetThe helper rows of one request
statusallsuccess (2xx–3xx) or error (400 and up)
status_codeunsetOne exact status, such as 502
request_idunsetCase-insensitive prefix
include_internalfalseInclude internal traffic
traced_onlyfalseLog only: requests with spans
limit50Log only: 1–200
before_ms, before_request_idunsetLog only: cursor from the last row's ts_ms and request_id
bucket_ms60000Histogram only: at least 1 s, widened to at most 400 buckets

Spans come back ordered by start_ms, kept for 14 days. request_id is obleth's own id, also sent to clients as x-obleth-request-id.

Daily usage rollup

GET /api/v1/usage/daily reads the permanent rollup, so it covers dates the raw ledger has dropped. It excludes benchmark traffic.

Query paramDefaultNotes
start_day, end_day7 days ago, todayInclusive, YYYY-MM-DD
tenant_id, modelunsetFilters
key_idunsetOne id or a comma-separated list
group_bydayday, tenant, key, model, key_model, day_tenant, day_model, day_key_model
Response fields: usage reads and logs

Overview and stats. /overview/summary returns requests, tokens, input_tokens, output_tokens, errors, cost, has_pricing, p50_ttft_ms, avg_ttft_ms, energy and CO2 totals, and tenant_count, active_tenants, model_count, enabled_models, key_count. /stats returns in_flight, queued, max_in_flight, replicas, mode and cluster_in_flight (see Fairshare and capacity). /usage/compact returns retention_days and partitions_dropped. /stats/daily returns days and per-item daily counts: direct, tool_calls, errors, ms per MCP server, or searches, hits, chunks per collection.

Request logs. Each log row carries the usage columns (request_id, ts_ms, tenant, key, model, request_type, session_id, session_id_source, device_id, admission, status_code, tokens, cached_input_tokens, queue_wait_ms, ttft_ms, total_ms, cache_status, cost, energy, parent_request_id, model_variant) plus tenant_name, key_name, key_prefix, and has_trace. The histogram returns bucket_ms and non-empty buckets of bucket_ms, requests, errors. Facets return up to 12 values each for status_codes, models, tenants, keys and request_types (value, label, requests, errors), plus failures: the most common status code and model pairs.

Daily rollup. Rows carry day, tenant_id, key_id, model (empty or the zero UUID outside the grouping), request, success and error counts, tokens, estimated_tokens, cache hits and misses, avg_ttft_ms and avg_total_ms (successful requests only), and cost, energy and CO2 as frozen at completion.

Models

MethodPathWhat it does
POST/api/v1/modelsRegister a model
GET/api/v1/modelsList models
GET/api/v1/models/{id}Get a model
PUT/api/v1/models/{id}Update a model
DELETE/api/v1/models/{id}Delete a model
GET/api/v1/models/exportExport the registry as an obleth-models manifest
POST/api/v1/models/importMerge a manifest; ?dry_run=true previews
POST/api/v1/models/validateAdvisory pre-flight for an upstream
PUT/api/v1/models/{id}/statusSet the lifecycle: staged, active, deprecated or retired
PUT/api/v1/models/{id}/reasoningSet how the model takes reasoning effort: passthrough, mapped or unsupported
PUT/api/v1/models/{id}/listingSet listed: whether /v1/models and /model/info offer the model
GET / POST/api/v1/model-familiesList or create model families
PUT / DELETE/api/v1/model-families/{id}Update or delete a model family
PUT/api/v1/models/{id}/weightSet admission_weight
PUT/api/v1/models/{id}/rejected-request-fieldsSet the request fields the model refuses with a 400
PUT/api/v1/models/{id}/session-affinitySet the model's own session affinity: enabled, hold_ms, max_held_percent, max_bypass_secs, each optional; {} follows the gateway
PUT/api/v1/models/{id}/capacitySet max_in_flight (null for the default)
PUT/api/v1/models/{id}/capacity-modeSet capacity_mode and the discovered-mode fields
POST/api/v1/models/{id}/autotuneRun the capacity ramp probe; recommends only
POST/api/v1/models/{id}/autotune/applyApply max_in_flight and mark the model tuned
PUT/api/v1/models/{id}/cacheSet cache_enabled, cache_ttl_secs
PUT/api/v1/models/{id}/reliabilitySet timeout, retries, endpoint selection, diagnostics
GET/api/v1/models/{id}/knowledgeAttached knowledge collections
PUT/api/v1/models/{id}/knowledgeReplace attached collections: collection_ids
GET/api/v1/models/{id}/endpointsList endpoints
POST/api/v1/models/{id}/endpointsAdd an endpoint
PUT/api/v1/models/{id}/endpoints/{endpoint_id}Update an endpoint
DELETE/api/v1/models/{id}/endpoints/{endpoint_id}Remove an endpoint
GET/api/v1/models/healthLatest health summary for every model
POST/api/v1/models/healthCheck every eligible model now
GET/api/v1/models/{id}/healthOne model's summary and recent checks
POST/api/v1/models/{id}/health/checkCheck one model now
POST/api/v1/models/{id}/health/activateProbe a switched-off model; turn it on if healthy
PUT/api/v1/models/{id}/health/configSet one model's health-check settings

Model fields, for POST and PUT /api/v1/models/{id} and the manifest. Task page: Model registry.

FieldDefaultNotes
model_namerequired on createClient-facing name; not on PUT
upstream_model, api_baserequiredapi_base passes the outbound URL policy
api_keynoneWrite-only; responses show api_key_set. On PUT omit to keep, "" to clear
upstream_headersnoneName-to-value object added to every upstream call. Write-only; responses show upstream_header_names. On PUT omit to keep, {} removes all, a null value keeps that header
aliases[]At most 16 extra names, unused elsewhere, not auto; PUT replaces the list
variants[]At most 8 {name, description, boons}: names unused elsewhere that add boons. PUT replaces the list. See Variants
description""
model_typechatchat, embedding, audio_transcription, audio_speech, image, video, search (a search tool: api_base is a SearXNG root)
quantizationunknownnone, fp16, bf16, fp8, nvfp4, mxfp4, int8, int4, awq, gptq, gguf; descriptive only
input_cost_per_token, output_cost_per_token0USD per token
cost_per_image, cost_per_audio_second, cost_per_character0image, audio_transcription, audio_speech prices
cost_per_video0Flat USD per created video job
context_windowTokens
admission_weight100Multiplier on tenant weight inside this pool
max_in_flightnullPool size; null uses OBLETH_DEFAULT_MODEL_MAX_IN_FLIGHT. The fallback in discovered mode
capacity_modestaticstatic, tuned, discovered
capacity_sourceendpointsdiscovered mode: endpoints or kubernetes
per_replica_max_in_flightnullRequests one backend replica takes, 1–100000; needed for kubernetes, and for endpoints unless every endpoint sets its own. PUT null clears
capacity_headroom1.0Multiplier on the derived size, above 0 and at most 10
capacity_service, capacity_namespacenullkubernetes source; unset uses OBLETH_CAPACITY_DEFAULT_SERVICE and the allowed namespaces. PUT null or "" clears
supports_function_calling, supports_tool_choice, supports_response_schema, supports_visionfalseCapabilities
supports_system_messagestrue
tags[]auto routing tags, optional level (coding:3)
boons[]vision, structured_output, compression, knowledge, image_generation, speculation, web_search
tool_servers[]MCP server names for the tool loop; needs function calling
energy_slots_per_node0Sequences that saturate one node, for per-node energy; 0 opts out
route_bias1.0Multiplier on the auto score, clamped 0.1–3.0
auto_eligibletruefalse keeps the model out of auto
draft_model, verify_api_base, verify_upstream_model""Speculation overrides; "" clears on PUT
enabledtruefalse on create registers it switched off; a disabled model returns 403
statusactiveCreate only: staged registers it staged; change it later with …/status

PUT leaves omitted optional fields unchanged. Responses add id, capacity_tuned_at, cache and reliability fields, lifecycle, effective_status (the status in force now) and timestamps. Deleting a model or dropping an alias evicts it from Redis. Rename a model by creating it under the new name with the old one as an alias.

The manifest ("format": "obleth-models", "version": 1) is keyed by model_name, never exports secrets (has_api_key, upstream_header_names), and every other field is optional. Import creates or updates listed models, deletes nothing, reports all errors together with 400, and returns created, updated, unchanged and per-model action, changed_fields and warnings. See Import models.

Endpoint fields (POST/PUT …/endpoints):

FieldDefaultNotes
namerequiredUnique within the model
api_baserequiredPasses the outbound URL policy
api_keythe model's keyWrite-only (api_key_set); PUT omit keeps, "" clears
priority100Lower is tried first in failover
weight100Share in load_balance
enabledtrue
max_in_flightnullPer-endpoint concurrency for discovered on endpoints; PUT omit keeps, null clears

Endpoint responses add health_status, consecutive_failures, alert_state, and the last check's time, latency, HTTP status and message.

Model capacity and auto-tune

PUT …/capacity-mode takes capacity_mode plus the optional capacity_source, capacity_namespace, capacity_service, per_replica_max_in_flight and capacity_headroom, with the same rules as PUT /api/v1/models/{id}. A discovered write the gateway cannot discover is refused with 400. See Pool sizes.

POST …/autotune probes the upstream directly (bypassing admission) for chat and embedding models, within 60 s and 20000 requests, and writes nothing. See Capacity auto-tune.

FieldDefaultNotes
workloadchatchat or coding prompt shape
latency_headroom4.0Multiple of single-request p99 that marks the knee; 1.5–20
replicasunsetSizes the ramp ceiling at 32 per replica
max_concurrency64Explicit ceiling, overrides replicas; at most 512

The report has recommended_max_in_flight, knee_reason (latency_degraded, plateau, max_concurrency, no_data), baseline_p99_ms, latency_ceiling_ms, recommended_throughput_rps, and per-step results. …/autotune/apply takes {"max_in_flight": N}.

Other per-model bodies:

RouteFields
…/weightadmission_weight
…/capacitymax_in_flight
…/cachecache_enabled, cache_ttl_secs (default 300; 0 disables). See Response cache
…/reliabilityrequest_timeout_secs (null uses OBLETH_UPSTREAM_TIMEOUT_SECS), max_retries (0), retry_backoff_ms (200), endpoint_selection_mode (failover, load_balance, session_hash), debug_diagnostics (false). See Reliability
…/health/configchecks_enabled, alerts_enabled, check_interval_secs, failure_threshold, maintenance_until, maintenance_note. See Model health
/models/validateapi_base, upstream_model, optional api_key, model_type; always 200 with reachable, wildcard, listed, warnings
…/knowledgecollection_ids; an unknown id is 400 and changes nothing
…/statusstatus (staged, active, deprecated, retired), replacement, retire_at (RFC 3339), note (at most 500 characters), redirect. Sets the whole lifecycle; see Model lifecycle

POST /api/v1/models/health returns checked and skipped. …/health/activate returns enabled, activated and the health detail; an already-enabled model gets a manual check.

Fairshare and capacity

MethodPathWhat it does
GET/api/v1/fairshare/liveScheduler snapshot: every live gateway in shared mode (scope: cluster), else the answering one
GET/api/v1/fairshare/historySampled scheduler history
POST/api/v1/fairshare/groupsCreate a group: name, weight
GET/api/v1/fairshare/groupsList groups
PATCH/api/v1/fairshare/groups/{name}/weightSet a group's weight
GET/api/v1/capacityThe global ceiling, max_in_flight
PUT/api/v1/capacityChange the global ceiling on this replica until restart
GET/api/v1/capacity/discoveryDiscovery settings and every discovered model's state
GET/api/v1/capacity/servicesServices the kubernetes source can see

Task pages: Fairshare engine, Pool sizes.

mode, in /fairshare/live, /stats and /capacity/discovery, is how the answering replica enforces limits:

modeMeaningLimits reported
sharedCluster-wide slots in Redis, more than one replica liveConfigured values
splitShared slots off; each replica enforces ceil(configured / replicas)The replica's share
fallbackShared slots on but Redis unavailable; the split appliesThe replica's share
localOne live replica, or both settings offConfigured values

cluster_in_flight is the count across every replica in shared mode and null otherwise; every other count is the answering replica's own. See Multiple gateway replicas.

/fairshare/history takes since_ms (default: start of retention) and model (absent sums all pools). It returns interval_ms (2000), retention_ms (OBLETH_FAIRSHARE_HISTORY_SECS), oldest_ts_ms, and points of ts_ms, in_flight, queued, groups. /capacity/services takes ?model= (name or id) to add default_service and default_match; an unknown model is 404, and the listing is cached for 15 s.

Response fields: fairshare live and capacity discovery

GET /api/v1/fairshare/live: algorithm; max_in_flight and configured_max_in_flight (the pools of enabled models with servers summed, enforced and configured); models_with_servers, how many models those totals add up, and models_without_servers, the enabled models left out because they have no api_base, no enabled endpoint, or a discovered backend with no ready replica; hard_ceiling and configured_hard_ceiling; default_model_max_in_flight; replicas; mode; shared_slots; replica_aware; cluster_in_flight; global_in_flight, global_queued, global_borrowed; groups, tenants, keys aggregated across pools; model_in_flight and model_queued maps; and pools, one per model with model, no_servers, cap, configured_cap, in_flight, cluster_in_flight, queued, borrowed, held (slots this gateway holds for sessions' next steps, counted in in_flight; 0 in shared mode, where they are held in Redis) and its group, tenant and key rows. scope says whose counts these are: cluster (every live gateway, merged, with replicas_reporting and state_age_ms) or replica (the answering gateway alone, with scope_reason when shared mode could not read the others). replica_in_flight and replica_queued, top level and per pool, are always the answering gateway's own. Rows carry weight, in_flight, queued, served_tokens, share_score (served tokens over weight, which the scheduler minimizes), weight_share and expected_slots; groups add slot_cap and borrowed, tenants and keys max_in_flight.

GET /api/v1/capacity/discovery: enabled, interval_secs, namespaces, default_service, replicas, mode, and models, each with model_id, model_name, enabled, static_max_in_flight, enforced_max_in_flight, cluster_in_flight, in_flight, and status: source, namespaces, namespace, service, ready_replicas, per_replica_max_in_flight (null when endpoints differ), per_replica_source (configured, endpoint, or both), replica_capacity, headroom, derived_max_in_flight, effective_max_in_flight, state (discovered, stale, fallback), last_refresh, last_success, reason.

GET /api/v1/capacity/services: services (service, namespace, ready), reason when empty or incomplete, errors per namespace, default_service, default_match.

Settings & alerting

Settings live in Postgres; the data plane picks up a change within 15 s.

MethodPathWhat it does
GET / PUT/api/v1/settings/alertsAlert channels
POST/api/v1/settings/alerts/testSend a test alert on each channel
GET / PUT/api/v1/settings/auto-routerauto routing and classifier
POST/api/v1/router/simulateDry-run the router for a prompt
GET/api/v1/router/readinessLint the routing configuration
GET / PUT/api/v1/settings/boonsGlobal boon switches and settings
GET / PUT/api/v1/settings/knowledgeRetrieval and indexing
GET / PUT/api/v1/settings/energyEnergy accounting
POST/api/v1/settings/energy/testRun the power queries once, saving nothing
GET/api/v1/settings/compressorProbe the compression sidecar
GET / PUT/api/v1/settings/charoPlayground assistant; PUT replaces the whole object
GET / PUT/api/v1/settings/usage-retentionRaw usage retention in days

Every field in the table below is optional on PUT.

SectionFieldDefaultNotes
Alertsslack_webhook_urlnoneWrite-only (slack_webhook_set); clear_slack_webhook: true removes it
Alertsmin_interval_secs300Quiet period
Alertsemailnonesmtp_host, smtp_port (587), username, smtp_password, from_address, recipients, starttls (true); omitting it turns email off
Alertsemail.smtp_passwordnoneWrite-only (password_set); clear_smtp_password: true removes it
Auto routerclassifier_enabledfalseAsk a small model for intent tags
Auto routerclassifier_modelnull"" clears
Auto routerclassifier_timeout_ms250
Auto routercapacity_weight, cost_weight, tag_weight0.6, 0.4, 0.5Each 0–1
Auto routerdefault_soft_cap8Assumed concurrency without max_in_flight
Auto routertemperature0.00–2; 0 picks the best score
Auto routerdifficulty_enabledfalseTier filter
Auto routertier_sourcehybridhybrid, derived, declared
Auto routermessages_default_modelnullServed for an unknown /v1/messages model; "" clears
Auto routerverdicts_default_modelnull (auto)Answers a /v1/verdicts request that names no model; "" clears
Boonsvision_enabled, vision_fallback_modelfalse, null
Boonsvision_describe_prompt, vision_max_images, vision_timeout_msbuilt-in, 6, 30000
Boonsstructured_output_enabled, structured_output_fixer_modelfalse, null"" repairs with the request's model
Boonsstructured_output_max_repair_attempts, structured_output_timeout_ms1, 30000Attempts at most 3
Boonstool_loop_enabled, tool_loop_max_turnsfalse, 4Turns at most 8
Boonstool_loop_tool_timeout_ms, tool_loop_deadline_secs30000, 300Deadline 1–3600
Boonstool_loop_nudgebuilt-in"" restores the default
Boonscompression_enabled, compression_min_tokensfalse, 128
Boonscompression_max_segments, compression_max_lossy_segments64, 4Per request
Boonscompression_original_ttl_secs3600Redis TTL of stashed originals
Boonscompression_code_compaction, compression_dedup, compression_compact_logs, compression_allow_lossyfalseGlobal defaults a tenant policy overrides
Boonscompression_neural_keep_ratio0.5Above 0, at most 1
Boonsimage_generation_enabled, image_generation_modelfalse, nullAn image model
Boonsimage_generation_allowed_sizes["512x512", "1024x1024"]Empty restores the default
Boonsimage_generation_max_images_per_request, image_generation_timeout_ms2, 120000Images at most 4
Boonsimage_generation_tool_descriptionbuilt-in"" restores the default
Boonsspeculation_enabled, speculation_draft_model, speculation_classify_modelfalse, null, null
Boonsspeculation_verify_modelnullStored but unused
Boonsspeculation_agree_min, speculation_lp_min0.5, -1.0Ship floors
Boonsspeculation_abort_agree, speculation_abort_lp0.45, -1.6Abort floors
Boonsspeculation_first_chunk_tokens, speculation_chunk_tokens, speculation_decide_by_tokens, speculation_max_draft_tokens80, 250, 450, 2048
Boonsspeculation_pace_ms, speculation_timeout_ms9, 45000
Boonsspeculation_draft_chat_template_kwargsnull{} clears
Boonsspeculation_category_gates[][{tag, speculate, agree_min, lp_min}]
Boonsspeculation_unlisted_categories_speculatetrue
Boonsspeculation_verify_url_template""With {upstream} and {model}
Boonsweb_search_enabled, web_search_toolfalse, nullA search model; "" clears it
Boonsweb_search_max_results, web_search_max_searches_per_request, web_search_timeout_ms5, 3, 15000Results at most 10, searches at most 8
Boonsweb_search_tool_descriptionbuilt-in"" restores the default
KnowledgeenabledfalseRetrieval on or off
Knowledgetop_k, min_score, max_context_tokens, query_turns5, 0.35, 1500, 2
Knowledgeembed_timeout_ms, query_cache_ttl_s1500, 600
Knowledgemax_upload_bytes10485760At most 50 MiB
Knowledgemax_chunks_per_collection, index_batch_size, index_timeout_ms, index_stale_after_secs100000, 32, 30000, 1800
Knowledgedebug_snapshotfalseRecord retrieved text in spans
Energyenabledfalse
Energyprometheus_url, model_power_query, power_queryunsetWhere power is read, per model and per node
Energymodel_power_labelmodelThe label naming the model in model_power_query
Energymodel_requests_queryunsetRequests in progress per model on its servers, from every client
Energypoll_interval_secs, energy_cost_per_kwh, carbon_g_per_kwh, pue60, 0.1, 400, 1.0
Assistantenabled, brain_model, tools_enabledtrue, null, {}
Assistantbench_max_concurrency, bench_max_duration_s, bench_max_requests40, 120, 500
RetentiondaysOBLETH_USAGE_RETENTION_DAYS1–36500; GET adds configured

Task pages: Alerting, Auto model routing, Boons, Speculation, Knowledge base, Energy accounting, the Playground assistant.

GET /api/v1/settings/auto-router also returns available_tags. /router/simulate takes prompt or messages, and optionally max_tokens, tenant_id, effort, needs_function_calling, needs_tool_choice, needs_response_schema, weight overrides, busyness, uniform and classify; it returns the scored candidates and rejections without sending traffic. /router/readiness returns findings (severity, code, title, detail, models), pool_size, classifier_active, difficulty_enabled. /settings/energy/test takes prometheus_url and any of power_query, model_power_query, model_power_label and model_requests_query, and returns cluster_watts and node_count, plus models (total_watts, series, matched, unmatched_series, requests_in_progress) when a per-model query is given. /settings/compressor returns configured, url, reachable, model, revision, error.

Slurm provisioner

MethodPathWhat it does
GET / PUT/api/v1/settings/slurmSlurm connection and provisioner status
POST/api/v1/settings/slurm/testCheck JWT expiry and slurmrestd reachability
GET/api/v1/settings/slurm/resolvedSettings with the decrypted JWT, for the provisioner
GET/api/v1/slurm/resourcesPartitions with their allowed and denied accounts, nodes with state and allocation, accounts, QoS and associations; empty when Slurm is off
GET/api/v1/deployments/launchesLaunch history of Slurm replicas, newest first
GET/api/v1/managedAll launch specs
GET/api/v1/models/{id}/managedOne model's spec, or null
PUT/api/v1/models/{id}/managedCreate or replace the spec
DELETE/api/v1/models/{id}/managedRemove the spec; replicas drain
PATCH/api/v1/models/{id}/managed/provision-errorSet or clear ({"error": null}) the last submit error
GET/api/v1/replicasReplicas across all models
PATCH/api/v1/replicas/{id}Update state, message, nodes, endpoint_id
DELETE/api/v1/replicas/{id}Delete a replica row
POST/api/v1/replicas/{id}/restartCancel and resubmit the job
GET/api/v1/models/{id}/replicasOne model's replicas
POST/api/v1/models/{id}/replicasRegister a replica: slurm_job_id, port_base
POST/api/v1/models/{id}/replicas/clear-lostDelete the model's lost rows
GET/api/v1/recipesList saved recipes
POST/api/v1/recipesCreate: name, body, author
PUT/api/v1/recipes/{id}Update a recipe
DELETE/api/v1/recipes/{id}Delete a recipe

Task page: Slurm provisioning. Replica state is pending, starting, healthy, draining or lost.

PUT /api/v1/settings/slurm takes enabled, slurmrestd_url, slurmrestd_api_version (default v0.0.40), slurm_user, slurm_jwt (omit or "" keeps it), node_aliases ([{host, ip}], the full list), cluster_defaults (cache_dir, images_dir, log_dir, setup and an images map of engine to image; omit to keep) and hf_token (omit or null keeps it, "" clears it). GET returns jwt_set, jwt_last4, cluster_defaults, hf_token_set and hf_token_last4, plus the provisioner's provisioner_running, provisioner_last_seen_secs, version, git SHA, build time, provisioner_tick_status (ok, idle, error), provisioner_tick_detail, provisioner_last_ok_secs and provisioner_held_secs. The test returns jwt (set, expired, expires_at, expires_in_secs) and ping (ok, status_code, latency_ms, error). /settings/slurm/resolved returns the JWT and the Hugging Face token in full, for the provisioner.

GET /api/v1/deployments/launches takes model_id, recipe_id and limit (50, at most 500). Each row is one replica's launch, kept after the replica is gone: a snapshot of the spec, the allocated nodes, submitted_at, started_at, healthy_at, ended_at, and end_state (Slurm's own, such as TIMEOUT or OUT_OF_MEMORY, gone, or cancelled:*) with end_reason, plus the computed queued_secs, load_secs and ran_secs.

Launch spec (PUT …/managed):

FieldDefaultNotes
partitionrequired
serving_portrequiredFirst port of the replica's window; exported as OBLETH_SERVING_PORT
enabledtruefalse drains to zero
gres, nodes"", 1
cpus_per_task, mempartition defaultmem 0 is all of each node's memory
image, preamble, launch_command""Container image, setup lines, command
script_body""Full job script; overrides the three above
log_output_dir""Folder for each job's <job name>-<job id>.out and .err; empty is the job's working directory
health_path/health
target_replicas, min_replicas2, 1
max_job_failures0Stop after this many consecutive lost replicas; 0 is unlimited
account, qos, time_limit, constraints, excludeunsetSlurm options
launcher_specunsetFree-form metadata

Knowledge, MCP, audit, and backup

MethodPathWhat it does
POST/api/v1/knowledge/collectionsCreate: name, description, embedding_model
GET/api/v1/knowledge/collectionsList collections
GET/api/v1/knowledge/collections/{id}Get a collection
PUT/api/v1/knowledge/collections/{id}Update name, description, embedder, chunking
DELETE/api/v1/knowledge/collections/{id}Delete a collection and its documents
GET/api/v1/knowledge/collections/{id}/documentsList documents
POST/api/v1/knowledge/collections/{id}/documentsUpload a base64-encoded document
POST/api/v1/knowledge/collections/{id}/reindexRe-index every document
POST/api/v1/knowledge/collections/{id}/searchRetrieval preview
DELETE/api/v1/knowledge/documents/{id}Delete a document
POST/api/v1/knowledge/documents/{id}/reindexRe-index one document
POST/api/v1/mcp-serversRegister: name, upstream_url, optional auth_header
GET/api/v1/mcp-serversList servers
GET/api/v1/mcp-servers/{id}Get a server
PUT/api/v1/mcp-servers/{id}Update URL, key, enabled, or rename
DELETE/api/v1/mcp-servers/{id}Delete; removed from every model's tool_servers
GET/api/v1/auditAudit rows, newest first, filtered
GET/api/v1/backup/exportExport configuration as JSON
POST/api/v1/backup/restoreRestore a backup; body up to 64 MiB

Knowledge

PUT also takes chunk_tokens (400) and chunk_overlap_tokens (50, less than chunk_tokens). A collection reports indexed_embedding_model, embedding_dim, needs_reindex, chunk_count, estimated_bytes. Uploads take title, filename and content_base64 for a UTF-8 .md, .txt or .csv file within max_upload_bytes; a document's status goes pending, indexing, ready or failed. Search takes query and top_k and returns hits with score, text and would_inject; it is 400 until the collection is indexed. See Knowledge base.

MCP servers

A name is 1–64 letters, digits, ., _ or -, starting with a letter or digit. PUT requires upstream_url and takes auth_header (omit or "" keeps it), clear_auth: true to remove it, enabled, and name (a rename carries into every model's grant). Responses show auth_header_set. See MCP gateway.

Audit

Rows have id, ts, actor, action, entity_type, entity_id, detail. See Audit log.

Query paramDefaultNotes
limit1001–1000
actor, entity_type, entity_idunsetExact match
actionunsetOne action or a comma-separated list
since, untilunsetRFC 3339; since inclusive, until exclusive
qunsetFree text over actor, action, entity id and detail
before_idunsetPage back from this row id

Backup

A backup holds fairshare groups, tenants, keys (hashes only), models, endpoints, MCP servers and every settings row, not knowledge collections. Secrets are carried as stored; restore refuses a backup whose key_check does not match the target's OBLETH_ENCRYPTION_KEY, warns on an API-key pepper mismatch, and returns inserted and updated counts plus warnings. See Backup and restore.