AgentMessage
Metrics

Outbound message counts and cost

GET
/v1/metrics/messages

Returns outbound messaging metrics aggregated into fixed time buckets across a window you specify. Each bucket is a half-open [bucket_start, bucket_start + granularity) interval. This is a read-only, precomputed view, so results may lag live activity slightly.

Requires the metrics:read scope. Granularity is gated by plan tier. Legacy matrix (still live for the dormant tiers): Starter is limited to day, Growth adds hour, and Scale and Custom add minute. Under PAYG, orgs resolve to day-only granularity (by design; the finer buckets remain tied to the dormant legacy tiers). Requesting a finer granularity than your tier allows returns 422 GRANULARITY_NOT_AVAILABLE with details.max_granularity. A response is capped at 10,000 buckets; a larger window returns 422 WINDOW_TOO_LARGE with details.bucket_count and details.max_buckets.

Results are cursor-paginated, with the next-page token in meta.next_cursor (null on the last page). The cursor pins the query shape, so page-2 requests whose parameters disagree with the cursor return 422 INVALID_INPUT.

meta.as_of reports how far aggregation has progressed. Buckets whose end has not yet been aggregated render with a value of null (or groups of null when grouping is requested), distinguishing a known zero from data that is still being computed. Successful responses carry Cache-Control: private, max-age=30.

AuthorizationBearer <token>

Authenticate by sending your API key as a bearer token: Authorization: Bearer am_live_.... Every request is automatically scoped to the organization that owns the key and to the scopes granted to that key.

In: header

Query Parameters

metric*string
Value in"sent" | "delivered" | "failed" | "cost_cents"
from?string
Formatdate-time
to?string
Formatdate-time
granularity?string
Value in"minute" | "hour" | "day"
group_by?string
Value in"channel" | "error_code"
cursor?string
limit?integer
Default1000
Range1 <= value <= 5000
compare_to?string
Value in"prior_period"

Response Body

application/json

application/json

application/json

application/json

curl -X GET "https://example.com/v1/metrics/messages?metric=sent"

{
  "success": true,
  "data": {
    "metric": "messages.inbound.received",
    "granularity": "hour",
    "from": "2026-05-05T00:00:00Z",
    "to": "2026-05-06T00:00:00Z",
    "buckets": [
      {
        "bucket_start": "2026-05-05T00:00:00Z",
        "value": 14
      },
      {
        "bucket_start": "2026-05-05T01:00:00Z",
        "value": 9
      },
      {
        "bucket_start": "2026-05-06T00:00:00Z",
        "value": null
      }
    ]
  },
  "meta": {
    "as_of": "2026-05-05T23:59:43Z",
    "limit": 1000,
    "next_cursor": null
  }
}

{
  "success": false,
  "error": {
    "code": "UNAUTHORIZED",
    "message": "authentication failed",
    "request_id": "01JTBQH2FZ8K1RXC0WJ4Z9P3VM"
  }
}
{
  "success": false,
  "error": {
    "code": "FORBIDDEN",
    "message": "missing required scope",
    "request_id": "01JTBQH2FZ8K1RXC0WJ4Z9P3VM"
  }
}

{
  "success": false,
  "error": {
    "code": "GRANULARITY_NOT_AVAILABLE",
    "message": "granularity not available at this plan tier",
    "request_id": "01JTBQH2FZ8K1RXC0WJ4Z9P3VM",
    "details": {
      "max_granularity": "day"
    }
  }
}