> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fingerprintiq.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Sentinel — Server-side caller classification

# Sentinel

Classify every API caller without requiring them to identify themselves. Sentinel inspects TLS fingerprints, header ordering, and request patterns to determine if a caller is a browser, AI agent, CLI tool, or bot.

## Install

```bash
npm install @fingerprintiq/server
```

## Hono middleware

```typescript
import { Hono } from 'hono';
import { sentinel } from '@fingerprintiq/server/hono';

const app = new Hono();

app.use('/api/*', sentinel({
  apiKey: 'fiq_live_...',
}));

app.get('/api/data', (c) => {
  const caller = c.get('sentinel');
  console.log(caller?.callerType); // "AI_AGENT", "CLI_TOOL", etc.
  return c.json({ ok: true });
});
```

## Express middleware

```typescript
import express from 'express';
import { sentinel } from '@fingerprintiq/server/express';

const app = express();
app.use(sentinel({ apiKey: 'fiq_live_...' }));

app.get('/api/data', (req, res) => {
  const caller = req.sentinel;
  if (caller?.callerType === 'AI_AGENT') {
    return res.status(403).json({ error: 'AI agents blocked' });
  }
  res.json({ ok: true });
});
```

## FastAPI middleware

```bash
pip install 'fingerprintiq[fastapi]'
```

```python
from fastapi import FastAPI, Request
from fingerprintiq.sentinel.fastapi import SentinelMiddleware

app = FastAPI()
app.add_middleware(SentinelMiddleware, api_key="fiq_live_...")

@app.get("/api/data")
def handler(request: Request):
    result = request.state.sentinel  # SentinelResult | None
    if result and result.caller_type == "bot":
        return {"blocked": True}
    return {"ok": True}
```

For bare-ASGI (Starlette, Litestar, custom) use `fingerprintiq.sentinel.asgi.SentinelASGIMiddleware` with the same kwargs.

## Programmatic usage

```typescript
import { createSentinel } from '@fingerprintiq/server';

const client = createSentinel({ apiKey: 'fiq_live_...' });
const result = await client.inspect(request);

console.log(result.callerType);       // "CLI_TOOL"
console.log(result.callerConfidence); // 0.85
console.log(result.classification.library); // "curl"
```

## Caller types

| Type | What it means |
|------|--------------|
| BROWSER_HUMAN | Real browser, human timing |
| BROWSER_AUTOMATED | Real browser, bot timing (Puppeteer, Playwright) |
| AI_AGENT | Agent framework (LangChain, CrewAI, AutoGen) |
| CLI_TOOL | Command-line tool (curl, httpie, wget) |
| SDK_CLIENT | Server-side SDK (python-requests, node-fetch) |
| BOT_SCRAPER | Web scraper or crawler |
| UNKNOWN | Not enough signals to classify |

## Live demo

Try it at [sentinel-demo.fingerprintiq.com](https://sentinel-demo.fingerprintiq.com)