Source: https://help.spamfoo.com/api/settings
Last updated: 2026-10-27

***

# 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](https://help.spamfoo.com/api#authentication).
- 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](https://help.spamfoo.com/api/settings#setting-keys).

## 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](https://help.spamfoo.com/api/settings#errors). Other values are saved as sent, so check the allowed values in [Settings You Can Change](https://help.spamfoo.com/api/settings#setting-keys) 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](https://help.spamfoo.com/api/classify-tabs) 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](https://help.spamfoo.com/api/classify#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](https://help.spamfoo.com/guides/configure#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](https://help.spamfoo.com/guides/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

```
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"
```

### C#

```
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");
```

### Python

```
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")
```
