bufferq

A bouncerfor your API.

bufferq runs as a sidecar middleware next to your API — no proxy, no DNS changes. It works out who's actually calling: human, script, or autonomous agent. Then it decides to let them through, grant them a slot, or queue them with a token to come back. 402 native and HATEOAS native for better understanding from agents.

Get startedSee the flow
no proxyno DNS changes<10 ms per evaluation402 + HATEOAS native
Admit, defer, or bounce.
Bouncer
admit · defer · reject
Your API
A
B
C
D
Under the limit — straight through
Over the limit — token, wait, retry
Retries too early — bounced again
Payment required — pay, then return
TOKENretry in 4s
TOKENretry in 7s
INVOICE402 · pay
inv_77d · awaiting payment
PAIDreceipt r_2b8
ADMIT
DEFER · token issued
TOKEN OK · ADMIT
DEFER · token issued
TOO EARLY · 429
TOKEN OK · ADMIT
402 · PAYMENT REQUIRED
RECEIPT OK · ADMIT
200 OK
200 OK
200 OK
200 OK
Gate log
A GET /v1/orders
B POST /v1/invoices
C POST /v1/invoices
A admitted · under limit
D POST /v1/render
B deferred · token t_4f1 · 4s
C deferred · token t_9ac · 7s
D 402 · payment required
A 200 OK
D paid · receipt r_2b8
C retries early with t_9ac
C 429 · token not ready
B retries t_4f1 · valid · admitted
D retries r_2b8 · admitted
B 200 OK
C retries t_9ac · valid · admitted
D 200 OK
C 200 OK
Admit
Defer, token issued
Retry with token
Reject
Payment required (402)

A dead end becomes a conversation.

Over the limit, a caller gets a token and a link to the next request. Come back, ask again, get a real answer.

real response · POST /api/accessgate/evaluate
{
  "outcome": "Queued",
  "callerType": "Agent",
  "granted": false,
  "leaseToken": "061F6A05…70CA",
  "reason": "rate_limit_exceeded",
  "links": {
    "poll": { "href": "/api/accessgate/poll", "method": "POST" }
  }
}
62 s later · POST /api/accessgate/poll
{
  "granted": true,
  "leaseToken": "ea530bb0…1c0c92",
  "reason": "poll_granted_within_rate_limit",
  "links": {
    "complete": { "href": "/api/accessgate/complete", "method": "POST" }
  }
}
Transport
HTTPgRPC

Call the gate over HTTP or gRPC — whichever your sidecar already speaks.

Native SDKs
JavaScript.NET

Available today for JavaScript and .NET.

Two different problems, one gate

Both are live in bufferq today — the same classification and policy engine, pointed at different traffic.

Agent traffic

Autonomous agents don't behave like your other traffic

Tool-call fan-outs fire five to thirty parallel requests in under fifty milliseconds, with near-zero dwell time between a response and the next dependent call. A static per-IP limiter can't tell that apart from an attack — it just drops things.

—Classifies the caller from request signals (Agent, StandardApi, Human, Unknown)
—Fingerprints repeat callers internally, never exposed to the caller
—Everything else passes through untouched — no evaluation, no record
API keys

Any caller can get a key with a real limit attached

Issue a key, attach a requests-per-minute policy, and bufferq enforces it — atomically, under concurrency, with no race between the request that got through and the one that didn't. Callers that are over the limit get a token back, not a dead end.

—Fixed per-minute windows — a window resets, it doesn't just keep rolling forward
—A denied request gets a poll token, not just a 429 and silence
—The caller asks "can I come in now?" and gets a real answer

What happens to one request

Not a pipeline diagram — this is the actual sequence, in the order it runs.

1.0
Evaluate.

The sidecar calls bufferq before the backend does any work — route, tenant, the caller's User-Agent and IP, and an API key + policy if one was presented.

2.0
Classify.

No key: bufferq classifies the caller — Agent, StandardApi, Human, or Unknown — from request signals. A key: its rate-limit policy takes over instead.

3.0
Decide.
PassThrough
Not an agent and no key — no record, gone.
Granted
Within the policy — a lease token, immediately.
Queued
Over the limit — a poll token instead of silence.
BillWalled
A fourth lane, wired to a real HTTP 402 in the controller — the status code fires the moment the service can produce it; no capacity rule or payment processor decides that yet.
4.0
Poll.

Only reachable from Queued. The caller asks "can I come in now?" bufferq re-checks the same window and either mints a real lease or says wait — and the response carries a links object naming the next request (poll again, or complete), so the caller doesn't have to hardcode routes to find out.

Three things that matter

links

Every response says what's next.

A Granted response carries a complete link. A Queued response carries a poll link. A caller doesn't need to know the API ahead of time — it follows what the response gives it, not a hardcoded route.

402

402-native, not bolted on.

BillWalled is wired to a real HTTP 402 in the controller — the status code fires the moment the service can produce it. No capacity rule or payment processor decides that yet.

<10 ms

Under 10 ms per evaluation.

bufferq runs as a sidecar, in front of every call. A gate that's slower than the request it's guarding defeats the point of a sidecar — every rate-limit and classification check is held to that target.

uffer

Put a bouncer on your API.

A sidecar next to your API. No proxy, no DNS changes.

bufferq© 2026 Chris Zioutas