Instance settings override environment variables at runtime: things like app name, ToS URL, privacy policy URL, and logo. Settings stored here take precedence over their env var equivalents. All endpoints require the settings:manage permission.
const TOKEN = "hv_..."; // your API keyconst headers = { Authorization: `Bearer ${TOKEN}` };const TOKEN = "hv_..."; // your API keyconst headers = { Authorization: `Bearer ${TOKEN}` };let token = "hv_..."; // your API keytoken := "hv_..." // your API key# All examples assume $TOKEN is an API key (hv_...)AUTH="Authorization: Bearer $TOKEN"List settings
Section titled “List settings”GET /admin/settingsconst response = await fetch("http://127.0.0.1:3000/admin/settings", { headers,});const data = await response.json();const response = await fetch("http://127.0.0.1:3000/admin/settings", { headers,});const data = await response.json();let response = client .get("http://127.0.0.1:3000/admin/settings") .bearer_auth(token) .send() .await?;let data: serde_json::Value = response.json().await?;req, _ := http.NewRequest("GET", "http://127.0.0.1:3000/admin/settings", nil)req.Header.Set("Authorization", "Bearer "+token)resp, err := http.DefaultClient.Do(req)curl http://127.0.0.1:3000/admin/settings -H "$AUTH"Response: 200 OK
[ { "key": "app_name", "value": "My HappyView", "source": "database" }]Stored values come first, sorted by key. They are followed by values from the environment or happyview.toml for keys with no stored value. source is database, env or project.
Known settings
Section titled “Known settings”| Key | Env var | Default | Description |
|---|---|---|---|
app_ | APP_NAME | --- | Application name shown in sidebar and OAuth consent screen |
client_ | CLIENT_URI | --- | Public URL for this instance, linked from OAuth consent screen |
logo_ | LOGO_URI | --- | External URL to a logo image |
tos_ | TOS_URI | --- | Link to terms of service |
policy_ | POLICY_URI | --- | Link to privacy policy |
backfill_ | BACKFILL_CONCURRENT_PDS | 10 | How many PDS servers to fetch from simultaneously during backfill |
backfill_ | BACKFILL_CONCURRENT_DIDS_PER_PDS | 3 | How many accounts to fetch concurrently from each PDS |
backfill_ | BACKFILL_CONCURRENT_RESOLUTION | 100 | How many DID document lookups to run in parallel during PDS resolution |
backfill_ | BACKFILL_RETENTION_DAYS | 28 | Days to keep per-account detail from completed backfill jobs. 0 = keep indefinitely |
verbose_ | VERBOSE_EVENT_LOGGING | false | Log every record index, record skip, and successful script run (record, label, and XRPC) to the event log. High write volume, so recommended only for debugging |
feature.spaces_ | FEATURE_SPACES_ENABLED | --- | Enables the experimental Permissioned Spaces API. When "true", space endpoints are available. When absent or any other value, space endpoints return 404 FeatureDisabled |
event_ | EVENT_LOG_RETENTION_DAYS | 30 | Days to keep event log entries |
script_ | SCRIPT_INSTRUCTION_LIMIT | 1000000 | Instruction budget for a script run. PUT refuses a value outside 1000 to 1000000000 with 400 Bad Request |
script_ | SCRIPT_WALL_CLOCK_SECONDS | 10 | Wall-clock limit for a request’s script run, in seconds. PUT refuses a value outside 1 to 300 with 400 Bad Request |
script_ | SCRIPT_METRICS_ENABLED | true | Record per-script run metrics for /admin/metrics. PUT refuses anything but "true" or "false" with 400 Bad Request |
Upsert a setting
Section titled “Upsert a setting”PUT /admin/settings/{key}const response = await fetch("http://127.0.0.1:3000/admin/settings/app_name", { method: "PUT", headers: { ...headers, "Content-Type": "application/json", }, body: JSON.stringify({ value: "My HappyView" }),});const response = await fetch("http://127.0.0.1:3000/admin/settings/app_name", { method: "PUT", headers: { ...headers, "Content-Type": "application/json", }, body: JSON.stringify({ value: "My HappyView" }),});let response = client .put("http://127.0.0.1:3000/admin/settings/app_name") .bearer_auth(token) .json(&serde_json::json!({ "value": "My HappyView" })) .send() .await?;body := bytes.NewBufferString(`{ "value": "My HappyView" }`)req, _ := http.NewRequest("PUT", "http://127.0.0.1:3000/admin/settings/app_name", body)req.Header.Set("Authorization", "Bearer "+token)req.Header.Set("Content-Type", "application/json")resp, err := http.DefaultClient.Do(req)curl -X PUT http://127.0.0.1:3000/admin/settings/app_name \ -H "$AUTH" \ -H "Content-Type: application/json" \ -d '{ "value": "My HappyView" }'The body is { "value": "..." }. The value is always a string, so send "true", not true.
Response: 204 No Content. 400 Bad Request when a script limit is out of range or script_metrics_enabled isn’t "true" or "false". A telemetry.* key returns 409 Conflict where a hosting platform manages telemetry.
Delete a setting
Section titled “Delete a setting”DELETE /admin/settings/{key}Removes the override; the corresponding environment variable (if any) takes effect again. Returns 404 Not Found if no value is stored for that key.
Database info
Section titled “Database info”GET /admin/settings/db-infoReturns database backend, connection pool sizes, and whether a server restart is recommended to resize the backfill pool for current concurrency settings.
const response = await fetch("http://127.0.0.1:3000/admin/settings/db-info", { headers,});const data = await response.json();const response = await fetch("http://127.0.0.1:3000/admin/settings/db-info", { headers,});const data = await response.json();let client = reqwest::Client::new();let response = client .get("http://127.0.0.1:3000/admin/settings/db-info") .bearer_auth(token) .send() .await?;let data: serde_json::Value = response.json().await?;req, _ := http.NewRequest("GET", "http://127.0.0.1:3000/admin/settings/db-info", nil)req.Header.Set("Authorization", "Bearer "+token)resp, err := http.DefaultClient.Do(req)curl http://127.0.0.1:3000/admin/settings/db-info -H "$AUTH"Response: 200 OK
{ "backend": "sqlite", "server_max_connections": null, "main_pool_size": 32, "backfill_pool_size": 16, "restart_recommended": false}| Field | Type | Description |
|---|---|---|
backend | string | "sqlite" or "postgres" |
server_ | number | null | Postgres max_connections setting. null for SQLite |
main_ | number | Current main connection pool size |
backfill_ | number | Current backfill connection pool size |
restart_ | boolean | true if concurrency settings have changed and a restart would resize the pool |
Upload / delete logo
Section titled “Upload / delete logo”PUT /admin/settings/logoDELETE /admin/settings/logoPUT takes a multipart/form-data body whose first part is the image, and stores it as the instance logo (served via the public dashboard). The part’s content type must be image/* and it must be at most 5 MB, otherwise the request is refused with 400 Bad Request. DELETE removes the stored logo.
Response: 204 No Content for both.
© HappyProto

