API Reference
API Reference
GitHub
Admin Panel

Platform Metrics

Platform-wide metrics and analytics

What an administrator can watch across the whole installation, and where the line falls between platform-wide and per-project figures.

Where platform-wide numbers come from

There is no cross-project aggregation API. Installation-wide observability is the Prometheus endpoint :

GET /metrics

It binds metrics.addr — loopback by default, its own listener — is off unless metrics.enabled is set, and can be gated with a bearer token (metrics.token). It carries counters for accepted and finalized emails, inbound mail and webhook deliveries, plus a scrape-time gauge of emails by status. Anything you want charted across tenants is built there, in your own monitoring stack, rather than in this console.

Per-project analytics

The delivery figures are scoped to the active project, resolved from the usual X-Mailyard-Project-Id header, and need analytics:read:

GET /api/v1/dashboard/stats
GET /api/v1/analytics?from=2026-01-01&to=2026-01-31

from and to are plain YYYY-MM-DD dates. The window defaults to the trailing 30 days and may not exceed 366. daily_counts fills days with no traffic, so a quiet week cannot silently rescale a chart’s axis. Both routes exist on the machine API too (/api/v1/...) with an API key holding the relevant :read permissions. Details in Email Analytics .

An administrator holds owner-equivalent rights in every project, so reading another project’s figures means switching to it rather than calling a different endpoint.

Real-Time Monitoring

Live activity stream

The console updates its notification badge from a server-sent events feed rather than polling. It is a browser feature carried on the session cookie, so there is nothing to call from a script - for machine-side notification of the same events, register a webhook .

Stream statistics

The console reports the live subscriber count and how many events were dropped because a client stopped reading. A dropped count that climbs steadily means some browser is not keeping up.

{
    "subscribers": 3,
    "projects": 2,
    "dropped": 0
}

Notifications

In-app alerts, addressed to a project rather than a person: what they report is a fact about the project, and read state is shared, so one member clearing an alert clears it for everyone.

GET    /api/v1/notifications
GET    /api/v1/notifications/unread
POST   /api/v1/notifications/{id}/read
POST   /api/v1/notifications/read-all
DELETE /api/v1/notifications/{id}

Any project member. ?unread=true narrows the list. The unread count is a separate endpoint because the console polls it far more often than it opens the list.

Bounce rate alerts

A scheduled job (bounce-alert, every 15 minutes) measures each project’s bounce rate over the last hour and raises a warning when it crosses the threshold.

SettingDefaultMeaning
bounce_alert_percent10Rate that raises an alert. 0 turns it off.
bounce_alert_min_volume20Messages that must finish in the hour before the rate is judged. Two bounces out of three sends is 66% and means nothing.
notification_retention_days30How long read notifications are kept. Unread ones are never purged by age.

Only terminal outcomes count toward the rate - queued and processing messages have not decided yet, and including them would dilute the number and hide a real problem behind a backlog.

The alert is deduped per hour, so a rate that stays high produces one notification an hour rather than one every fifteen minutes. Marking it read does not make it fire again.

Why a job and not the send path

A rate is a property of a window, so it cannot be evaluated at the moment one message fails. Hooking the failure path would also make the alert fire hardest exactly when the system is already struggling.