Sign in Console
Docs/Platform guides/Any backend

Any backend

Node, Deno, Python, Go or PHP: one fetch call with a fail-open timeout.

3 min readView as Markdown

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

Shell
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):

TypeScript
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)

TypeScript
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...
}