Skip to content
Sendtier Docs

Data retention

How long Sendtier keeps messages, events, webhook deliveries, logs, idempotency keys, and a deleted account.

Retention periods below are the ones in this repository. A live account uses the same rules unless an operator changes SENDTIER_RETENTION_DAYS. The operator can set a longer or a shorter window. Configuration rejects a value below the minimum.

Messages, events, and webhook deliveries

Daily UTC partitions cover emails, email_events, webhook_deliveries, and webhook_delivery_attempts. Cron prepares seven days ahead at startup and every hour. It then drops partitions older than SENDTIER_RETENTION_DAYS. The default is 30 days. The minimum is 4 days, one day more than the 72-hour scheduling horizon. The cutoff UTC day is kept. The drop is the same for every tenant. It is not a delete for one account.

List and detail reads stay inside that window. Webhook delivery rows and their attempts use the same window, including deliveries that are still pending when the day expires.

Idempotency keys

An Idempotency-Key is kept until its created_at is older than 24 hours. Cron deletes those rows at startup and every hour. A replay after that delete is a new request.

Account deletion

A dashboard owner can schedule deletion of the selected organization. The API returns purge_at 720 hours after the first request. That is 30 days of 24 hours. A repeat request keeps the original time. The owner can restore the organization strictly before purge_at. API keys revoked at the request stay revoked. After the window, cron deletes that tenant's rows and its unused provider identities. A failed purge retries, so 720 hours is the earliest purge time, not a completion guarantee. Export and deletion need the dashboard owner. An API key cannot call them.

Logs

CloudWatch log groups for each service role, named /ecs/<stack>/<role>, keep logs for 30 days. The database-url log group keeps logs for 30 days. Those are the log groups this repository sets.

What this page does not expire

Suppression rows stay until the API deletes them. A global suppression can remain after the tenant row is removed. The raw-MIME bucket lifecycle is 30 days. The current binary does not write that bucket.

Sources: partition maintenance (internal/cron/partitions.go), retention setting (internal/config/config.go), idempotency cleanup (internal/store/queries/system/idempotency.sql), deletion window (internal/domain/account.go), CloudWatch log groups (infra/terraform/observability.tf), ADR-0017 (docs/adr/0017-partitioning-and-retention.md), ADR-0024 (docs/adr/0024-account-export-and-deletion.md).

On this page