Authentication
Create a key in Settings → Integrations (workspace owners and admins). Keys start with mk_live_, are shown once, and give read access to every brand in the workspace plus prompt management. Send the key as a bearer token:
curl https://mentioned-flame.vercel.app/api/v1/projects \
-H "Authorization: Bearer mk_live_…"Revoke a key at any time from the same page; revocation is immediate.
Rate limits & errors
Each key may make 600 requests per hour. Responses include X-RateLimit-Limit and X-RateLimit-Reset (Unix seconds); over the limit you get 429 with Retry-After. All errors use the same envelope:
{ "error": { "code": "not_found", "message": "Project not found." } }| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | A parameter or body field failed validation. |
| 401 | unauthorized | Missing, malformed, invalid or revoked key. |
| 403 | plan_required | The workspace’s plan doesn’t include API access. |
| 404 | not_found | The resource doesn’t exist in this workspace. |
| 422 | limit_exceeded | A plan limit (e.g. prompts per brand) is already reached. |
| 429 | rate_limited | Too many requests for this key. |
| 5xx | internal_error / unavailable | Retry with exponential backoff. |
Endpoints
Base URL: https://mentioned-flame.vercel.app/api/v1. All responses are JSON with a top-level data field.
GET /projects
List the brands in your workspace.
GET /projects/{id}
One brand, including its latest overall metrics.
GET /projects/{id}/metrics
Daily metrics per engine and overall (provider = all). Max 366 days per request.
Parameters: from, to (YYYY-MM-DD; default last 30 days), provider (all | openai | perplexity | anthropic | gemini)
GET /projects/{id}/results
Individual analysed answers, newest first, keyset-paginated. Answer text is omitted unless requested.
Parameters: since (ISO 8601), limit (1–500, default 100), cursor, provider, prompt_id, include=answers
GET /projects/{id}/prompts
All prompts for the brand, with the plan’s per-brand limit.
POST /projects/{id}/prompts
Add up to 100 prompts. Case-insensitive duplicates and prompts over your plan limit are skipped and reported.
Parameters: body: { "prompts": [{ "text": "…", "intent"?: "best_for|versus|alternatives|how_to|other", "tags"?: ["…"] }] }
GET /projects/{id}/recommendations
Weekly recommendations, newest week first.
Parameters: status (open | done | all), week (YYYY-MM-DD), limit (1–200)
Example: add prompts
curl -X POST https://mentioned-flame.vercel.app/api/v1/projects/PROJECT_ID/prompts \
-H "Authorization: Bearer mk_live_…" \
-H "Content-Type: application/json" \
-d '{"prompts":[{"text":"best CRM for startups","intent":"best_for","tags":["core"]}]}'{
"created": [{ "id": "…", "text": "best CRM for startups", "intent": "best_for", "tags": ["core"], "active": true, … }],
"skipped": [],
"limit": 100
}Pagination
/results returns next_cursor when more rows exist. Pass it back as ?cursor=… (keep the same filters) until it is null. Cursors are opaque; don’t construct them yourself.
Webhooks
Add HTTPS endpoints in Settings → Integrations and choose events. Each delivery is a POST with a JSON body:
{
"id": "5f0c…", // unique per event — use it to de-duplicate retries
"type": "run.completed",
"created": "2026-11-06T09:15:00.000Z",
"data": { … } // event-specific; new fields may be added, ignore unknown ones
}Events:
run.completed— a tracking run finishedalert.created— a visibility alert fired (drop, competitor overtake, new gap domains…)recommendations.created— new weekly recommendations are available
Headers on every delivery:
Mentioned-Event— the event typeMentioned-Delivery— the event idMentioned-Signature—t=<unix seconds>,v1=<hex HMAC-SHA256(secret, t + "." + raw body)>
Respond with any 2xx within 10 seconds. Other responses, timeouts and redirects count as failures and are retried with exponential backoff; an endpoint is paused automatically after 20 consecutive failures (re-enable it in settings). Use “Send test event” to check your handler.
Verifying signatures (Node.js)
import crypto from "node:crypto";
// Express example — use the RAW request body, not re-serialised JSON.
app.post("/webhooks/mentioned", express.raw({ type: "application/json" }), (req, res) => {
const ok = verifyMentionedSignature(
process.env.MENTIONED_WEBHOOK_SECRET,
req.body.toString("utf8"),
req.get("Mentioned-Signature") ?? "",
);
if (!ok) return res.status(400).send("bad signature");
const event = JSON.parse(req.body.toString("utf8"));
// Deliveries can be retried: de-duplicate on event.id.
res.sendStatus(200);
});
function verifyMentionedSignature(secret, rawBody, header, toleranceSeconds = 300) {
const parts = Object.fromEntries(header.split(",").map((kv) => kv.split("=", 2)));
const t = Number(parts.t);
if (!Number.isFinite(t) || !parts.v1) return false;
if (Math.abs(Date.now() / 1000 - t) > toleranceSeconds) return false; // replay protection
const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(parts.v1);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}AI referral tracking snippet
See how many visits each AI assistant sends to your site. Copy your brand’s snippet from the brand’s AI traffic tab and add it to every page:
<script async src="https://mentioned-flame.vercel.app/t.js" data-key="YOUR_TRACKING_KEY"></script>The script is cookieless and stores nothing in the browser. It only sends a beacon when the visitor arrives from a known AI assistant (ChatGPT, Perplexity, Claude, Gemini, Copilot, DeepSeek, Grok, Meta AI) by referrer or utm_source, and it reports only the assistant and the landing page path — never query strings or personal data. IP addresses are used transiently (hashed) for rate limiting and never stored.