ReflectDocs
Browse docsOverview
REST API

Reporting API

Server-to-server REST endpoints for pulling attribution, revenue, retention, and event time-series into your BI tools, warehouse, or custom dashboards. Auth via app_server_key Bearer token. Tenant-scoped to one app per key.

Base URL

https://api.reflect.cloud/api/v1/reports

Authentication

Every request must carry a Bearer token in the Authorization header:

Authorization: Bearer srv_<48 hex chars>

Mint a key in the admin console: Settings → Server Keys → New Key. Each key is tied to ONE app — reports are automatically scoped to that app's app_id. To query multiple apps, mint one key per app.

Keep the key server-side
Don't put a Bearer key in client-side JS or in your mobile app. It carries enough authority to read every event for the app. Use it from your backend, a warehouse-pipe daemon, or a scheduled cron.

Common parameters

ParamDefaultNotes
since_msnow − 30dInclusive lower bound. Unix epoch milliseconds.
until_msnowExclusive upper bound. Max window: 365 days.
limit1001–1000.
offset0Page offset for cursor-free pagination.

Response shape

{
  "rows": [ /* report-specific rows, see each endpoint */ ],
  "meta": {
    "since_ms":   1714000000000,
    "until_ms":   1716592000000,
    "limit":      100,
    "offset":     0,
    "elapsed_ms": 47
  }
}

GET /api/v1/reports/attribution

Installs grouped by partner + attribution type + day.

curl https://api.reflect.cloud/api/v1/reports/attribution?since_ms=1714000000000 \
     -H "Authorization: Bearer srv_…"

Row shape:

{
  "day":              "2026-05-12",
  "partner":          "TikTok",
  "attribution_type": "deterministic",
  "installs":         1247,
  "organic":          0,
  "reinstalls":       18,
  "fraud_flagged":    3
}

GET /api/v1/reports/revenue

Revenue events (purchases, subscriptions) grouped by partner + day. partner is derived from each install's most-recent attribution. ARPPU is computed in-query.

{
  "day":         "2026-05-12",
  "partner":     "Meta",
  "purchases":   312,
  "revenue_usd": 4127.42,
  "arppu_usd":   13.23
}

GET /api/v1/reports/cohorts

D1 / D7 / D30 retention by install day. "Retained at day N" means the install fired any event in the 24-hour window starting N·24h after attribution.

{
  "day":      "2026-05-12",
  "installs": 1247,
  "d1":       742,
  "d7":       402,
  "d30":      201,
  "d1_rate":  0.595,
  "d7_rate":  0.323,
  "d30_rate": 0.161
}

Note: D30 rates only stabilize for installs older than 30 days. For freshly-acquired installs, D30 will be lower than reality because the window hasn't elapsed.

GET /api/v1/reports/events

Event time-series — counts by event_name + day. Includes revenue_usd for revenue-bearing events.

{
  "day":             "2026-05-12",
  "event_name":      "purchase",
  "events":          892,
  "unique_installs": 624,
  "revenue_usd":     2447.18
}

Errors

HTTPBodyCause
400{ error: "invalid_since_until" }Non-numeric or NaN timestamps
400{ error: "since_ms_must_be_less_than_until_ms" }Reversed window
400{ error: "window_too_large" }> 365 days requested
401{ error: "missing_bearer_token" }No Authorization header
401{ error: "invalid_or_revoked_key" }Key not found or revoked
404{ error: "unknown_report" }Bad path under /api/v1/reports/
405{ error: "method_not_allowed" }Anything other than GET

Rate limits

Same per-key rate limits as the S2S event API. The Reporting API queries D1 directly so latency scales with the data volume in your window — narrow windows return in <100ms; full 365-day cohort queries on high-traffic apps can take several seconds. Cache aggressively on your side.

Pipeline example

Sync nightly to a warehouse:

#!/bin/bash
KEY="srv_..."
TODAY=$(date +%s)000
SINCE=$((TODAY - 30 * 86400 * 1000))

for endpoint in attribution revenue cohorts events; do
    curl -s "https://api.reflect.cloud/api/v1/reports/$endpoint?since_ms=$SINCE&until_ms=$TODAY&limit=1000" \
         -H "Authorization: Bearer $KEY" \
         > "/tmp/reflect-$endpoint.json"

    # Pipe into your warehouse (BigQuery, Snowflake, ClickHouse, DuckDB...)
    jq -c '.rows[]' "/tmp/reflect-$endpoint.json" \
       | duckdb -c "INSERT INTO reflect_$endpoint SELECT * FROM read_ndjson_auto('/dev/stdin')"
done
Looking for raw events?
The Reporting API returns aggregated rows. For raw event-level export with every property, use the REST API's /api/v1/events stream or set up a warehouse export under Settings → Warehouse Exports (BigQuery / Snowflake / S3 / GCS sinks with daily JSONL/CSV writes).