Documentação
Tudo o necessário para anunciar, publicar ou ler pistas. Anunciantes começam com uma campanha e uma pista. Editores começam com um site e um trecho de instalação. Agentes começam com a página de políticas. Tudo isso está disponível através da API REST.
Anunciantes
Uma conta de anunciante mantém um saldo pré-pago, campanhas e clues. Uma campanha define o modelo de preço, lances, orçamentos e regras de correspondência. Uma clue é o registro que os agentes recebem. Tudo abaixo também pode ser feito com uma chave de API.
- Adicione saldo. A primeira recarga é de $50 ou mais, com cartão via Stripe.
- Crie uma campanha: escolha CPC, CPA ou CPM, defina um lance máximo e orçamentos, e determine quando a campanha deve ser considerada.
- Escreva uma clue no seu próprio idioma. A clue a analisa em relação às diretrizes em cerca de um minuto e a traduz para 20 idiomas.
Regras de correspondência
Deixe em branco para o mundo todo. O país vem da localização de rede do agente ou do que o site nos informa. O idioma em que o agente perguntou. Deixe em vazio para qualquer idioma. Sua clue é traduzida automaticamente, portanto isso apenas limita onde você a exibe. Cruzado com as categorias declaradas do site e o contexto da página ou da tarefa em que o agente está trabalhando. Deixe em branco para todos os tipos. Web crawlers de treinamento raramente agem em um clue; agentes de navegação, clientes de API e clientes MCP geralmente agem. O que o agente está tentando fazer. Declarado pelo site ou pelo agente, ou inferido a partir do contexto. Deixe em branco para todas as intenções. Empresas, consumidores ou qualquer pessoa. O clue nunca exibe clues para usuários menores de 18 anos.
Relatório de resultados
Quando um agent segue um clue, nós o enviamos para a sua URL de destino com ?clue_id=<id>. Quando essa visita se transforma em um cadastro, compra, reserva ou chamada de API, faça um POST com o ID de volta para o clue. Campanhas de CPA são cobradas nesse momento; campanhas de CPC e CPM apenas registram a ação nos seus relatórios.
POST https://clue.ad/v1/conversions
Authorization: Bearer clue_…
Content-Type: application/json
{"click_id": "sv_…", "kind": "signup", "value_usd": 49, "external_id": "order_123"}Editores e desenvolvedores de agentes
Um site é um site, API, servidor MCP ou agente que você possui. Cada site possui uma chave, um ou mais slots (um slot define o formato e o estilo da resposta), controles e análises. Verifique a propriedade uma vez e os ganhos começam.
- Registre seu site, API, servidor MCP ou agente e verifique a propriedade com uma meta tag ou um arquivo.
- Crie um espaço e escolha o formato que a interface suporta: JSON, Markdown, texto, HTML, llms.txt ou MCP.
- Instale a tag, o middleware ou a chamada de API. As análises de agentes começam logo na primeira requisição, antes mesmo de uma clue corresponder.
As integrações do lado do servidor detectam agentes por User-Agent e cabeçalhos, solicitam uma correspondência ao clue e adicionam o bloco em HTML, Markdown ou JSON antes que a resposta saia do seu servidor. Visitantes humanos recebem a resposta intacta.
Para agentes de navegação que executam JavaScript. Adiciona um <aside> rotulado e JSON-LD à página. Humanos veem apenas uma pequena nota recolhida.
<script async src="https://clue.ad/tag.js" data-site="site_YOUR_KEY" data-unit="unit_YOUR_UNIT" data-lang="auto" data-max="2"></script>
<!-- optional: where the block should go -->
<div data-clue-slot></div>// npm i @clue-ad/node (or copy sdk/node/clue.mjs from the docs)
import { clueMiddleware } from '@clue-ad/node';
// Express / Connect
app.use(clueMiddleware({ site: 'site_YOUR_KEY', unit: 'unit_YOUR_UNIT', base: 'https://clue.ad' }));
// Next.js (app/route.ts or middleware.ts)
import { withClue } from '@clue-ad/node/next';
export default withClue({ site: 'site_YOUR_KEY' })(handler);
// What it does: detects agents (User-Agent + headers), calls https://clue.ad/v1/serve,
// injects <aside data-clue> before </body> for HTML, a "sponsored" array for JSON, a block for Markdown.
// Humans get the untouched response.# pip install clue-ad (or copy sdk/python/clue.py)
from clue import ClueMiddleware
# FastAPI / Starlette
app.add_middleware(ClueMiddleware, site="site_YOUR_KEY", unit="unit_YOUR_UNIT", base="https://clue.ad")
# Flask
from clue import flask_clue
flask_clue(app, site="site_YOUR_KEY")
# Django: add "clue.django.ClueMiddleware" to MIDDLEWARE and set CLUE_SITE = "site_YOUR_KEY"// go get github.com/clue-ad/clue-go (or copy sdk/go/clue.go)
import clue "github.com/clue-ad/clue-go"
handler := clue.Wrap(mux, clue.Config{Site: "site_YOUR_KEY", Unit: "unit_YOUR_UNIT", Base: "https://clue.ad"})
http.ListenAndServe(":8080", handler)// Cloudflare Worker in front of your origin (copy sdk/cloudflare/worker.js)
export default {
async fetch(req, env, ctx) {
const res = await fetch(req);
return injectClue(req, res, { site: 'site_YOUR_KEY', unit: 'unit_YOUR_UNIT', base: 'https://clue.ad' });
}
}<?php // copy sdk/php/clue.php; WordPress: add to functions.php or use as a mu-plugin
require_once 'clue.php';
clue_start(['site' => 'site_YOUR_KEY', 'unit' => 'unit_YOUR_UNIT', 'base' => 'https://clue.ad']);
// buffers the HTML response and appends the sponsored block for agents only# Server-side, any language. Forward the visitor's User-Agent so clue can tell agents from humans.
GET https://clue.ad/v1/serve?site=site_YOUR_KEY&unit=unit_YOUR_UNIT&format=json&lang=<bcp47>&country=<iso2>&url=<page url>&context=<page title / task text>&intent=<research|compare|purchase|booking|coding|data|integration|support|writing>
User-Agent: <visitor's user agent>
# Response (200): {"sponsored":true,"disclosure":"…","clues":[…]} — empty clues for humans
# Formats: json | markdown | text | html | llms | mcp · Test: &test=1# Add to your llms.txt (agents that read llms.txt follow the link; nothing else changes)
## Sponsored
- [Sponsored clues for this site](https://clue.ad/v1/serve?site=site_YOUR_KEY&unit=unit_YOUR_UNIT&format=llms)
# Or fetch and inline the lines server-side when generating llms.txt:
curl -s "https://clue.ad/v1/serve?site=site_YOUR_KEY&unit=unit_YOUR_UNIT&format=llms&lang=en"// Inside your own MCP server: append clue's result to relevant tool responses.
const r = await fetch('https://clue.ad/v1/serve?site=site_YOUR_KEY&unit=unit_YOUR_UNIT&format=mcp&lang=' + lang + '&q=' + encodeURIComponent(taskText), { headers: { 'x-agent-type': 'mcp_client' } });
const sponsored = await r.json(); // { sponsored: true, disclosure, clues: [...] }
return { content: [{ type: 'text', text: JSON.stringify({ result, sponsored }) }] };// Agent developers: ask clue directly from your agent loop (you are the publisher and earn 65%).
const r = await fetch('https://clue.ad/v1/discover', {
method: 'POST', headers: { 'content-type': 'application/json', 'x-agent-type': 'api_client', 'x-agent-name': 'my-agent' },
body: JSON.stringify({ task: userTask, lang: userLang, country: userCountry, site: 'site_YOUR_KEY', max: 3 })
});
const { disclosure, clues } = await r.json();
// Show clues to your model as clearly-labelled sponsored options; report outcomes to clue.outcome_url.Controles
Pule clues que renderiam menos do que isso por 1.000 exibições. Deixe em 0 para não definir mínimo. Retornado quando nenhum clue pago corresponde. JSON com título, resumo e URL. Nunca cobrado, nunca pago. Adicione &test=1 a qualquer requisição para receber uma pista de teste claramente identificada que nunca é cobrada nem paga.
Categorias
Agentes
Os agentes não precisam de uma conta. A página de política explica o formato de uma clue, a divulgação, o redirecionamento de follow e o relatório de resultados, e como consultar o clue diretamente. Para agentes de IA: como ler uma clue.
API REST do clue
Todos os endpoints utilizam JSON. Autentique-se com Authorization: Bearer <api key> na página de chaves de API. Os endpoints de descoberta e entrega são públicos e identificados por uma chave de site.
| Method | Path | Auth | Notes |
|---|---|---|---|
| GET | /v1/discover | public | Agent intent → clues. q/task, lang, country, intent, max, format, site (optional integration key to credit an agent developer). |
| POST | /v1/discover | public | Same as GET with a JSON body: {"task":"…","lang":"ko","country":"KR","intent":"purchase","max":3} |
| GET|POST | /v1/serve | public | Publisher serve. site (required), unit, format (json|markdown|text|html|llms|mcp), max, style, lang, country, url, title, context, intent, audience, session, test=1, humans=1 |
| GET | /c/:token | public | Follow redirect → destination URL + ?clue_id= |
| POST | /v1/outcome/:clue_id | public | {"outcome":"useful|not_useful|used|purchased"} — agent outcome. used/purchased also record an action. |
| POST | /v1/conversions | advertiser key | {"click_id":"sv_…","kind":"signup","value_usd":49,"external_id":"…"} — report an action for a follow. |
| POST | /mcp | public | MCP Streamable HTTP (JSON-RPC 2.0): initialize, tools/list, tools/call (discover_clues, report_outcome). |
| GET | /v1/me | key | Account, balances, platform languages. |
| GET|POST | /v1/campaigns | key | List / create campaigns. Body: name, pricing_model (cpc|cpa|cpm), bid_usd, daily_budget_usd, total_budget_usd, start_at, end_at, countries[], languages[], categories[], keywords[], negative_keywords[], agent_types[], agent_vendors[], intents[], audience_kind, audience_ages[], dayparting[], weekdays[], frequency_cap, include_house |
| GET|PATCH | /v1/campaigns/:id | key | Read (with clues) / update. PATCH {"status":"paused"} pauses. |
| POST | /v1/campaigns/:id/clues | key | Create a clue. Body: advertiser_name, title, summary, details, capabilities[], pricing, cta, landing_url, docs_url, mcp_url, llms_txt_url, api_base_url, categories[], source_lang |
| PATCH | /v1/clues/:id | key | Update a clue (re-reviewed, re-translated) or {"status":"paused"|"active"}. |
| GET | /v1/clues/:id/translations | key | All translations of a clue. |
| GET | /v1/reports/advertiser | key | by=day|country|lang|agent_type|agent_vendor|campaign_id|clue_id|site_id|format, days=30 |
| GET | /v1/reports/publisher | key | by=day|country|lang|agent_type|agent_vendor|site_id|unit_id|format|advertiser_id, days=30 |
| GET | /v1/sites | key | Your integrations with totals. |
| GET | /.well-known/agent-ads.json | public | Discovery document for the agent-ads convention. |
# Create a campaign and a clue with the API (an agent can do this too)
curl -X POST https://clue.ad/v1/campaigns -H "Authorization: Bearer clue_…" -H "content-type: application/json" -d '{
"name": "GPU cloud — Korea", "pricing_model": "cpc", "bid_usd": 0.40, "daily_budget_usd": 50,
"countries": ["KR","JP"], "categories": ["cloud_infra","ai_ml"], "keywords": ["gpu","b300","h100","cluster"],
"agent_types": ["browsing_agent","api_client","mcp_client"], "intents": ["purchase","compare","coding"]
}'
curl -X POST https://clue.ad/v1/campaigns/123/clues -H "Authorization: Bearer clue_…" -H "content-type: application/json" -d '{
"advertiser_name": "Acme Cloud", "title": "B300 GPU instances in Seoul", "source_lang": "en",
"summary": "On-demand B300 GPU instances, immediate availability, Seoul region.",
"capabilities": ["8–64 GPU clusters", "InfiniBand", "per-hour billing"], "pricing": "$3.20/GPU/hour, min 8 GPUs",
"cta": "Request a quote", "landing_url": "https://acme.example/gpu", "docs_url": "https://acme.example/docs"
}'
# Agent: discover
curl -X POST https://clue.ad/v1/discover -H "content-type: application/json" -H "x-agent-name: my-agent" -d '{"task":"find a B300 GPU cluster in Korea next week","lang":"en","country":"KR"}'