# Gated - Universal Zero-Trust Integration Specification

 Add Gated in front of your LLM call in under 60 seconds using native `fetch()`. Zero SDK dependencies required.

## Five Zero Trust First Principles of Gated
1. **Principle 1 - Treat Every Incoming Prompt as Untrusted Input:** Never pass raw user input directly into a privileged LLM context or tool-calling loop without deterministic pre-screening at the boundary.
2. **Principle 2 - Zero Trust Between Customer App and Screening Service (Strict Least-Privilege Data Boundary):** Your application never shares its system prompt, OpenAI/Anthropic/Supabase API keys, database credentials, or conversation history with Gated. Only the single untrusted user message (`input`), an anonymous visitor ID (`user`), and `app_id` cross the boundary.
3. **Principle 3 - Zero Supply-Chain Trust Required (Zero Third-Party Code Execution):** Never install an opaque third-party `npm` or `pip` package that could read `process.env` or execute arbitrary code inside your runtime. Integration uses only a transparent 15-line native HTTPS `fetch()` call.
4. **Principle 4 - Zero Persistent Trust in Storage (Ephemeral In-Memory Evaluation):** Prompts are evaluated in volatile memory in under 1 millisecond and discarded immediately. No raw prompt text is ever written to disk, logged, or used to train models.
5. **Principle 5 - Zero Single-Point-of-Failure Risk (Deterministic Fail-Open Continuity):** If the network call times out or an account reaches its plan quota, the boundary fails open (`{ allow: true }`) so legitimate customer traffic is never interrupted.

## 1. Environment Variable
Add your secret key to your backend environment (Vercel, Supabase Secrets, Replit Secrets, Render, Railway, AWS, or Cloudflare):
```bash
M6L_GATE_KEY=m6lg_live_your_key_here
```

## 2. Drop-In Helper (TypeScript / JavaScript / Edge Runtime)
Place this helper in your server code (e.g. `lib/m6lGate.ts` or directly inside your API route):

```ts
export interface GateVerdict {
  allow: boolean;
  verdict: "allow" | "flag" | "block";
  reason: string | null;
  category: string | null;
  message?: string;
  retry_after_s?: number;
  check_id: string;
}

export async function m6lGateCheck(params: {
  user: string;
  input: string;
  messages?: number;
  context_chars?: number;
  feature?: string;
  anonymous?: boolean;
}): Promise<GateVerdict> {
  const apiKey = process.env.M6L_GATE_KEY || (globalThis as any).Deno?.env?.get?.("M6L_GATE_KEY");
  if (!apiKey) {
    return { allow: true, verdict: "allow", reason: null, category: null, check_id: "bypass_no_key" };
  }

  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(), 800); // 800ms fail-open timeout

  try {
    const res = await fetch("https://getgated.ai/v1/check", {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${apiKey}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        user: params.user || "anon",
        input: params.input.slice(0, 32000),
        input_chars: params.input.length,
        messages: params.messages ?? 1,
        context_chars: params.context_chars ?? params.input.length,
        feature: params.feature ?? "chat",
        anonymous: params.anonymous ?? false,
      }),
      signal: controller.signal,
    });
    clearTimeout(timer);
    if (!res.ok) {
      return { allow: true, verdict: "allow", reason: null, category: null, check_id: "fail_open_http" };
    }
    return (await res.json()) as GateVerdict;
  } catch {
    clearTimeout(timer);
    // Always fail open so your app never experiences downtime
    return { allow: true, verdict: "allow", reason: null, category: null, check_id: "fail_open_timeout" };
  }
}
```

## 3. Usage in Next.js App Router (`app/api/chat/route.ts`)
```ts
import { m6lGateCheck } from "@/lib/m6lGate";

export async function POST(req: Request) {
  const { messages, userId } = await req.json();
  const latestUserText = String(messages?.[messages.length - 1]?.content ?? "");
  const visitorId = String(
    userId ||
    req.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ||
    req.headers.get("cf-connecting-ip") ||
    "anon"
  );

  // 1. Check Gated BEFORE calling OpenAI / Anthropic
  const gate = await m6lGateCheck({
    user: visitorId,
    input: latestUserText,
    messages: Array.isArray(messages) ? messages.length : 1,
    context_chars: JSON.stringify(messages ?? []).length,
    feature: "chat",
    anonymous: !userId,
  });

  if (!gate.allow) {
    return Response.json(
      {
        error: gate.reason,
        message: gate.message ?? "Sorry, I can't help with that request.",
        retry_after_s: gate.retry_after_s,
      },
      { status: gate.retry_after_s ? 429 : 400 }
    );
  }

  // 2. Proceed with your normal LLM call...
}
```
