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/reportsAuthentication
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.
Common parameters
| Param | Default | Notes |
|---|---|---|
since_ms | now − 30d | Inclusive lower bound. Unix epoch milliseconds. |
until_ms | now | Exclusive upper bound. Max window: 365 days. |
limit | 100 | 1–1000. |
offset | 0 | Page 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
| HTTP | Body | Cause |
|---|---|---|
| 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/api/v1/events stream or set up a warehouse export under Settings → Warehouse Exports (BigQuery / Snowflake / S3 / GCS sinks with daily JSONL/CSV writes).