Read and Change Settings

Read SpamFoo Client's saved settings, or change them from a script. These endpoints change the same settings as the System > Settings page in the admin console, plus a few that aren't on it.

  • Both endpoints require the proxy secret, even from loopback, and have no license check. See Authenticate Requests.
  • A request with the proxy secret is treated as a system administrator. Do not send X-User-ID on these requests. With it, the request is treated as a dashboard user and returns 403.
  • For the keys you can send, see Settings You Can Change.

Read Settings

GET/admin/api/settings

Returns every setting saved in SpamFoo Client's local database, grouped by the part of the key before the first dot. A key with no dot is grouped under General.

{
    "Backup": [
        {
            "key": "Backup.HourOfDay",
            "value": "2",
            "valueType": "Int",
            "updatedUtc": "2026-10-01T09:15:42.1234567Z",
            "updatedBy": "local"
        }
    ],
    "Retention": [
        {
            "key": "Retention.DayAggregatesDays",
            "value": "30",
            "valueType": "String",
            "updatedUtc": "2026-10-07T14:02:11.7654321Z",
            "updatedBy": "local"
        }
    ]
}
Field Type Description
key string The setting's key, such as Queue.MaxConcurrency.
value string The saved value. Numbers and true or false values are returned as text.
valueType string String, Int, Bool, or Json. Values saved through PUT are stored as String, whatever they hold.
updatedUtc string When the value was last saved, in UTC.
updatedBy string Who saved it. Changes from the Settings page and this API show local.
  • Missing keys: a setting that has never been saved isn't listed, and SpamFoo Client uses its default. Some defaults are saved when SpamFoo Client first starts, so those are listed.
  • Internal keys: the response can include keys SpamFoo Client manages itself, such as the Migration group. Do not change them.

Change Settings

PUT/admin/api/settings

Saves one or more settings. Send a JSON object whose names are setting keys and whose values are strings. The request needs Content-Type: application/json.

{
    "Retention.DayAggregatesDays": "30",
    "Backup.Enabled": "true"
}
  • Send every value as a string, such as "30" or "true". A JSON number or true without quotes returns 400.
  • Keys you leave out don't change. You only need to send the settings you're changing.
  • All or nothing: if any value fails a check, the request returns 400 and nothing is saved.
  • Few values are checked. SpamFoo Client checks only the values listed under Errors. Other values are saved as sent, so check the allowed values in Settings You Can Change first.
  • Key names aren't checked. A misspelled key is saved and then ignored. Read the settings back to confirm a change.
  • When changes apply: saved values are used right away, with no restart. They win over environment variables and command-line options, except that SPAMFOO_GPU still overrides Features.GpuAcceleration.

Change Response

A successful request returns 200 with the number of keys saved.

{
    "updated": 2
}

Settings You Can Change

Send these keys to PUT /admin/api/settings. When a setting is also on System > Settings in the admin console, its Settings page line shows the card and field where it appears.

Scan Queue

These settings control where messages wait to be scanned. Mail being delivered waits in the spool queue and gets first claim on the scanning slots. Requests to Classify Without Spam Checks wait in the background queue.

Max Concurrency

Queue.MaxConcurrency

How many messages are scanned at once, shared by both queues. Each message being scanned can keep one processor core fully busy. A higher value lets a busy server keep up, but uses more memory and processor time. On servers with few processor cores, 1 can work better.

Type: Whole number, 1 to 32 Default: 2 Settings page: Classification > Max Concurrency

Queue Timeout

Queue.TimeoutSeconds

How long a message can wait for a slot before SpamFoo Client returns an error (HTTP 503), in seconds. Both queues use it unless they have their own limit.

Type: Whole number of seconds Default: 30 Settings page: Classification > Queue Timeout

Spool Queue Timeout

Queue.SpoolTimeoutSeconds

A separate wait limit for the spool queue, in seconds. When it isn't set, the spool queue uses Queue.TimeoutSeconds.

