Surface 04 · CanaryHoneypot
Deploy a honeypot
A honeypot is a decoy AI endpoint that answers convincingly with synthetic data while recording everything. Place its URL where only someone hunting for hidden endpoints would find it. Every prompt is classified by intent — jailbreak, extraction, probing, normal — and stored with its source IP, the full request headers it sent, and a suspicion score.
API access is not gated by plan. Generating a key needs only a signed-in session, and the only thing that can refuse it is holding the maximum number of active keys already — five by default. This create route also accepts a session JWT directly, so you can call it with no API key at all. The console at /canaryhoneypot deploys the same trap: name it, describe the persona, done.
What your plan does limit is how many traps can be active at once — one on Free, five on Shield, 50 on Pro and 200 on Enterprise. Pausing a trap frees its slot, so you can rotate personas without upgrading.
The honeypot has no connection to your systems — the worst an attacker gets is a convincing fiction, while you collect their playbook.
Rate limit, and what a spent decoy budget looks like
The public trap routes are unauthenticated by design — the caller is the adversary probing the trap — so they are limited by source address rather than by account: 20 requests per minute per IP, on every public trap route.
Underneath that sits a daily ceiling on the model calls a decoy reply costs, because those calls are billed to one shared inference key that every paid surface also draws on. A fully served hit spends two of them — one for the persona reply, one to classify the intent. Three buckets bound the spend, all resetting at 00:00 UTC: 66 calls across the whole platform, 40 per trap, and 40 per source IP, so one address cannot drain the platform allowance by walking across traps. An operator can raise any of the three, or switch it off.
The ceiling degrades in two steps, and detection survives both. Past three quarters of a bucket the intent classifier falls back to a keyword heuristic while the persona call is kept, so the trap still answers in the model's voice and the hit is still classified — from outside, nothing has changed. Once a bucket is spent no model call is made at all: the hit is still written with its intent, suspicion score, source IP and headers, and your alert still fires, but the caller now gets a generic 503 instead of a generated reply. It is worded as an ordinary outage and names neither the budget nor the product, so a spent trap reads as a flaky endpoint rather than as an instrumented one. The OpenAI-shaped route refuses in the shape a provider would, with error.type set to server_error.
So the convincing reply is the part a busy day can take away; the recorded hit and the alert are not. And if the budget counter itself fails it fails open — the trap answers in full — because a broken counter must not become a way to silence someone else's detection.