Skip to main content
The Platform Statistics API provides aggregated data across all services for reporting, billing, and analytics purposes.

Base URL

/platform-stats

Authentication

All endpoints require admin authentication.

Endpoints

Get Platform Stats

Retrieve platform-wide notification statistics for a date range.
GET /platform-stats?start_date={start_date}&end_date={end_date}

Parameters

start_date
string
Start date in YYYY-MM-DD format. Defaults to today.
end_date
string
End date in YYYY-MM-DD format. Defaults to today.

Response

{
  "email": {
    "total": 1250000,
    "delivered": 1248500,
    "failed": 1500,
    "requested": 1250000,
    "technical-failure": 500,
    "temporary-failure": 750,
    "permanent-failure": 250
  },
  "sms": {
    "total": 85000,
    "delivered": 84200,
    "failed": 800,
    "requested": 85000,
    "technical-failure": 200,
    "temporary-failure": 400,
    "permanent-failure": 200
  },
  "letter": {
    "total": 12000,
    "delivered": 11950,
    "failed": 50,
    "requested": 12000,
    "technical-failure": 30,
    "temporary-failure": 15,
    "permanent-failure": 5
  }
}

Response Fields

For each notification type (email, sms, letter):
  • total - Total notifications processed
  • delivered - Successfully delivered notifications
  • failed - Total failed notifications
  • requested - Total requested notifications
  • technical-failure - Technical failures (system errors)
  • temporary-failure - Temporary failures (will retry)
  • permanent-failure - Permanent failures (invalid recipient, etc.)

Get Billing Report Data

Retrieve comprehensive billing data for all services within a financial year date range.
GET /platform-stats/data-for-billing-report?start_date={start_date}&end_date={end_date}

Parameters

start_date
string
required
Start date in YYYY-MM-DD format
end_date
string
required
End date in YYYY-MM-DD format
Both dates must be within the same financial year. The endpoint will return a 400 error if dates span multiple financial years.

Response

[
  {
    "organisation_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "organisation_name": "Department for Education",
    "service_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
    "service_name": "Teacher Training Service",
    "sms_cost": 125.50,
    "sms_chargeable_units": 7606,
    "total_letters": 450,
    "letter_cost": 202.50,
    "letter_breakdown": "200 second class letters at 45p\n250 first class letters at 45p\n",
    "purchase_order_number": "PO-2024-12345",
    "contact_names": "Jane Smith, John Doe",
    "contact_email_addresses": "[email protected], [email protected]",
    "billing_reference": "DFE-TTS-2024"
  },
  {
    "organisation_id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
    "organisation_name": "NHS Digital",
    "service_id": "d4e5f6a7-b8c9-0123-def1-234567890123",
    "service_name": "Appointment Reminders",
    "sms_cost": 2450.75,
    "sms_chargeable_units": 148530,
    "total_letters": 0,
    "letter_cost": 0,
    "letter_breakdown": "",
    "purchase_order_number": "NHS-2024-9876",
    "contact_names": "Sarah Johnson",
    "contact_email_addresses": "[email protected]",
    "billing_reference": "NHS-APT-2024"
  }
]

Response Fields

  • organisation_id - UUID of the organisation (empty string if none)
  • organisation_name - Name of the organisation (empty string if none)
  • service_id - UUID of the service
  • service_name - Name of the service
  • sms_cost - Total SMS cost in GBP
  • sms_chargeable_units - Total chargeable SMS units (fragments)
  • total_letters - Total number of letters sent
  • letter_cost - Total letter cost in GBP
  • letter_breakdown - Human-readable breakdown of letter costs by type
  • purchase_order_number - PO number for billing
  • contact_names - Billing contact names
  • contact_email_addresses - Billing contact emails
  • billing_reference - Service billing reference
The results are sorted by organisation name (blanks last), then by service name. Only services with non-zero costs are included.

Error Responses

400
error
{
  "message": "Date must be in a single financial year.",
  "status_code": 400
}
Or:
{
  "message": "Input must be a date in the format: YYYY-MM-DD",
  "status_code": 400
}
Or:
{
  "message": "Start date must be before end date",
  "status_code": 400
}

Get DVLA Billing Report Data

Retrieve DVLA-specific billing data for letters within a financial year date range.
GET /platform-stats/data-for-dvla-billing-report?start_date={start_date}&end_date={end_date}

Parameters

start_date
string
required
Start date in YYYY-MM-DD format
end_date
string
required
End date in YYYY-MM-DD format
Both dates must be within the same financial year.

Response

[
  {
    "date": "2024-04-15",
    "postage": "second",
    "cost_threshold": "sorted",
    "sheets": 5,
    "rate": 0.31,
    "letters": 1250,
    "cost": 1937.50
  },
  {
    "date": "2024-04-15",
    "postage": "first",
    "cost_threshold": "unsorted",
    "sheets": 3,
    "rate": 0.45,
    "letters": 850,
    "cost": 1147.50
  }
]