Type: Whole number of seconds

Background Queue Slots

Queue.BackgroundMaxConcurrency

The most slots the background queue can use. It can never take every slot, so mail being delivered always has room.

Type: Whole number, at least 1 Default: one less than Queue.MaxConcurrency, at least 1

Background Queue Timeout

Queue.BackgroundTimeoutSeconds

A separate wait limit for the background queue, in seconds. When it isn't set, the background queue uses Queue.TimeoutSeconds if it has been saved, or 120 seconds.

Type: Whole number of seconds

Spam Filtering

Spam Sensitivity

Spam.Sensitivity

How readily SpamFoo Client marks a message as spam. Low (Conservative on the Settings page) marks fewer legitimate messages as spam but lets more spam through. High (Aggressive) catches the most spam but may mark more legitimate messages. Medium (Recommended) suits most servers. The setting also decides which spam levels count as spam; see Spam Levels. A change applies to the next message without a restart.

Type: Low, Medium or High (any letter case) Default: Medium Settings page: Spam Filtering > Spam Sensitivity

Model Processing

Enable Speedup Optimizations

Features.OnnxOptimizations

Lets SpamFoo Client use more processor and memory to scan each message faster. Turn it on only if the server is dedicated to SpamFoo Client or has a lot of unused processor and memory. See Speedup Optimizations.

Type: true or false Default: false Settings page: Classification > Enable Speedup Optimizations

GPU Acceleration

Features.GpuAcceleration

Runs the text model on an NVIDIA GPU. When the SPAMFOO_GPU environment variable is set, it overrides this setting. See Turn On GPU Acceleration.

Type: true or false Default: false Settings page: Hardware > GPU Acceleration

Dashboard Display

Default Time Range

UI.DefaultTimeRange

The time range dashboard pages show when they open.

Type: 1h, 6h, 24h, 7d, or 30d Default: 24h Settings page: Display > Default Time Range

Scan History and Message Content

Store Scan History

Retention.RawEventsEnabled

Keeps a record of each scanned message. Turning it off deletes the stored records at the next daily cleanup.

Type: true or false Default: true Settings page: Scan History > Store Scan History

Retention Period

Retention.RawEventsDays

How many days scan records are kept. Log files are deleted after the same number of days.

Type: Whole number of days, 1 to 365 Default: 7 Settings page: Scan History > Retention Period

Store Message Content

Retention.MessageContentEnabled

Keeps the subject and body of scanned messages, with known sensitive patterns removed, so they can be read on the Messages page.

Type: true or false Default: true Settings page: Message Content > Store Message Content

Maximum Stored Messages

Retention.MessageContentMaxMessages

How many messages keep their content. The oldest content is cleared first.

Type: Whole number, 1 to 100,000 Default: 10000 Settings page: Message Content > Maximum Stored Messages

Share Correction Content

Training.ShareCorrectionContent

Includes the stored message content when someone reports a wrong result from the SpamFoo dashboard. Needs Retention.MessageContentEnabled. When it's on, users who report a message see a notice that a sanitized copy is sent to SpamFoo. Make sure sharing message content fits your organization's privacy policy.

Type: true or false Default: false Settings page: Message Content > Share Correction Content

Mail Totals

SpamFoo Client keeps per-minute, per-hour, and per-day mail totals for the dashboard charts. Only this API can change how long they are kept.

Per-Minute Totals

Retention.MinuteAggregatesHours

How many hours to keep per-minute totals.

Type: Whole number of hours Default: 24

Per-Hour Totals

Retention.HourAggregatesDays

How many days to keep per-hour totals.

Type: Whole number of days Default: 7

Per-Day Totals

Retention.DayAggregatesDays

How many days to keep per-day totals. Lower it to keep fewer daily totals.

Type: Whole number of days Default: 90

Backups

Back Up Databases Nightly

Backup.Enabled

