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-IDon these requests. With it, the request is treated as a dashboard user and returns403. - For the keys you can send, see Settings You Can Change.
Read Settings
/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
Migrationgroup. Do not change them.
Change Settings
/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 ortruewithout quotes returns400. - 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
400and 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_GPUstill overridesFeatures.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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
24
Per-Hour Totals
Retention.HourAggregatesDays
How many days to keep per-hour totals.
7
Per-Day Totals
Retention.DayAggregatesDays
How many days to keep per-day totals. Lower it to keep fewer daily totals.
90
Backups
Back Up Databases Nightly
Backup.Enabled
Copies the local databases into the backups folder each night.
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.
2 (2 AM)
Settings page: Database Backups > Backup Time
Backups to Keep
Backup.RetentionNights
How many nightly backups are kept. Older ones are deleted.
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")