Sign in Console
Docs/API reference/Analytics export

Analytics export

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.

5 min readLast updated Oct 25, 2026View as Markdown

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). 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' 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:

JavaScript
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
curl -sS https://getgated.ai/v1/analytics/export \
  -H "Authorization: Bearer $M6L_GATE_KEY"

Example 200 OK Response

JSON
{
  "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:

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

export async function getCorrelatedAbusiveUsers(dbUsers: Array<{ id: string; email: string; name: string }>) {
  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:

Code
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").