Documentation

Greyline Integration Guide

Everything you need to put a counter-agent between autonomous AI agents and your real API — in 5 minutes.

Quickstart

Greyline operates as a transparent reverse proxy. You point a subdomain at Greyline via a CNAME record, and Greyline inspects, scores, and routes every request before it reaches your origin server. There is zero code change required on your API.

01

Create your account

Sign up at /get-started. You'll receive a gl_live_ API key and a CNAME target — keep both somewhere safe.

02

Add a CNAME record

Point a subdomain (e.g. api.yourdomain.com) at proxy.greyline.themeridianlab.com via your DNS provider. Greyline handles TLS automatically via Cloudflare for SaaS.

03

Set your origin

In your dashboard, set the origin URL — the real endpoint Greyline forwards human traffic to. This never appears in DNS or public config.

04

Watch the sessions roll in

Your dashboard shows every agent session: score, signals detected, turn count, and the full interrogation transcript if the Bouncer engaged.

Fail-open guarantee. If Greyline encounters an error for any reason — network issue, internal timeout, unexpected input — the request passes through to your origin unchanged. Greyline never blocks legitimate traffic due to its own failure.

CNAME Setup

Add a single CNAME record to your DNS provider. The exact steps vary by provider but the values are always the same.

FieldValue
Type CNAME
Name / Host Your chosen subdomain, e.g. api
Target / Value proxy.greyline.themeridianlab.com
TTL 300 (or lowest available — we provision TLS quickly)
Do not proxy through Cloudflare (orange cloud off). If your DNS is on Cloudflare, set the CNAME record to DNS only mode. Greyline already sits on Cloudflare's network — double-proxying creates routing issues.

Propagation time

DNS propagation typically takes 5–15 minutes for low-TTL records. TLS certificate issuance happens automatically within that window. You can verify by visiting your subdomain in a browser — you should see a Greyline response (not your origin) while a request with no agent signals passes straight through.

Verification

After DNS propagates, verify your setup is active:

bash — Verify CNAME is live
# Check DNS resolution
dig CNAME api.yourdomain.com +short
# Should return: proxy.greyline.themeridianlab.com.

# Check TLS and proxy response
curl -I https://api.yourdomain.com
# Should return: x-greyline-score header in the response

Every proxied response includes the following response headers for debugging:

HeaderDescription
x-greyline-scoreNumerical score 0–100 for this request
x-greyline-labelhuman, uncertain, or agent
x-greyline-sessionSession ID (stable within a 24h window per IP+UA)
Note: Response headers are stripped from requests routed to the Bouncer — agents should not be able to detect Greyline's presence.

Strategies

When a request scores above your configured threshold, Greyline routes it to the Bouncer Durable Object. You can configure which strategy the Bouncer uses from your dashboard.

StrategyWhat happensTier
interrogate Claude-powered conversational friction. The Bouncer responds as a helpful-but-bureaucratic API assistant. Agents spend compute turns providing "compliance documentation" that goes nowhere. Free
tarpit Interrogation with an artificial 8-second delay before each response. Maximizes cost to the agent operator. Effective against high-volume scraping agents. Pro
poison Claude generates a schema-valid but entirely fabricated API response. The agent receives plausible-looking fake data — IDs, timestamps, field values — that it may pass to downstream systems. Requires your OpenAPI spec to be loaded. Enterprise
honeypot Returns an immediate fake 200 response with no Claude call. Zero compute cost. Best for known high-confidence agent patterns you want to silently discard. Free

Score thresholds

Requests are scored 0–100 before any routing decision:

Score rangeLabelDefault action
0–30 Human Pass through to origin
31–60 Uncertain Pass through, log session
61–100 Agent Route to Bouncer with configured strategy

You can adjust the interception threshold (default: 61) from your account settings. Lowering it catches more uncertain traffic; raising it reduces any false-positive risk at the cost of letting marginal agents through.

Score Thresholds

Greyline's scoring engine runs 11 signal detectors organized into three tiers. These tiers determine how aggressively signals contribute to the final score.

Signal tiers

TierExamplesScore contribution
Zero-FP Agent framework user-agent, known ESP headers, agent metadata headers Any single signal → 90+ score. These have no false-positive cases — only agent frameworks send them.
Low-FP Superhuman request speed, heartbeat cadence, suspicious accept-encoding, API key auth without cookies 3+ signals → 85. 2 signals → 70. 1 signal → 40. Combined pattern required.
Medium-FP High turn count, anomalous request timing Score boost only (×0.15 multiplier). Never auto-flag alone — these are boosters.

After the signal tiers, global fingerprint intel is checked. If a session's fingerprint has been confirmed as an agent pattern by other customers, confidence is added (up to 0.85, with linear decay over 30 days).

Fast-Pass Tokens

Fast-pass allows you to pre-authorize known legitimate agents — your own automation, partner integrations, CI systems — so they bypass scoring entirely. Fast-pass uses Ed25519 asymmetric tokens for zero-latency verification.

How it works

  1. Generate an Ed25519 key pair using any standard library or the CLI.
  2. Register the public key in your Greyline dashboard under Fast-Pass → Add Operator.
  3. Your agent signs each request with the private key and includes the token in the x-fast-pass header.
  4. Greyline verifies the signature using your registered public key. Verified requests skip all signal detection.

Token format

The fast-pass header value is a base64url-encoded JSON payload followed by a period and the base64url-encoded Ed25519 signature:

Fast-Pass token format
# Header: x-fast-pass
# Value: base64url(payload) + "." + base64url(signature)

# Payload (JSON):
{
  "sub": "my-operator-id",   // Registered operator ID
  "iat": 1742392000,         // Issued at (Unix timestamp)
  "exp": 1742392300          // Expires (max 5 minutes ahead)
}

