# Batch Analytics Export API (5-Min Sync) & Real-Time Telemetry Streaming

> Exclusive to the Business ($49/mo) plan: pull 5-minute batch rollups via GET /v1/analytics/export OR receive true real-time event streaming (0ms delay) via GET /v1/analytics/stream and live_stream_webhook_url to join pseudonymous user identifiers against your local database.

## Business ($49/mo) Plan Feature: Why Zero-Trust User Correlation Matters

**Plan Requirement:** Programmatic access to `GET /v1/analytics/export` is included exclusively with the **Business ($49/mo)** plan ([Upgrade to Business](https://getgated.ai/console#/billing)). Calling this endpoint with a Starter or Builder key returns `HTTP 403 pro_plan_required`.

Gated operates on a strict zero-retention privacy model: we never see or store your end-users&apos; email addresses, names, or raw prompt text. However, as an application owner, you often want to know **which specific user accounts on your platform are attempting prompt-extraction attacks, coupon exploits, or token-drain paste bombs** so your internal admin dashboard can flag, rate-limit, or suspend them.

With `GET /v1/analytics/export`, you get both privacy and full visibility:

- **Zero PII Sent to Gated:** When your backend calls `POST /v1/check`, you pass an opaque pseudonymous identifier in the `user` field (for example, `usr_8f92a1c4` or `"usr_" + sha256(user.id + LOCAL_SALT).slice(0, 16)`). Gated only ever sees that opaque token.
- **Two Access Modes: 5-Minute Batch Pull + True Real-Time Event Streaming:** Use `GET https://getgated.ai/v1/analytics/export` for scheduled 5-minute batch pulls (`min_poll_interval_seconds: 300`), OR use `GET https://getgated.ai/v1/analytics/stream` (SSE / instant stream with `0s` cooldown) and configure `live_stream_webhook_url` via `POST /v1/analytics/stream` so every blocked or flagged prompt is pushed to your server in real time (`0ms` delay) the instant it occurs.
- **Local Join Inside Your Own Backend:** Your server caches the export response for 5 minutes and joins `abusive_users_rollup[].customer_user_ref` (or `user_hash`) against your own local `users` table. Your internal admin panel displays the exact user email and account details while keeping 100% of customer PII inside your own database.

## Step 1: Pass a Pseudonymous `user` Identifier to `POST /v1/check`

Generate a deterministic pseudonymous reference on your server (or store a `gate_user_ref` column on your `users` table) and pass it in the `user` field when calling `POST /v1/check`:

```
import crypto from "node:crypto";

// Deterministic pseudonymous user token (never exposes email or raw UUID to Gated)
export function toGateUserRef(userId: string): string {
const salt = process.env.INTERNAL_USER_HASH_SALT || "app_local_salt";
return "usr_" + crypto.createHmac("sha256", salt).update(String(userId)).digest("hex").slice(0, 16);
}

// Inside your chat route before calling OpenAI / Anthropic:
const gateUserRef = toGateUserRef(currentUser.id);
const gateRes = await fetch("https://getgated.ai/v1/check", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.M6L_GATE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
user: gateUserRef,
input: userMessage,
feature: "chat",
}),
signal: AbortSignal.timeout(400),
});
```

## Step 2: Fetch & Cache `GET /v1/analytics/export` (5-Minute Cooldown)

Call `GET https://getgated.ai/v1/analytics/export` from your backend and cache the result for 5 minutes (300 seconds). If your backend calls the endpoint again before 300 seconds have elapsed, Gated returns `HTTP 429 Too Many Requests` with a `Retry-After` header indicating how many seconds remain until the next allowed poll.

```
curl -sS https://getgated.ai/v1/analytics/export \
-H "Authorization: Bearer $M6L_GATE_KEY"
```

### Example `200 OK` Response

```
{
"ok": true,
"schema_version": "1.0",
"app_id": "app_15ad7beb3e6593de",
"fetched_at": "2026-10-25T13:00:00.000Z",
"min_poll_interval_seconds": 300,
"next_allowed_fetch_at": "2026-10-25T13:05:00.000Z",
"polling_policy": "Maximum 1 fetch every 5 minutes (300 seconds) per API key. Cache this payload in your backend or database for 5 minutes.",
"summary": {
"total_checks": 42,
"blocked_count": 5,
"flagged_count": 1,
"allowed_count": 36,
"estimated_tokens_saved": 4820,
"estimated_usd_saved": 0.0723
},
"abusive_users_rollup": [
{
"user_hash": "9d81a24f0c11b3e9a01244c1",
"user_key": "usr_a8f921c4e0",
"customer_user_ref": "usr_a8f921c4e0",
"total_requests": 6,
"blocked_attempts": 4,
"flagged_attempts": 0,
"allowed_attempts": 2,
"categories_triggered": ["secret_extraction", "ecom_discount_abuse"],
"rule_ids_triggered": ["INJ.01", "SEC.01", "ECOM.DISCOUNT.01"],
"estimated_tokens_saved": 3910,
"estimated_usd_saved": 0.0587,
"first_seen_at": 1761396000000,
"last_seen_at": 1761396900000,
"recommended_action": "rate_limit_or_suspend"
}
],
"events_count": 42,
"events": [ ... ]
}
```

## Step 3: Join Against Your Local `users` Table in Your Admin Backend

Here is a complete Next.js / Node server helper that caches the Gated export for 5 minutes and joins `abusive_users_rollup` with your own database users:

```
let cachedExport: { data: any; expiresAt: number } | null = null;

export async function getCorrelatedAbusiveUsers(dbUsers: Array) {
const now = Date.now();
if (!cachedExport || now >= cachedExport.expiresAt) {
const res = await fetch("https://getgated.ai/v1/analytics/export", {
headers: { Authorization: `Bearer ${process.env.M6L_GATE_KEY}` },
});
if (res.ok) {
const payload = await res.json();
cachedExport = { data: payload, expiresAt: now + 300_000 }; // Cache for 5 minutes (300s)
} else if (!cachedExport) {
throw new Error(`Gated export returned HTTP ${res.status}`);
}
}

// Build local lookup map from pseudonymous gate_user_ref -> real internal user record
const userByRef = new Map(dbUsers.map((u) => [toGateUserRef(u.id), u]));

return (cachedExport.data.abusive_users_rollup || []).map((row: any) => ({
...row,
local_user: userByRef.get(row.customer_user_ref) || null,
}));
}
```

## One-Click AI Builder Prompt (Claude, ChatGPT, Grok Bot, Lovable, Cursor)

Copy and paste this prompt into your AI coding assistant to add an internal Abusive Users & Token Drain Leaderboard to your own admin dashboard:

```
Add an internal "AI Abuse & Token Drain Protection" panel to my admin dashboard powered by Gated:
1. In our AI chat backend route, before calling POST https://getgated.ai/v1/check, pass a deterministic pseudonymous user token in the "user" field: "usr_" + HMAC_SHA256(user.id, INTERNAL_SALT).slice(0, 16) so we never send raw user emails or PII to Gated.
2. Create an internal admin backend endpoint that fetches GET https://getgated.ai/v1/analytics/export with header Authorization: Bearer process.env.M6L_GATE_KEY.
3. IMPORTANT: Gated enforces a 5-minute (300-second) cooldown between /v1/analytics/export fetches per API key (min_poll_interval_seconds: 300). Cache the response in memory or our database for 5 minutes (300 seconds) and never poll more frequently than once every 5 minutes.
4. Join response.abusive_users_rollup[].customer_user_ref against our local users table and render an admin table showing the user email, blocked_attempts, categories_triggered, estimated_usd_saved, and recommended_action ("flag_for_review" or "rate_limit_or_suspend").
```