Response Fields

  • date - Date in ISO format (YYYY-MM-DD)
  • postage - Postage class (first, second, europe, rest-of-world)
  • cost_threshold - Letter sorting threshold (sorted, unsorted)
  • sheets - Number of sheets per letter
  • rate - Rate per letter in GBP
  • letters - Number of letters sent
  • cost - Total cost in GBP

Daily Volumes Report

Retrieve daily notification volumes for the platform.
GET /platform-stats/daily-volumes-report?start_date={start_date}&end_date={end_date}

Parameters

start_date
string
required
Start date in YYYY-MM-DD format
end_date
string
required
End date in YYYY-MM-DD format

Response

[
  {
    "day": "2024-04-15",
    "sms_totals": 85000,
    "sms_fragment_totals": 102000,
    "sms_chargeable_units": 98500,
    "email_totals": 1250000,
    "letter_totals": 12000,
    "letter_sheet_totals": 36000
  },
  {
    "day": "2024-04-16",
    "sms_totals": 92000,
    "sms_fragment_totals": 110500,
    "sms_chargeable_units": 106200,
    "email_totals": 1345000,
    "letter_totals": 11500,
    "letter_sheet_totals": 34500
  }
]

Response Fields

  • day - Date in YYYY-MM-DD format (BST timezone)
  • sms_totals - Total SMS notifications sent
  • sms_fragment_totals - Total SMS fragments (160-char chunks)
  • sms_chargeable_units - Chargeable SMS units
  • email_totals - Total emails sent
  • letter_totals - Total letters sent
  • letter_sheet_totals - Total letter sheets (pages)

Daily SMS Provider Volumes Report

Retrieve daily SMS volumes broken down by provider.
GET /platform-stats/daily-sms-provider-volumes-report?start_date={start_date}&end_date={end_date}

Parameters

start_date
string
required
Start date in YYYY-MM-DD format
end_date
string
required
End date in YYYY-MM-DD format

Response

[
  {
    "day": "2024-04-15",
    "provider": "mmg",
    "sms_totals": 45000,
    "sms_fragment_totals": 54000,
    "sms_chargeable_units": 52000,
    "sms_cost": 858.00
  },
  {
    "day": "2024-04-15",
    "provider": "firetext",
    "sms_totals": 40000,
    "sms_fragment_totals": 48000,
    "sms_chargeable_units": 46500,
    "sms_cost": 767.25
  }
]

Response Fields

  • day - Date in ISO format (YYYY-MM-DD)
  • provider - SMS provider name (e.g., mmg, firetext)
  • sms_totals - Total SMS sent via this provider
  • sms_fragment_totals - Total SMS fragments
  • sms_chargeable_units - Chargeable units for this provider
  • sms_cost - Total cost for this provider in GBP

Volumes by Service Report

Retrieve notification volumes grouped by service.
GET /platform-stats/volumes-by-service?start_date={start_date}&end_date={end_date}

Parameters

start_date
string
required
Start date in YYYY-MM-DD format
end_date
string
required
End date in YYYY-MM-DD format

Response

[
  {
    "service_name": "Teacher Training Service",
    "service_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
    "organisation_name": "Department for Education",
    "organisation_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "free_allowance": 250000,
    "sms_notifications": 5200,
    "sms_chargeable_units": 6240,
    "email_totals": 125000,
    "letter_totals": 450,
    "letter_sheet_totals": 1350,
    "letter_cost": 202.50
  },
  {
    "service_name": "Appointment Reminders",
    "service_id": "d4e5f6a7-b8c9-0123-def1-234567890123",
    "organisation_name": "NHS Digital",
    "organisation_id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
    "free_allowance": 250000,
    "sms_notifications": 98500,
    "sms_chargeable_units": 118200,
    "email_totals": 450000,
    "letter_totals": 0,
    "letter_sheet_totals": 0,
    "letter_cost": 0.0
  }
]

Response Fields

  • service_name - Name of the service
  • service_id - UUID of the service
  • organisation_name - Name of parent organisation (empty string if none)
  • organisation_id - UUID of parent organisation (empty string if none)
  • free_allowance - Free SMS allowance for the service
  • sms_notifications - Total SMS notifications sent
  • sms_chargeable_units - Total chargeable SMS units
  • email_totals - Total emails sent
  • letter_totals - Total letters sent
  • letter_sheet_totals - Total letter sheets
  • letter_cost - Total letter cost in GBP

Common Error Responses

Invalid Date Format

{
  "message": "Input must be a date in the format: YYYY-MM-DD",
  "status_code": 400
}

Invalid Date Range

{
  "message": "Start date must be before end date",
  "status_code": 400
}

Financial Year Validation

{
  "message": "Date must be in a single financial year.",
  "status_code": 400
}

Notes

  • All dates use the YYYY-MM-DD format
  • Times are in UTC unless specified as BST (British Summer Time)
  • Financial year runs from April 1st to March 31st
  • Cost values are in GBP (Great British Pounds)
  • Empty organisation fields return empty strings, not null

Build docs developers (and LLMs) love