My AI agent actually did a full write up here you go:
Solved: additional Stalwart account licenses were not syncing
I fixed this on Stalwart v0.16.4 running in Docker.
Root cause
The server still had a valid signed 25-account license installed. In this release, Stalwart’s automatic renewal logic only contacts the licensing service when the current license is invalid or within roughly four days of expiration. Because the old license remained valid until 2027, purchasing more accounts did not automatically download the updated entitlement.
Also, separate 25-account keys do not stack. The server needs the newly issued signed key that contains the full 50-account allowance.
What fixed it
-
Back up the current Enterprise settings and license material.
-
Manually request the current signed license from Stalwart’s licensing API using the auto-renewal API key:
curl -fsS \
-A 'Stalwart/0.16.4' \
-H "Authorization: Bearer ${STALWART_API_KEY}" \
"https://license.stalw.art/api/license/example.com" \
-o new-license.key
Replace example.com with the domain to which the license was issued. Keep both keys private.
A normal Python HTTP client was rejected by Cloudflare with error 1010, but the request worked when sent with a Stalwart user agent.
-
Confirm the returned key is different from the installed key and contains the expected domain and total account count. In my case, the licensing API returned a vendor-signed 50-account key.
-
Apply the new license key and the auto-renewal API key through the official CLI rather than the WebUI. I used the official Docker image:
docker pull stalwartlabs/cli:latest
docker run --rm -i \
-e STALWART_URL=https://mail.example.com \
-e STALWART_USER=admin \
-e STALWART_PASSWORD \
stalwartlabs/cli:latest update Enterprise --stdin
The JSON submitted on stdin was:
{
"licenseKey": {
"@type": "Value",
"secret": ""
},
"apiKey": {
"@type": "Value",
"secret": ""
}
}
Using stdin avoids placing the license value directly in shell history. If a temporary JSON file is used, protect and delete it afterward.
-
Restart Stalwart, wait for it to become healthy, and restart any reverse proxy or network-namespace bridge that depends on the container.
-
Log out and back into the WebUI, then verify the Enterprise status, account count, and logs.
Result
The server now reports 25 accounts in use out of 50 licensed, leaving 25 available. Enterprise APIs, admin access, SMTP, and IMAP all remained healthy, and there were no license errors after restart.
The key step was manually retrieving the newly issued combined entitlement and applying it with stalwart-cli; repeatedly pasting the old key into the WebUI could never increase the limit.