Copies the local databases into the backups folder each night.

Type: true or false Default: true Settings page: Database Backups > Back Up Databases Nightly

Backup Time

Backup.HourOfDay

The hour the nightly backup runs, in server time.

Type: Whole number, 0 to 23 Default: 2 (2 AM) Settings page: Database Backups > Backup Time

Backups to Keep

Backup.RetentionNights

How many nightly backups are kept. Older ones are deleted.

Type: Whole number, 1 to 365 Default: 7 Settings page: Database Backups > Backups to Keep

Errors

Status Body Cause
400 {"error": "The following settings keys are reserved and cannot be modified through this endpoint: ..."} PUT: a key starts with License., Cache., or Server., or is another key SpamFoo Client manages itself.
400 {"error": "Retention.MessageContentEnabled must be true or false."} PUT: the value wasn't true or false.
400 {"error": "Retention.MessageContentMaxMessages must be between 1 and 100000."} PUT: the value wasn't a whole number in that range.
400 {"error": "Spam.Sensitivity must be Low, Medium or High."} PUT: the value wasn't one of those three words.
400 {"error": "Backup.HourOfDay must be between 0 and 23."} PUT: the value wasn't a whole number in that range.
400 {"error": "Backup.RetentionNights must be between 1 and 365."} PUT: the value wasn't a whole number in that range.
400 Empty PUT: the body was empty, wasn't valid JSON, or had a value that wasn't a string.
401 Empty The proxy secret was missing or wrong.
403 Empty The request included X-User-ID, so it was treated as a dashboard user without system administrator access.
415 Empty PUT: the request did not use Content-Type: application/json.

Example

This example keeps 30 days of per-day totals, then reads the settings back to confirm the change.

curl -X PUT http://localhost:16253/admin/api/settings \
    -H "Content-Type: application/json" \
    -H "X-SpamFoo-Proxy-Auth: $SPAMFOO_PROXY_SECRET" \
    -d '{"Retention.DayAggregatesDays": "30"}'

curl http://localhost:16253/admin/api/settings \
    -H "X-SpamFoo-Proxy-Auth: $SPAMFOO_PROXY_SECRET"
using System.Net.Http.Json;
using System.Text.Json;

var secret = Environment.GetEnvironmentVariable("SPAMFOO_PROXY_SECRET")
    ?? throw new InvalidOperationException("Set SPAMFOO_PROXY_SECRET.");

using var http = new HttpClient { BaseAddress = new Uri("http://localhost:16253") };
http.DefaultRequestHeaders.Add("X-SpamFoo-Proxy-Auth", secret);

var changes = new Dictionary<string, string> { ["Retention.DayAggregatesDays"] = "30" };
using var response = await http.PutAsJsonAsync("/admin/api/settings", changes);
response.EnsureSuccessStatusCode();

var settings = await http.GetFromJsonAsync<Dictionary<string, JsonElement[]>>("/admin/api/settings");
var saved = settings!["Retention"]
    .First(s => s.GetProperty("key").GetString() == "Retention.DayAggregatesDays");
Console.WriteLine($"Per-day totals kept: {saved.GetProperty("value").GetString()} days");
import os

import requests

SPAMFOO_URL = "http://localhost:16253"
HEADERS = {"X-SpamFoo-Proxy-Auth": os.environ["SPAMFOO_PROXY_SECRET"]}

response = requests.put(
    f"{SPAMFOO_URL}/admin/api/settings",
    json={"Retention.DayAggregatesDays": "30"},
    headers=HEADERS,
    timeout=30,
)
response.raise_for_status()

response = requests.get(f"{SPAMFOO_URL}/admin/api/settings", headers=HEADERS, timeout=30)
response.raise_for_status()
saved = next(
    s for s in response.json()["Retention"] if s["key"] == "Retention.DayAggregatesDays"
)
print(f"Per-day totals kept: {saved['value']} days")