Reports API¶
Weekly Certificate and Secret Expiry Reports — Settings, Trigger, and Preview
Document Version: 1.0.61
Last Updated: 2026-11-09
Overview¶
The Reports API manages the weekly expiry report. Each organization has its own e-mail recipients and receives only its own organization's report: the certificates and secrets of its projects that expire within the next 60 days. The report also goes to the organization's report-enabled notification channels (Slack, Teams, webhook, Jira). Certificates without a project belong to no organization and appear in no organization's weekly report; assign them to a project to have them reported.
| Method | Endpoint | Description | Permission |
|---|---|---|---|
| GET | /api/v1/organizations/{id}/reports/settings |
Get the organization's recipients | report:read in the organization |
| PUT | /api/v1/organizations/{id}/reports/settings |
Replace the organization's recipients | report:write in the organization |
| POST | /api/v1/organizations/{id}/reports/trigger |
Send the organization's report now | report:write in the organization |
| GET | /api/v1/organizations/{id}/reports/preview |
Preview the organization's report | report:read in the organization |
| GET | /api/v1/reports/settings |
Get the instance-level recipients left from before (they receive nothing) | global report:read |
| PUT | /api/v1/reports/settings |
Change or clear the instance-level recipients | global report:write |
| POST | /api/v1/reports/trigger |
Send every organization its own report now | global report:write |
| GET | /api/v1/reports/preview |
Preview the items of all organizations and projects visible to the caller | report:read |
"In the organization" means an organization role in that organization or a global role; a project role is not enough.
Get Organization Report Settings¶
Returns the organization's weekly-report recipients.
Response 200 OK¶
Response Fields¶
| Field | Type | Description |
|---|---|---|
recipients |
array of strings | Email addresses that receive this organization's weekly report |
Update Organization Report Settings¶
Replaces the organization's full recipient list. Send an empty array to stop e-mail delivery. The change is audited as REPORT_RECIPIENTS_UPDATED (the number of recipients, not the addresses).
PUT /api/v1/organizations/{id}/reports/settings HTTP/1.1
Authorization: Bearer <token>
Content-Type: application/json
{
"recipients": [
"security@example.com",
"ops-team@example.com",
"ciso@example.com"
]
}
Request Fields¶
| Field | Type | Required | Description |
|---|---|---|---|
recipients |
array of strings | ✅ | List of email addresses to receive the report (max 10). Each address must be a valid email format. Send [] to disable email delivery. |
Response 200 OK¶
Scheduling
Every Monday at 07:00 (Europe/Prague) each organization's report is sent to its recipients and report-enabled channels. This endpoint only manages recipients.
Trigger Organization Report¶
Sends the organization's report now to its recipients and report-enabled channels, with the same content as the scheduled delivery.
No request body is required.
Response 200 OK¶
Delivery Behavior
Without recipients and report-enabled channels nothing is sent and the request still returns 200 OK. If a recipient or channel cannot be reached, the others still get the report and the request returns 500 with the failed deliveries in details.
Instance-Level Recipients¶
Before per-organization recipients there was one recipient list for the whole instance. On upgrade, an instance with a single organization moved that list to its organization. With several organizations the list is kept as instance-level recipients that receive no report, so that no organization's report reaches another organization's people. A global admin sees them with GET /api/v1/reports/settings, adds them to the right organizations, and then clears them with PUT /api/v1/reports/settings and {"recipients": []}. The System Outputs → Weekly Expiry Report tab shows them to a global admin with a Clear button.
POST /api/v1/reports/trigger (global role) sends every organization its own report, like the Monday run.
Preview Report¶
Returns the organization's report content without sending anything: what its recipients would get next. GET /api/v1/reports/preview returns the same shape for all organizations and projects visible to the caller.
Response 200 OK¶
{
"generated_at": "2026-04-26T10:00:00Z",
"total_certificates": 3,
"total_secrets": 1,
"expiring_certificates": [
{
"common_name": "api.example.com",
"expires_at": "2026-05-10T00:00:00Z",
"days_remaining": 14,
"issuer": "MazeVault Internal CA",
"serial_number": "0a:1b:2c:3d:4e:5f",
"auto_renew": true,
"project_name": "Backend Services",
"environment": "production"
},
{
"common_name": "internal.corp.example.com",
"expires_at": "2026-05-20T00:00:00Z",
"days_remaining": 24,
"issuer": "MazeVault Internal CA",
"serial_number": "ff:ee:dd:cc:bb:aa",
"auto_renew": false,
"project_name": "Internal Tools",
"environment": "staging"
}
],
"expiring_secrets": [
{
"name": "stripe-api-key",
"expires_at": "2026-05-05T00:00:00Z",
"days_remaining": 9,
"type": "api_key",
"project_name": "Payment Service",
"environment": "production"
}
]
}
Response Fields¶
| Field | Type | Description |
|---|---|---|
generated_at |
string (ISO 8601) | Timestamp when this preview was generated |
total_certificates |
integer | Number of expiring certificates included in the report |
total_secrets |
integer | Number of expiring secrets included in the report |
expiring_certificates |
array | List of certificates expiring within the lookahead window |
expiring_secrets |
array | List of secrets expiring within the lookahead window |
expiring_certificates Object¶
| Field | Type | Description |
|---|---|---|
common_name |
string | Certificate Common Name (CN) |
expires_at |
string (ISO 8601) | Certificate expiry timestamp |
days_remaining |
integer | Days until expiry at the time the preview was generated |
issuer |
string | Issuing CA name |
serial_number |
string | Certificate serial number |
auto_renew |
boolean | Whether automatic renewal is configured for this certificate |
project_name |
string | Name of the project that owns the certificate |
environment |
string | Environment scope of the certificate |
expiring_secrets Object¶
| Field | Type | Description |
|---|---|---|
name |
string | Secret key name |
expires_at |
string (ISO 8601) | Secret expiry timestamp |
days_remaining |
integer | Days until expiry at the time the preview was generated |
type |
string | Secret type (e.g., api_key, password, certificate) |
project_name |
string | Name of the project that owns the secret |
environment |
string | Environment scope of the secret |
Error Responses¶
| HTTP Status | Meaning |
|---|---|
400 Bad Request |
Invalid request body — e.g., invalid email address format or more than 10 recipients |
401 Unauthorized |
Missing or invalid bearer token |
403 Forbidden |
The caller has no report:read/report:write organization or global role in the organization (a project role is not enough), or no global role for /api/v1/reports/settings and /trigger |
404 Not Found |
The organization does not exist |