# Limristem eMail API Reference

Base URL:
- public: `https://<mail-host>/`
- internal: `http://127.0.0.1:8080/`

Authentication:
- HTTP Basic Auth over HTTPS
- username from `LIMRISTEM_MAIL_API_ADMIN_USER`
- password verified against `LIMRISTEM_MAIL_API_ADMIN_PASS_HASH` (or plaintext only if explicitly configured)
- brute-force protection through in-process rate limiting

## Domains

- `GET /domains` — list domains
- `POST /domains` — create domain
- `GET /domains/{id}` — domain details
- `PATCH /domains/{id}` — update `is_active`, `max_users`, `dmarc_policy`
- `POST /domains/{id}/dkim` — rotate or generate DKIM key
- `GET /domains/{id}/dns` — suggested DNS entries
- `POST /domains/{id}/dns/provider` — configure the DNS provider for the domain (`cloudflare` is currently supported)
- `POST /domains/{id}/dns/sync-dkim` — create or update the DKIM TXT record through the configured DNS provider

Example:

```json
{
  "name": "example.com",
  "is_active": true,
  "max_users": 50,
  "dmarc_policy": "quarantine",
  "generate_dkim": true,
  "dkim_selector": "default"
}
```

`GET /domains/{id}/dns` now returns safer hints:
- MX pointing to `LIMRISTEM_MAIL_HOSTNAME`
- SPF without self-recursive `include:<same-domain>`
- DMARC with stricter alignment hints
- DKIM TXT suggestion
- PTR reminder
- when the domain matches `LIMRISTEM_MAIL_PRIMARY_DOMAIN`, optional `MTA-STS` / `TLS-RPT` hints too

Cloudflare provider example:

```json
{
  "dns_provider": "cloudflare",
  "dns_zone_id": "0123456789abcdef0123456789abcdef",
  "dns_api_token": "cloudflare-zone-token",
  "dns_sync_enabled": true
}
```

Use a Cloudflare API token scoped to the exact zone with DNS edit permission. The token is accepted on write, but is not returned by `DomainOut`; responses only expose `dns_has_api_token`.

## Accounts

- `GET /accounts?domain=example.com`
- `GET /accounts/{id}`
- `POST /accounts`
- `PATCH /accounts/{id}`
- `DELETE /accounts/{id}`

Example:

```json
{
  "domain": "example.com",
  "local_part": "user",
  "password": "StrongMailboxPass123",
  "quota_mb": 2048,
  "is_active": true
}
```

Notes:
- `quota_mb` is validated and now feeds Dovecot quota enforcement.
- `max_users` on the domain is enforced when creating active accounts.

## Aliases

- `GET /aliases`
- `POST /aliases`
- `PATCH /aliases/{id}`
- `DELETE /aliases/{id}`

Example:

```json
{
  "domain": "example.com",
  "source_local": "info",
  "destination": "user@example.com",
  "is_active": true
}
```

## Redirects

- `GET /redirects`
- `POST /redirects`
- `PATCH /redirects/{id}`
- `DELETE /redirects/{id}`

Example:

```json
{
  "domain": "example.com",
  "source_local": "sales",
  "target_email": "team@other.example",
  "is_active": true
}
```

Notes:
- self-redirects are rejected
- external forwarding works better with the included optional `postsrsd` integration

## Reputation

- `GET /reputation`
- `GET /reputation/lookup?entity_type=ip&entity_value=1.2.3.4`
- `POST /reputation`
- `PATCH /reputation/{id}`

Supported `entity_type` values:
- `ip`
- `domain`
- `email`
- `asn`
- `hash`

`POST /reputation` now behaves as an upsert for the same `(entity_type, entity_value)`.

## Health

- `GET /health` — public readiness summary with DB and Redis checks
- `GET /health/details` — authenticated details including hostname and runtime paths

## Admin

- `GET /admin/queue` — list the Postfix queue
- `POST /admin/queue/{queue_id}/hold`
- `POST /admin/queue/{queue_id}/release`
- `POST /admin/queue/{queue_id}/requeue`
- `DELETE /admin/queue/{queue_id}`
- `GET /admin/bans` — list active fail2ban bans, grouped by jail/service
- `POST /admin/bans`
- `DELETE /admin/bans?ip=203.0.113.5`
- `GET /admin/limits`
- `PATCH /admin/limits`
- `GET /admin/backups` — current backup config plus local runs
- `PATCH /admin/backups`
- `POST /admin/backups/run`
- `GET /admin/firewall` — current nftables firewall configuration and rule rows
- `PATCH /admin/firewall` — update `firewall-enabled`, `firewall-rules-json`, or legacy tcp/udp port keys

The optional web panel is available under `/panel/*` when `LIMRISTEM_MAIL_ENABLE_WEB_PANEL=yes`, with a dedicated login at `GET /panel/login`.

## Operational notes

- The API no longer auto-creates the SQL schema on import; provisioning is delegated to `scripts/install.sh`.
- DKIM selectors and domains are validated before key generation.
- DKIM keys are written under `LIMRISTEM_MAIL_DKIM_KEYS_DIR`.
- Per-domain DNS provider tokens are excluded from API responses and cache payloads. Store Cloudflare tokens with the least permissions required for the target zone.
- Redis cache entries expire after `LIMRISTEM_MAIL_CACHE_TTL_SECONDS` seconds to reduce stale control-plane data.
- Queue / bans / limits / backup operations call dedicated root-owned CLI helpers through a constrained sudoers rule, so the `limristem-mail.service` unit must keep privilege escalation available for those specific helper commands.

## Example curl

```bash
curl -u admin:'your-bootstrap-password' \
  -H 'Content-Type: application/json' \
  https://mail.example.com/domains \
  -d '{"name":"example.com","generate_dkim":true}'

curl -u admin:'your-bootstrap-password' \
  -H 'Content-Type: application/json' \
  https://mail.example.com/accounts \
  -d '{"domain":"example.com","local_part":"alice","password":"StrongMailboxPass123"}'

curl -u admin:'your-bootstrap-password' \
  https://mail.example.com/health/details

curl -u admin:'your-bootstrap-password' \
  -H 'Content-Type: application/json' \
  https://mail.example.com/domains/1/dns/provider \
  -d '{"dns_provider":"cloudflare","dns_zone_id":"0123456789abcdef0123456789abcdef","dns_api_token":"cloudflare-zone-token","dns_sync_enabled":true}'

curl -u admin:'your-bootstrap-password' \
  -X POST \
  https://mail.example.com/domains/1/dns/sync-dkim
```
