Skip to main content
GET /notifications/{id}/metrics returns the delivery funnel for one notification template as a time series: sent, delivered, opened, clicked, errors, and undeliverable, broken out per provider and channel inside every bucket. Use it to build your own dashboards, alert when a delivery rate drops, pull the numbers into a warehouse or BI tool, or let an agent answer “how is this template doing?” without opening the Courier app.

Endpoint

GET https://api.courier.com/notifications/{id}/metrics Authenticate with your workspace API key as a Bearer token: Authorization: Bearer <token>. id is the template ID (nt_ prefix) or its alias. Full parameter and response details are on the reference page.

Pick a window

Two ways to set the window:
  • lookback: an ISO 8601 duration counted back from now, like P30D, P12W, or PT12H. If you send no window at all, Courier uses P30D.
  • start and end: ISO 8601 timestamps with an offset, like 2026-08-01T00:00:00Z. Supply both or neither. Either one alone returns 400, as does a start that is not earlier than end. An end in the future is accepted and not clamped, so the trailing buckets come back empty.
If you send both, start and end win and lookback is ignored. All boundaries are UTC. There is no timezone support, so a “day” is a UTC day. Courier widens the window to whole buckets, so every bucket the window touches comes back complete. A request for the last 36 hours at DAY granularity returns two full days, not a day and a half. The response echoes the snapped start and end. Label charts with those, not with the values you requested.

Pick a granularity

granularity sets the bucket size: HOUR, DAY (the default), WEEK, or MONTH. WEEK buckets start on Sunday. A finer granularity caps the window it can cover: A wider window returns 400. Use a coarser granularity instead of splitting the range across calls. WEEK and MONTH have no window cap, but every response is limited to 1000 buckets, and a request that would exceed that also returns 400.

Read the response

series holds one entry per bucket between the snapped start and end, oldest first. Each entry has a period, the start of the bucket in UTC, and a data array with one row per provider and channel that handled a message in that bucket. Quiet buckets are still returned, with data: [], so a series is plottable as-is with no gap filling on your side. There is no bucket-level total. Sum the rows in a bucket to get one, and compute rates from the sums:
Guard the division: an empty bucket has a sent of zero.
delivered depends on the provider reporting delivery back to Courier, and opened is always 0 on channels with no open tracking. See Analytics to set up delivery tracking for your providers.

Fetch the last 7 days

Plan limits and rate limits

Rate limits are per workspace, and every response carries RateLimit-* headers so you can pace a backfill.
A window that reaches further back than your plan allows returns 402, not a truncated series. Check the plan cap before you widen a range. A 429 carries Retry-After: wait that many seconds before retrying.

Errors

Good to know

  • An unknown template ID returns 200 with an all-empty series, not 404. Confirm the ID before you conclude a template sent nothing.
  • Messages sent without a template never appear here.
  • This endpoint is per-template only. To cover the whole workspace, list your templates with GET /notifications and call metrics for each one.
  • Available in the US region only.