API documentation
Run scans, read results, and pull PDF reports from your own scripts and integrations. POST endpoints, JSON in / JSON out, authenticated with a single API key.
What you can do
- Kick off a new scan against your active brand.
- List every scan you've ever run, or fetch just the latest one with its current status.
- Pull the full results of a scan: per-prompt model responses, mention & citation flags, and aggregate rates.
- Generate a PDF report for any scan — the same data that powers the dashboard's Print Report.
- List every blog post you've rewritten in MyAEO and fetch its markdown body.
Conventions
- Base URL:
https://myaeo.app/api/v1 - Method: all endpoints are
POST. - Body: JSON (
Content-Type: application/json). - Auth: bearer token in the
Authorizationheader. - Errors: JSON in the shape
{ error: string }with a non-2xx status code.
Generating an API key
Each MyAEO account has one active API key. Generating a new key replaces the old one — anything still using the previous key will stop working.
- Sign in to MyAEO and open Settings → API.
- Click Generate API key.
- Copy the key with the Copy button. It looks like:
myaeo_key_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// "myaeo_key_" prefix + 35 random alphanumeric charactersTreat the key like a password. Anyone holding it can read your scans and rewritten posts. If it leaks or you want to rotate it, click Generate new key on the same screen.
Authentication
Send the API key on every request as a bearer token in the Authorization header.
Authorization: Bearer myaeo_key_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/jsonRequests with a missing, malformed, or revoked key get a 401 response.
start-scan
/api/v1/start-scanKicks off a new scan against your active brand using all approved prompts and all enabled models. Web search is enabled. Returns immediately with the new scan ID — poll get-latest-scan or get-scan-results to follow progress.
Request body
No body required. Send {} or omit the body.
Example request
curl -X POST 'https://myaeo.app/api/v1/start-scan' \
-H 'Authorization: Bearer myaeo_key_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
-H 'Content-Type: application/json' \
-d '{}'const res = await fetch("https://myaeo.app/api/v1/start-scan", {
method: "POST",
headers: {
"Authorization": "Bearer myaeo_key_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
},
body: JSON.stringify({}),
});
const data = await res.json();
console.log(data);import requests
res = requests.post(
"https://myaeo.app/api/v1/start-scan",
headers={
"Authorization": "Bearer myaeo_key_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
},
json={},
)
print(res.json())Example response
{
"scan_id": "8c3f12e4-9a2b-4c8a-9c6e-1d2b3a4c5d6e",
"status": "running",
"started_at": "2026-04-25T18:32:11.482Z",
"total_responses": 12
}get-scans
/api/v1/get-scansReturns every scan you've ever run, newest first.
Request body
No body required. Send {} or omit the body.
Example request
curl -X POST 'https://myaeo.app/api/v1/get-scans' \
-H 'Authorization: Bearer myaeo_key_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
-H 'Content-Type: application/json' \
-d '{}'const res = await fetch("https://myaeo.app/api/v1/get-scans", {
method: "POST",
headers: {
"Authorization": "Bearer myaeo_key_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
},
body: JSON.stringify({}),
});
const data = await res.json();
console.log(data);import requests
res = requests.post(
"https://myaeo.app/api/v1/get-scans",
headers={
"Authorization": "Bearer myaeo_key_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
},
json={},
)
print(res.json())Example response
{
"scans": [
{
"scan_id": "8c3f12e4-9a2b-4c8a-9c6e-1d2b3a4c5d6e",
"scanned_at": "2026-04-25T18:32:11.482Z",
"time_ago": "12h ago"
},
{
"scan_id": "1f9b22c5-3a8e-4dde-b5e7-7e1a2b3c4d5e",
"scanned_at": "2026-04-22T09:14:00.000Z",
"time_ago": "4d ago"
}
]
}get-latest-scan
/api/v1/get-latest-scanReturns the most recent scan you've run, regardless of status. Same shape as get-scan-results, but skips the scan-id lookup. The status field tells you whether the scan is still running, has completed, or failed.
Request body
No body required. Send {} or omit the body.
Example request
curl -X POST 'https://myaeo.app/api/v1/get-latest-scan' \
-H 'Authorization: Bearer myaeo_key_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
-H 'Content-Type: application/json' \
-d '{}'const res = await fetch("https://myaeo.app/api/v1/get-latest-scan", {
method: "POST",
headers: {
"Authorization": "Bearer myaeo_key_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
},
body: JSON.stringify({}),
});
const data = await res.json();
console.log(data);import requests
res = requests.post(
"https://myaeo.app/api/v1/get-latest-scan",
headers={
"Authorization": "Bearer myaeo_key_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
},
json={},
)
print(res.json())Example response
{
"scan_id": "8c3f12e4-9a2b-4c8a-9c6e-1d2b3a4c5d6e",
"status": "running",
"started_at": "2026-04-25T18:32:11.482Z",
"finished_at": null,
"summary": {
"mention_amount": 4,
"cited_amount": 1,
"mention_rate": 67,
"cited_rate": 17,
"total_responses": 6
},
"prompts": [
{
"prompt_id": "5d8e1a2b-…",
"prompt": "Best CRM for small startups in 2026",
"category": "Comparison",
"models": [
{
"model": "openai/gpt-5.4",
"model_label": "ChatGPT",
"status": "completed",
"response": "For small startups in 2026, popular options include …",
"mentioned": true,
"cited": false,
"cited_urls": [],
"error": null
}
]
}
]
}get-scan-results
/api/v1/get-scan-resultsReturns the full results of one scan: per-prompt model responses, mention/citation flags, and aggregate rates.
Request body
{
"scan_id": "<scan id from get-scans>"
}Example request
curl -X POST 'https://myaeo.app/api/v1/get-scan-results' \
-H 'Authorization: Bearer myaeo_key_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
-H 'Content-Type: application/json' \
-d '{ "scan_id": "8c3f12e4-9a2b-4c8a-9c6e-1d2b3a4c5d6e" }'const res = await fetch("https://myaeo.app/api/v1/get-scan-results", {
method: "POST",
headers: {
"Authorization": "Bearer myaeo_key_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
},
body: JSON.stringify({ scan_id: "8c3f12e4-9a2b-4c8a-9c6e-1d2b3a4c5d6e" }),
});
const data = await res.json();
console.log(data);import requests
res = requests.post(
"https://myaeo.app/api/v1/get-scan-results",
headers={
"Authorization": "Bearer myaeo_key_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
},
json={"scan_id": "8c3f12e4-9a2b-4c8a-9c6e-1d2b3a4c5d6e"},
)
print(res.json())Example response
{
"scan_id": "8c3f12e4-9a2b-4c8a-9c6e-1d2b3a4c5d6e",
"status": "completed",
"started_at": "2026-04-25T18:32:11.482Z",
"finished_at": "2026-04-25T18:34:48.701Z",
"summary": {
"mention_amount": 9,
"cited_amount": 4,
"mention_rate": 75,
"cited_rate": 33,
"total_responses": 12
},
"prompts": [
{
"prompt_id": "5d8e1a2b-…",
"prompt": "Best CRM for small startups in 2026",
"category": "Comparison",
"models": [
{
"model": "openai/gpt-5.4",
"model_label": "ChatGPT",
"status": "completed",
"response": "For small startups in 2026, popular options include …",
"mentioned": true,
"cited": false,
"cited_urls": [],
"error": null
},
{
"model": "perplexity/sonar-pro-search",
"model_label": "Perplexity",
"status": "completed",
"response": "Several CRMs stand out for startups…",
"mentioned": true,
"cited": true,
"cited_urls": ["https://yourbrand.com/crm-guide"],
"error": null
}
]
}
]
}generate-report
/api/v1/generate-reportGenerates a PDF report of a scan — same data that powers the dashboard's Print Report. Pass a scan_id to target a specific scan, or omit it to use the latest completed scan. Unlike the other endpoints, this one returns the PDF bytes directly with Content-Type: application/pdf — not JSON.
Request body
{
"scan_id": "<scan id from get-scans>" // optional — omit to use latest completed scan
}Example request
curl -X POST 'https://myaeo.app/api/v1/generate-report' \
-H 'Authorization: Bearer myaeo_key_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
-H 'Content-Type: application/json' \
-d '{}' \
--output report.pdfconst res = await fetch("https://myaeo.app/api/v1/generate-report", {
method: "POST",
headers: {
"Authorization": "Bearer myaeo_key_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
},
body: JSON.stringify({}),
});
const blob = await res.blob();
// In Node: const buf = Buffer.from(await res.arrayBuffer());
// fs.writeFileSync("report.pdf", buf);import requests
res = requests.post(
"https://myaeo.app/api/v1/generate-report",
headers={
"Authorization": "Bearer myaeo_key_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
},
json={},
)
with open("report.pdf", "wb") as f:
f.write(res.content)Response
On success: 200 with a PDF body. The Content-Disposition header sets a default filename like MyAEO Report - 2026-04-26.pdf.
On failure: standard JSON error shape { error: string } with a non-2xx status.
get-posts
/api/v1/get-postsReturns every post you've rewritten in MyAEO, newest first.
Request body
No body required. Send {} or omit the body.
Example request
curl -X POST 'https://myaeo.app/api/v1/get-posts' \
-H 'Authorization: Bearer myaeo_key_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
-H 'Content-Type: application/json' \
-d '{}'const res = await fetch("https://myaeo.app/api/v1/get-posts", {
method: "POST",
headers: {
"Authorization": "Bearer myaeo_key_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
},
body: JSON.stringify({}),
});
const data = await res.json();
console.log(data);import requests
res = requests.post(
"https://myaeo.app/api/v1/get-posts",
headers={
"Authorization": "Bearer myaeo_key_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
},
json={},
)
print(res.json())Example response
{
"posts": [
{
"post_id": "a1b2c3d4-…",
"headline": "How modern CRMs are rebuilding for AI-first workflows",
"status": "completed",
"written_at": "2026-04-25T19:02:44.103Z"
},
{
"post_id": "f5e6d7c8-…",
"headline": "The 7 sales-automation patterns that actually move revenue",
"status": "completed",
"written_at": "2026-04-23T10:11:00.000Z"
}
]
}get-post-content
/api/v1/get-post-contentReturns the full markdown body of a single post.
Request body
{
"post_id": "<post id from get-posts>"
}Example request
curl -X POST 'https://myaeo.app/api/v1/get-post-content' \
-H 'Authorization: Bearer myaeo_key_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
-H 'Content-Type: application/json' \
-d '{ "post_id": "a1b2c3d4-..." }'const res = await fetch("https://myaeo.app/api/v1/get-post-content", {
method: "POST",
headers: {
"Authorization": "Bearer myaeo_key_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
},
body: JSON.stringify({ post_id: "a1b2c3d4-..." }),
});
const data = await res.json();
console.log(data);import requests
res = requests.post(
"https://myaeo.app/api/v1/get-post-content",
headers={
"Authorization": "Bearer myaeo_key_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
},
json={"post_id": "a1b2c3d4-..."},
)
print(res.json())Example response
{
"post_id": "a1b2c3d4-…",
"headline": "How modern CRMs are rebuilding for AI-first workflows",
"status": "completed",
"written_at": "2026-04-25T19:02:44.103Z",
"markdown": "# How modern CRMs are rebuilding for AI-first workflows\n\nIn 2026, the way teams sell has fundamentally shifted…"
}Errors
All errors return a non-2xx status code and a JSON body shaped { error: string }.
| Status | Meaning |
|---|---|
| 400 | Body wasn't valid JSON, or a required field is missing. |
| 401 | API key is missing, malformed, or revoked. |
| 402 | Out of credits — top up in Settings → Account.start-scan only. |
| 404 | Resource doesn't exist or isn't owned by this key. |
| 500 | Unexpected error — try again or contact support. |
| 502 | Couldn't reach the scan worker — try again in a moment. start-scan only. |
Need help? Join the Telegram group chat.