Magister API

API Documentation

Quickstart

AI visibility, AEO audits, brand profiles and site maps for any domain over REST, billed in prepaid API credits. Get a key and make a first request.

The Magister API gives your own code the data and analysis Magister runs for its customers: AI visibility checks for any domain (on up to 11 engines of your choosing, each answer scored with the score's parts), keyword opportunities, full marketing audits, AEO audits, a brand profile and a site map from a domain. Every endpoint takes a domain or a URL and runs once, on its own: there is no brand to set up. An AI visibility check returns every answer whole, with its sources; where an endpoint is built on a data provider's keyword data, its numbers come back as bands (each endpoint below says what it is built on). It is plain HTTPS and JSON at https://api.magistermarketing.com, authenticated with an API key and paid for in prepaid API credits ($0.02 each), apart from any Magister plan.

Open to every organization — create an API account at /developers/signup (an organization with no brand, which lands on Settings → Developers), or use the organization you already have: Settings → Developers shows your keys, credits, usage, requests and webhooks. Questions, or a volume you want priced: team@magistermarketing.com.

1. Create a key — an owner or admin opens Settings → Developers → API keys → Create key. Copy it right away: the full key (mm_live_...) is shown once. Your organization's API account opens with 300 free credits. See Authentication.

2. Make a request — check your balance (free), start an AI visibility check, and poll the job until it finishes. With nothing but a domain, a check asks the 3 default engines 3 suggested questions each and costs about 22 credits; max_credits refuses it up front if it could cost more than you allow.

Choose the engines, the answers and the search — a check asks the real apps buyers use and the makers' own models. ChatGPT, Gemini and Google AI Mode are read as a person sees them, Claude, Perplexity, OpenAI and Grok are asked through their makers' APIs with web search, and Gemini (API), DeepSeek, Mistral and Meta Muse answer from what the model knows. Every answer comes back in full with its sources, beside Magister's analysis of it: whether the domain is named, where, beside whom, the score and the sites it cites. Three request fields decide what is asked:

- engines: which engines, by name ("chatgpt") or with their own settings ({"name": "openai", "answers": 5, "web_search": false}). Omitted: the default engines, marked in the table below.

- answers_per_engine: how many of the questions each engine answers (the first N). 3 by default, or every question in your own prompts.

- web_search: false asks the models without search (cheaper, no sources, and what the model itself knows of a brand); true asks only the engines that search. Omitted: each engine's default.

EngineWhat answersWeb searchIn the default checkTypical credits per answerHolds up to
chatgptThe ChatGPT app, read through DataForSEOAlwaysYes1.22.5
geminiThe Gemini app, read through DataForSEOAlwaysYes1.22.5
claudeAnthropic's API (Claude Haiku) with web searchOn by default; web_search: false turns it offYes4.713
perplexityPerplexity's Sonar APIAlways. It is a search engine: it has no answer without searchOnly by name1.85
openaiOpenAI's API (not the ChatGPT app) with web searchOn by default; web_search: false turns it offOnly by name3.410
google_ai_modeGoogle AI Mode, read through DataForSEOAlwaysOnly by name1.22.5
xaixAI's API with xAI's own search (not the Grok app)On by default; web_search: false turns it offOnly by name24.850
gemini_apiGoogle's Gemini model through an API (not the Gemini app)Never. Google's terms bar reselling answers grounded in Google SearchOnly by name1.33
deepseekDeepSeek's modelNever. Its search runs only on DeepSeek's own API, which has no zero-retention endpointOnly by name1.12.5
mistralMistral's modelNever. Mistral's terms bar storing or passing on the sources its search returnsOnly by name2.96.5
metaMeta's Muse Spark model (not the Meta AI app)Never. Its search runs only on Meta's own API, which has no zero-retention endpointOnly by name1.43

An engine outside the default check is asked only when you name it in engines, and every engine you add raises the check's price by its own credits per answer. The default check (ChatGPT, Gemini, Claude) costs about 22 credits; with every engine added it costs about 135. Grok's search pages are billed as tokens, so one of its answers costs several times any other engine's.

Add this engineAdds, for 3 answers (credits)The default check with it (credits)
Perplexity (perplexity)about 5about 27
OpenAI (openai)about 10about 32
Google AI Mode (google_ai_mode)about 4about 26
Grok (xai)about 74about 96
Gemini (API) (gemini_api)about 4about 26
DeepSeek (deepseek)about 3about 25
Mistral (mistral)about 9about 31
Meta Muse (meta)about 4about 26

An engine named for a search setting it cannot do answers 422, and GET /v1/ai-visibility/engines returns this table with which engines your account can use. An answer without search stays out of a check's citation numbers, and by_grounding in the result gives the searching and the non-searching engines' numbers apart.

bash
export MAGISTER_API_KEY=mm_live_...

# Your API credit balance (free)
curl https://api.magistermarketing.com/v1/credits \
  -H "Authorization: Bearer $MAGISTER_API_KEY"

# Start an AI visibility check: a job, answered 202 with its job_id
curl https://api.magistermarketing.com/v1/ai-visibility/check \
  -H "Authorization: Bearer $MAGISTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"domain": "example.com", "max_credits": 75}'

# Poll it until "status" is no longer "running"
curl https://api.magistermarketing.com/v1/jobs/JOB_ID \
  -H "Authorization: Bearer $MAGISTER_API_KEY"

The same in JavaScript (Node 18 or later; keep the key on a server):

js
const API = 'https://api.magistermarketing.com';
const headers = {
  Authorization: `Bearer ${process.env.MAGISTER_API_KEY}`,
  'Content-Type': 'application/json',
};

async function call(path, init = {}) {
  const response = await fetch(API + path, { ...init, headers });
  const body = await response.json();
  if (!response.ok) throw new Error(`${body.error}: ${body.message}`);
  return body;
}

let job = await call('/v1/ai-visibility/check', {
  method: 'POST',
  body: JSON.stringify({ domain: 'example.com', max_credits: 75 }),
});
while (job.status === 'running') {
  await new Promise((done) => setTimeout(done, (job.poll_after_seconds ?? 15) * 1000));
  job = await call(`/v1/jobs/${job.job_id}`);
}
console.log(job.status, job.credits_charged, job.result);

The same in Python (with requests):

python
import os
import time

import requests

API = "https://api.magistermarketing.com"
HEADERS = {"Authorization": f"Bearer {os.environ['MAGISTER_API_KEY']}"}


def call(method, path, **kwargs):
    response = requests.request(method, API + path, headers=HEADERS, timeout=30, **kwargs)
    body = response.json()
    if not response.ok:
        raise RuntimeError(f"{body['error']}: {body['message']}")
    return body


job = call("POST", "/v1/ai-visibility/check", json={"domain": "example.com", "max_credits": 75})
while job["status"] == "running":
    time.sleep(job.get("poll_after_seconds") or 15)
    job = call("GET", f"/v1/jobs/{job['job_id']}")
print(job["status"], job["credits_charged"], job["result"])

3. Read what it cost — every successful response carries credits_charged (what the request used) and the X-Magister-Credits-Remaining header (your API credit balance). A request the balance cannot cover is refused with a 402 before anything runs. See Credits and billing.

4. Go further — skip polling with a webhook (Jobs and webhooks), handle every error code (Errors), and browse every endpoint (Endpoints reference). The machine-readable OpenAPI document is at https://api.magistermarketing.com/v1/openapi.json.

API or MCP? — the API is for your own code: scripts, back ends, scheduled jobs and products you build. To work with Magister from Claude, ChatGPT, Cursor or another assistant, connect it over MCP instead (How Connect works).