Documentación
Todo lo necesario para anunciar, publicar o leer pistas. Los anunciantes empiezan con una campaña y una pista. Los editores empiezan con un sitio y un fragmento de instalación. Los agentes empiezan con la página de políticas. Todo ello disponible a través de la API REST.
Anunciantes
Una cuenta de anunciante contiene un saldo prepago, campañas y clues. Una campaña define el modelo de precios, pujas, presupuestos y reglas de coincidencia. Un clue es el registro que reciben los agentes. Todo lo siguiente también se puede hacer con una clave de API.
- Recarga tu saldo. La primera recarga es de $50 o más, con tarjeta a través de Stripe.
- Crea una campaña: elige CPC, CPA o CPM, establece una puja máxima y presupuestos, y define cuándo se debe considerar la campaña.
- Escribe una clue en tu propio idioma. clue la revisa según las políticas en aproximadamente un minuto y la traduce a 20 idiomas.
Reglas de coincidencia
Déjalo vacío para todo el mundo. El país proviene de la ubicación de red del agente o de lo que nos indique el sitio. El idioma en el que preguntó el agente. Déjalo vacío para cualquier idioma. Tu clue se traduce automáticamente, por lo que esto solo limita dónde la muestras. Se compara con las categorías declaradas del sitio y el contexto de la página o tarea en la que trabaja el agente. Dejar vacío para todos los tipos. Los rastreadores de entrenamiento rara vez actúan en un clue; los agentes de navegación, los clientes de API y los clientes de MCP suelen hacerlo. Lo que el agente intenta hacer. Declarado por el sitio o el agente, o inferido a partir del contexto. Déjalo vacío para todas las intenciones. Empresas, consumidores o cualquier persona. clue nunca muestra anuncios a usuarios menores de 18 años.
Informes de resultados
Cuando un agente sigue un clue, lo enviamos a su URL de destino con ?clue_id=<id>. Cuando esa visita se convierta en un registro, compra, reserva o llamada a la API, haga un POST con el id de vuelta a clue. Las campañas de CPA se cobran en ese momento; las campañas de CPC y CPM simplemente registran la acción en sus informes.
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 y desarrolladores de agentes
Un sitio es un sitio web, API, servidor MCP o agente de tu propiedad. Cada sitio tiene una clave, uno o más espacios (un espacio fija el formato y estilo de la respuesta), controles y estadísticas. Verifica la propiedad una sola vez y comienza a generar ingresos.
- Registra tu sitio web, API, servidor MCP o agente y verifica la propiedad con una etiqueta meta o un archivo.
- Crea un espacio y elige el formato con el que se comunica la interfaz: JSON, Markdown, texto, HTML, llms.txt o MCP.
- Instala la etiqueta, el middleware o la llamada a la API. Las estadísticas de los agentes comienzan desde la primera solicitud, incluso antes de que coincida una clue.
Las integraciones del lado del servidor detectan agentes mediante User-Agent y cabeceras, solicitan una coincidencia a clue y añaden el bloque a HTML, Markdown o JSON antes de que la respuesta salga de su servidor. Los visitantes humanos reciben la respuesta intacta.
Para agentes de navegación que ejecutan JavaScript. Añade un <aside> etiquetado y JSON-LD a la página. Los humanos solo ven una pequeña nota contraída.
<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
Omite las pistas que le harían ganar menos de esta cantidad por cada 1.000 servidas. Déjelo en 0 para no establecer un mínimo. Se devuelve cuando ninguna pista de pago coincide. JSON con título, resumen y URL. Nunca se factura, nunca se paga. Añade &test=1 a cualquier solicitud para recibir un clue de prueba claramente etiquetado que nunca se factura ni se paga.
Categorías
Agentes
Los agentes no necesitan una cuenta. La página de políticas explica el formato de un clue, la divulgación, la redirección de seguimiento y el informe de resultados, así como la forma de consultar clue directamente. Para agentes de IA: cómo leer un clue.
clue REST API
Cada endpoint procesa JSON. Autentícate con Authorization: Bearer <api key> desde la página de claves de API. Los endpoints discover y serve son públicos y se identifican mediante una clave de sitio.
| 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"}'