API Documentation

Reference docs for events ingestion, identity, and integration patterns.

Traffic Reports API (read-only)

GET /api/v2/traffic_reports

Returns the GA4 traffic that MetrixNest synced for your product, summed over a date range and grouped by source, medium, campaign, and landing_page.

Authentication

This endpoint uses a Reports API key, not an Events API key:

bash
Authorization: Bearer <YOUR_REPORTS_API_KEY>

The two key kinds are separate. A Reports API key is rejected (401) by the ingest endpoints, and an Events API key is rejected (401) here. A Reports API key reads data for one product only.

Query parameters

Name Required Description
from yes First day of the range, YYYY-MM-DD, inclusive
to yes Last day of the range, YYYY-MM-DD, inclusive. Must be on or after from
source no Exact match on source (for example saashub.com)
medium no Exact match on medium (for example referral)

The range can hold at most 366 days, counting both from and to.

Example

bash
curl "/api/v2/traffic_reports?from=2026-09-01&to=2026-09-30&medium=referral" \
  -H "Authorization: Bearer YOUR_REPORTS_API_KEY"
json
{
  "product": "0b0f6c1e-6f0b-4a53-9f0e-2f5f5a0f7c11",
  "from": "2026-09-01",
  "to": "2026-09-30",
  "connection": { "provider": "ga4", "status": "active", "last_synced_at": "2026-10-01T03:00:12Z" },
  "coverage": { "first_report_date": "2026-09-01", "last_report_date": "2026-09-30" },
  "rows": [
    {
      "source": "saashub.com",
      "medium": "referral",
      "campaign": "(not set)",
      "landing_page": "/",
      "sessions": 12,
      "users": 10,
      "page_views": 30,
      "conversions": 1
    }
  ],
  "totals": { "sessions": 12, "users": 10, "page_views": 30, "conversions": 1 },
  "truncated": false
}

Response fields

  • product: UUID of the product the key belongs to.
  • connection: the product's GA4 data connection, or null when the product has none. status is one of pending, active, syncing, error, disconnected.
  • coverage: the earliest and latest report_date stored for the product inside the requested range. Both are null when nothing was synced for that window. source and medium filters do not change coverage, so you can tell "no data synced" (coverage is null) from "synced, but no matching sessions" (coverage is set, rows is empty).
  • rows: ordered by sessions descending, then source. campaign and landing_page can be null.
  • totals: sums over every matching row, including rows cut off by the row limit.
  • truncated: true when more than 5000 groups matched. Only the first 5000 are in rows; narrow the range or add a filter.

Errors

Status error.code When
400 parameter_missing from or to is absent
400 invalid_date from or to is not a YYYY-MM-DD date
400 invalid_date_range to is before from, or the range is longer than 366 days
400 invalid_filter source or medium is not a plain string
401 unauthorized Missing, wrong-kind, revoked, or expired key
429 rate_limited More than 60 requests per minute per key or per IP