Generating a key pair

Node.js — Generate Ed25519 key pair
import { generateKeyPairSync } from 'crypto';

const { privateKey, publicKey } = generateKeyPairSync('ed25519', {
  publicKeyEncoding:  { type: 'spki', format: 'der' },
  privateKeyEncoding: { type: 'pkcs8', format: 'der' },
});

// Register this public key in your Greyline dashboard
console.log(publicKey.toString('base64'));

// Keep the private key safe — sign tokens with it
console.log(privateKey.toString('base64'));
Never expose your private key. Store it in a secrets manager (AWS Secrets Manager, Vault, GitHub Actions secrets). Treat it like a root API key.

API Authentication

All Greyline API calls authenticate using your gl_live_ API key via the X-Greyline-API-Key header.

Example authenticated request
curl https://greyline-api.hello-knowyourexposure-com.workers.dev/api/account \
  -H "X-Greyline-API-Key: gl_live_your_key_here"
Base URL: https://greyline-api.hello-knowyourexposure-com.workers.dev
All API endpoints require X-Greyline-API-Key authentication.

Sessions API

GET/api/sessions

Returns paginated agent sessions. Sessions are created when a request scores above the yellow threshold (31+) and is logged.

Query paramDefaultDescription
limit25Results per page (max 100)
offset0Pagination offset
statusFilter: active, exhausted, idle-expired
Response
{
  "sessions": [
    {
      "id": "sess_a1b2c3...",
      "firstSeen": 1742392000000,
      "lastSeen": 1742392180000,
      "turnCount": 7,
      "score": 82,
      "strategyUsed": "interrogate",
      "framework": "openai-agents",
      "status": "active"
    }
  ],
  "total": 148,
  "limit": 25,
  "offset": 0
}

GET/api/sessions/:id

Returns a single session with its full turn-by-turn transcript.

Response includes transcript
{
  "session": { ... },
  "transcript": [
    { "turn": 1, "role": "agent",   "content": "GET /users/export" },
    { "turn": 1, "role": "bouncer", "content": "To process this request, could you provide..." }
  ]
}

Stats API

GET/api/stats

Returns aggregate stats for your account: blocked counts, top frameworks detected, and daily activity for the last 14 days.

Response
{
  "totals": {
    "blocked": 1847,
    "interrogated": 312,
    "passed": 94821
  },
  "frameworks": [
    { "framework": "openai-agents", "count": 84 },
    { "framework": "langchain",     "count": 61 }
  ],
  "daily": [
    { "date": "2026-03-18", "blocked": 124, "passed": 6210 }
  ]
}

Config API

PUT/api/customers/config

Update your account configuration. All fields are optional — only provided fields are updated.

FieldTypeDescription
strategystringinterrogate, tarpit, poison, honeypot
originUrlstringYour real API origin (kept server-side, never exposed)
openApiSpecstringOpenAPI JSON/YAML spec for poison mode (max 50KB)
interceptThresholdnumberScore threshold for interception (default: 61)

Fast-Pass API

POST/api/fast-pass

Register a new fast-pass operator. Once registered, requests bearing a valid token signed with the operator's private key bypass all signal scoring.

Request body
{
  "name": "My CI Pipeline",
  "email": "ops@yourdomain.com",
  "publicKeyBase64": "MCowBQYDK2VwAyEA...",
  "intent": "Post-deploy smoke tests"
}
Response
{
  "operatorId": "fp_op_a1b2c3d4",
  "name": "My CI Pipeline"
}

Use the operatorId as the "sub" claim in your fast-pass token payload.

Signals Overview

Greyline inspects each request across 11 signals without modifying the request or adding latency to the pass-through path. Signal detection runs synchronously in ~2ms average.

Signal Tiers

Zero false-positive signals

SignalWhat it detects
framework-uaKnown agent framework user-agent strings (OpenAI Agents, LangChain, CrewAI, AutoGPT, etc.)
agent-metadataRequest headers that agent frameworks inject (x-openai-assistant-id, x-agent-id, etc.)
missing-browserAbsent browser-only headers that all real browsers send (sec-fetch-site, sec-ch-ua)

Low false-positive signals

SignalWhat it detects
superhuman-speedRequest cadence faster than human typing or reading allows
heartbeat-cadenceMetronomic polling patterns at exact intervals (agent retry loops)
send-time-anomalyRequests during statistically unlikely hours relative to timezone
suspicious-uaNon-browser, non-bot UAs from curl, Python, Go HTTP clients, etc.
missing-cookiesAPI key auth with no cookie header — common in headless agent setups
cross-user-patternFingerprint seen across multiple customer accounts (shared agent infra)

Medium false-positive signals (score boosters only)

SignalWhat it detects
high-turn-countSession has made an unusually high number of requests within the day window
suspicious-acceptAccept-Encoding or Content-Type patterns atypical for browser clients

Badge CDN

Embed a live badge on your docs or status page showing real-time blocked agent counts. The badge updates automatically — no JavaScript, no iframe.

Live badge (auto-updating)

HTML
<img
  src="https://greyline-badge.hello-knowyourexposure-com.workers.dev/badge/YOUR_CUSTOMER_ID.svg"
  alt="Protected by Greyline"
  height="20"
>

The live badge refreshes every 60 seconds and shows the count of blocked agent sessions in the last 30 days.

Static shield badge

HTML — static "protected" shield
<img
  src="https://greyline-badge.hello-knowyourexposure-com.workers.dev/badge/YOUR_CUSTOMER_ID/shield.svg"
  alt="Protected by Greyline"
  height="20"
>

Your YOUR_CUSTOMER_ID is displayed in your dashboard Settings tab.

Tip: Some operators report that displaying the badge deters unsophisticated agents entirely — the badge is a signal that the API is actively monitored.