Affinity Design
Agency Guide

Monthly Reports

Generate, review, override, and share monthly performance reports with clients

Overview

Monthly reports compile client performance data — calls, bookings, agent metrics, and more — into a structured document stored as a MonthlyReport. Reports follow a lifecycle: draft → reviewed → sent, and can be shared with clients through the portal or via a public report token.

Generating Reports

Via API

Endpoint: POST /admin/reports/monthly/generate

Body:

{
  "clientId": "client_abc",
  "intervalDays": 30
}
ParameterRequiredValuesDescription
clientIdYesAny client IDThe client to generate a report for
intervalDaysNo30 or 90Reporting window. Defaults to 30.

The generateReport utility in utils/analytics.js compiles call history, agent metrics, and a monthly summary. If a structured summary is available, it uses generateMonthlyReportSummary; otherwise it falls back to buildFallbackMonthlyReportSummary.

List All Reports

Endpoint: GET /admin/reports/monthly?clientId=xxx&period=YYYY-MM&status=draft

FilterDescription
clientIdFilter by client
periodFilter by YYYY-MM
statusFilter by draft, reviewed, or sent
intervalDaysFilter by reporting window (30 or 90)

Returns up to 100 reports sorted by generatedAt descending.

View a Single Report

Endpoint: GET /admin/reports/monthly/:id

Returns the full report with mergedMetrics (base metrics merged with overrides). If the report has no previousMetrics, the system automatically fetches the previous report for period-over-period comparison.

Report Lifecycle

Reports progress through three statuses:

StatusMeaning
draftNewly generated, pending review. Can be deleted.
reviewedReviewed by an operator. Ready to share.
sentShared with the client. A reportToken is generated for portal access.

Updating Status

Endpoint: PUT /admin/reports/monthly/:id/status

Body:

{
  "status": "sent"
}

When a report is moved to sent:

  • emailSentAt is set (if not already set)
  • A reportToken is generated (cryptographically random, 48 hex characters) for public/portal access

Only draft reports can be deleted. Once a report is reviewed or sent, it must stay in the system for audit purposes.

Deleting a Draft

Endpoint: DELETE /admin/reports/monthly/:id

Only reports with status: "draft" can be deleted. The delete action is audit-logged.

Overriding Metrics

After generation, you can override specific metric values without regenerating the entire report. This is useful for correcting known data gaps or adding context.

Endpoint: PUT /admin/reports/monthly/:id/overrides

Body:

{
  "overrides": {
    "totalCalls": 152,
    "note": "Adjusted for 3 test calls excluded from production data"
  }
}

The overrides object is merged with the base metrics to produce mergedMetrics, which is what the portal and API return.

Adding Notes

Endpoint: PUT /admin/reports/monthly/:id/notes

Body:

{
  "notes": "Strong booking month. Campaign X drove 40% of new leads."
}

Notes are stored on the report and visible in the admin UI. They are not currently exposed to clients in the portal.

Client Portal Access

Clients can view their reports through the portal:

List Reports

Endpoint: GET /secure/reports

Returns all reports for the authenticated client, sorted by generatedAt descending. The overrides field is stripped from the list view.

View a Single Report

Endpoint: GET /secure/reports/:id

Returns the full report with mergedMetrics and previousMetrics (for period comparison). On first view, the report is marked as seenAt / seenBy.

Public Report Access

When a report status is set to sent, a reportToken is generated. This token can be used to construct a public report URL:

https://YOUR_API_HOST/public-reports/:reportToken

Public report links are unauthenticated. Treat the reportToken as a secret — do not share it in public channels. If a token is compromised, change the report status back to reviewed and then re-send it to generate a new token.

Monthly Summary (Portal)

The client portal also provides a lightweight monthly summary with daily breakdowns, separate from the formal MonthlyReport documents:

Endpoint: GET /secure/reports/monthly?year=2025&month=6

Returns:

FieldDescription
totalCallsCalls in the period
bookedCalls with booked_appointment status
totalMinutesTotal call minutes
pickupRatePercentage of calls with duration > 0
prevTotalCallsPrevious month's call count (for trend)
dailyArray of { date, calls, duration } per day

CSV Export

Endpoint: GET /secure/reports/export?from=2025-06-01&to=2025-06-30

Exports the client's own call history as a CSV file. Date range is optional; omit for all history.

Report Data Sources

Monthly reports aggregate data from:

SourceData Provided
Call recordsVolume, duration, outcomes, status
Agent metricsPer-agent calls, bookings, AI-handled calls
Analytics summaryMonthly performance summary with trend data
OverridesManual corrections applied after generation
Previous periodPrior report metrics for comparison

On this page