Configuration
Send these headers on every call to Dedica:
1. Serve the well-known file
GET https://<your domain>/.well-known/dedica.json must return 200 with Cache-Control: no-store and:
2. Send heartbeats
CallPOST /api/v1/middleware/heartbeat/ with {"middleware": "...", "version": "..."} at least every 5 minutes, or fetch the policy that often (a policy fetch counts as a heartbeat). A 401 means a wrong or replaced token.
3. Verification
When you run the middleware check in Dedica, it fetches your well-known file and requires the rightsite_id and a heartbeat from the last 15 minutes.
4. Fetch the policy
GET /api/v1/middleware/policy/ returns what to do for your site:
serve for up to 15 minutes after the last successful fetch.
Agent detection
Match on the lowercasedUser-Agent, with every needle list sorted longest first:
- A search engine, link preview or monitor (
traditionalBots) is never an agent. - A browser navigation (
Sec-Fetch-Mode: navigateandSec-Fetch-Dest: document) is a person. - A known AI agent (
agentUa), aSignature-Agentheader insignatureAgentDomains, or abotLikePatternmatch withoutSec-Fetch-Modeis an agent.
5. Serve (autopilot only, GET and HEAD only)
Check these in order. The first match wins, and anything that answers nothing goes to your origin.X-Dedica-Origin-Fetch: 1(Dedica’s own crawler): always your origin.- The path is in
artifacts:proxyserves it from Dedica for every visitor,blockreturns 403 andpassthroughgoes to your origin.fallbackasks your origin first and returns its answer when it has the file itself (any 3xx, or a 2xx that isn’ttext/html); otherwise serve it from Dedica, and if Dedica has nothing either, return your origin’s answer. Pass through any action you don’t know. humanPageVetosayshuman(or an unknown bot-like user agent): your origin. With?mode=agent, onlyhumankeeps the normal page.- The path ends with
twins.suffix(/pricing.md) and matchesincludePathsand notexcludePaths: serve it from Dedica as a shared, cacheable answer. twins.negotiateis on, the client isn’t a search engine, and it is a detected agent, sendsAccept: text/markdownor asks for?mode=agent: serve the page’s agent version withCache-Control: private, no-store. Forward the query string.- Your origin answered
404or410to an agent with a body that isn’t markdown: keep the status and replace the body with a short markdown note pointing to/llms.txtand the home page.
/llms.txt, */llms.txt, *.md, /openapi.json, /mcp/server-card, /.well-known/*), on /ask and /mcp (any method, so an agent’s first call isn’t sent to your origin), and on ?mode=agent. Every other request goes to your origin while the policy loads.
Calling the serve API
CallGET <serve.baseUrl><path without leading slash>?<query> with:
- the token header;
- the visitor’s
User-AgentandAccept; X-Dedica-Version: v1:<artifact version or serve.version>;X-Dedica-Category: public(shared answers) oreligible(private agent versions).
If-None-Match and If-Modified-Since only for shared answers. Never let the path leave serve.baseUrl: reject . and .. segments.
6. Proxy /ask and /mcp
Whilequery is null, pass both through. Once the policy enables a route, it looks like this:
query.baseUrl, which must be Dedica’s API origin, and stream the response:
Forward only
accept, content-type, origin, user-agent, sec-fetch-*, mcp-* and last-event-id, plus the token header. Failures are explicit JSON errors (JSON-RPC for /mcp, NLWeb failure for /ask), never your origin, because the visitor asked for Dedica’s endpoint. Limit each visitor to query.requestsPerMinute requests a minute.
7. Report traffic
Report every page load, from people, AI agents and bots alike, so Dedica can show how much of your traffic is agents. Don’t report static files (scripts, styles, images, fonts, media), the sub-requests a browser page makes (Sec-Fetch-Dest other than document, iframe or frame), prefetches (Sec-Purpose or Purpose: prefetch), requests with X-Dedica-Origin-Fetch: 1 or the well-known file.
Call POST /api/v1/middleware/events/ with Content-Type: application/x-ndjson: a batch of up to 1000 events, one JSON object per line, and optionally an X-Dedica-Batch-Id header.
path and outcome are required. outcome says what the middleware did:
Batch events after the response, in the background, so reporting never slows down or changes a response. The reference worker sends a batch at 1000 events or 5 seconds after the first one, with a 5-second timeout.
Dedica answers
202 with {"accepted": n, "rejected": n, "errors": [...]} (the first 10 rejected lines and why). A bad line never fails the rest of the batch; more than 1000 events is a 400. If Dedica answers 429 or 503, or can’t be reached, keep the batch and send it with the next one (the reference worker keeps up to 5000 events). Drop it on any other answer.
Dedica accepts traffic reports but doesn’t show them in the dashboard yet.