# Citeon API

Read your Citeon AI visibility data from your own code. Read only, one workspace per key, the same figures as your dashboard.

Updated 2026-10-09. Web version: https://www.citeon.ai/docs/api. OpenAPI: https://www.citeon.ai/api/v1/openapi.json

## Overview

- Base URL: https://www.citeon.ai/api/v1
- OpenAPI 3.1 file: https://www.citeon.ai/api/v1/openapi.json (public, no key needed)
- Read only: every endpoint is GET. Any other method gets 405.
- Plans: Optimize (5,000 calls a month) and Enterprise (25,000 calls a month), shared with the Citeon MCP.
- The same keys as the Citeon MCP, from Developers in Citeon.

```bash
curl https://www.citeon.ai/api/v1/workspace \
  -H "Authorization: Bearer YOUR_KEY"
```

## Authentication

Send a key in the Authorization header: Authorization: Bearer ctn_live_… . A key reads one workspace, the one it was created in. Keys are created, set to expire and revoked in Developers; the Citeon MCP docs describe them in full.

Call the API from a server, never from a web page: a key in a browser can be read by anyone.

## Conventions

- Fields are snake_case. Timestamps are ISO 8601 in UTC (2026-10-09T06:38:57Z); dates are YYYY-MM-DD.
- Rates are percentages already (24 means 24%).
- null means not measured, never 0. Objects that can be unmeasured carry measured and a reason that says why.
- Every response has a Request-Id header. Quote it when you contact us.
- Every response is checked against its schema in the OpenAPI file before it is sent.

## Pagination

Lists return { object: "list", data, has_more, next_cursor }. Ask for up to 100 items with limit (default 50). When has_more is true, pass next_cursor back as starting_after for the next page, unchanged.

```bash
curl "https://www.citeon.ai/api/v1/answers?limit=100&starting_after=NEXT_CURSOR" \
  -H "Authorization: Bearer YOUR_KEY"
```

/answers is ordered newest first by date. /questions returns every active question in one page.

## Quotas and limits

Calls are counted per billing workspace and month (UTC), shared between the API and the MCP. Every response that is counted carries the quota in headers:

| Header | Meaning |
| --- | --- |
| X-RateLimit-Limit | Calls a month on the plan |
| X-RateLimit-Remaining | Calls left this month |
| X-RateLimit-Reset | Unix seconds when the quota resets (the 1st, 00:00 UTC) |
| Retry-After | On a 429: seconds until the reset |

- /workspace and /usage are free. A call refused before it runs (bad key, bad parameter, quota reached, no access) is not counted.
- A call that runs counts, including one whose data could not be read, or one with a cursor found to be invalid while it runs.
- There is no per minute limit today. If one is added, it will be announced in the changelog first.

## Errors

Errors return a JSON body with the same shape every time:

```json
{
  "error": {
    "type": "invalid_request_error",
    "code": "invalid_parameter",
    "message": "range_days: Invalid input",
    "param": "range_days",
    "doc_url": "https://www.citeon.ai/docs/api#errors",
    "request_id": "req_…"
  }
}
```

| Status | type | code | When |
| --- | --- | --- | --- |
| 400 | invalid_request_error | invalid_parameter, invalid_cursor | A parameter is not valid; param names it |
| 401 | authentication_error | invalid_key | No key, or an unknown, revoked or expired key |
| 403 | permission_error | plan_has_no_access, workspace_inactive, workspace_not_found, key_creator_gone | The plan has no API access, the workspace was stopped, or the key's creator is no longer a member |
| 404 | invalid_request_error | unknown_endpoint | The path does not exist |
| 405 | invalid_request_error | method_not_allowed | Anything but GET |
| 429 | rate_limit_error | quota_reached | The month's calls are used; Retry-After says when they reset |
| 500 | api_error | schema_mismatch | We could not produce a correct response; nothing was guessed |
| 503 | api_error | read_failed, count_failed | A temporary failure; try again |

## Endpoints

10 endpoints, generated from the server's own registry.

### GET /workspace

The workspace's name, website, plan and the time of its latest scan. Free: not counted.

Free: not counted.

No parameters.

```bash
curl https://www.citeon.ai/api/v1/workspace \
  -H "Authorization: Bearer YOUR_KEY"
```

| Response field | Type | Description |
| --- | --- | --- |
| object | "workspace" |  |
| name | string |  |
| website | string \| null |  |
| plan | string \| null |  |
| latest_scan_at | string \| null | A timestamp, ISO 8601 in UTC. |
| dashboard_url | string |  |

### GET /usage

Calls counted this month against the plan's quota, per billing workspace. Free: not counted.

Free: not counted.

No parameters.

```bash
curl https://www.citeon.ai/api/v1/usage \
  -H "Authorization: Bearer YOUR_KEY"
```

| Response field | Type | Description |
| --- | --- | --- |
| object | "usage" |  |
| month | string | YYYY-MM, UTC. |
| calls_used | integer \| null | Calls counted this month; null if it could not be read. |
| calls_quota | integer |  |
| calls_left | integer \| null |  |
| resets_at | string | A timestamp, ISO 8601 in UTC. |

### GET /visibility

The latest scan's visibility score, the shares of answers naming and recommending the brand, share of voice rank, citations and per engine scores, as on the Overview.

Counts against the monthly quota.

No parameters.

```bash
curl https://www.citeon.ai/api/v1/visibility \
  -H "Authorization: Bearer YOUR_KEY"
```

| Response field | Type | Description |
| --- | --- | --- |
| object | "visibility" |  |
| measured | boolean |  |
| reason | string \| null | Why a value is null (not measured), or null when everything is measured. |
| as_of | string \| null | When the latest scan ran. |
| window | string \| null | The rolling period the figures summarise. |
| score | number \| null | Visibility score, 0 to 100. |
| mention_rate | number \| null | Share of answers naming the brand, a percentage (24 means 24%). null when not measured. |
| recommendation_rate | number \| null | Share of answers recommending the brand, a percentage (24 means 24%). null when not measured. |
| share_of_voice_rank | number \| null |  |
| citations | number \| null |  |
| questions | number \| null |  |
| engines | object[] |  |
| engines[].engine | string |  |
| engines[].score | number \| null |  |

### GET /questions

Every active tracked question with its answers in the window, the share naming and recommending the brand, the latest verdict per engine and the rivals named most, as on the Prompts page.

Counts against the monthly quota.

| Parameter | Type | Description |
| --- | --- | --- |
| range_days | "7" \| "14" \| "28" | Days back: 7, 14 or 28. Default 28. |

```bash
curl https://www.citeon.ai/api/v1/questions?range_days=7 \
  -H "Authorization: Bearer YOUR_KEY"
```

| Response field | Type | Description |
| --- | --- | --- |
| object | "list" |  |
| data | object[] |  |
| data[].question | string |  |
| data[].status | "rec" \| "named" \| "cited" \| "absent" \| "noanswer" | Latest verdict: rec recommended, named, cited (linked but not named), absent, noanswer. |
| data[].answers | integer |  |
| data[].named | integer \| null |  |
| data[].mention_rate | number \| null | Share of this question's answers naming the brand, a percentage (24 means 24%). null when not measured. |
| data[].recommendation_rate | number \| null | Share recommending the brand, a percentage (24 means 24%). null when not measured. |
| data[].last_answered | string \| null | A date, YYYY-MM-DD (UTC). |
| data[].reason | string \| null | Why a value is null (not measured), or null when everything is measured. |
| data[].engines | object[] |  |
| data[].engines[].engine | string |  |
| data[].engines[].status | "rec" \| "mention" \| "cited" \| "absent" \| "none" |  |
| data[].engines[].mention_rate | number \| null | This engine's share naming the brand, a percentage (24 means 24%). null when not measured. |
| data[].engines[].position | number \| null |  |
| data[].engines[].stale | boolean |  |
| data[].engines[].reason | string \| null | Why a value is null (not measured), or null when everything is measured. |
| data[].rivals | object[] |  |
| data[].rivals[].name | string |  |
| data[].rivals[].mention_rate | number |  |
| has_more | boolean | true when more items follow; pass next_cursor as starting_after. |
| next_cursor | string \| null | Opaque cursor for the next page, or null. |

### GET /answers

Every stored answer, newest first, with whether it names, recommends or cites the brand, the rivals named and the domains cited, and the answer text verbatim while it is kept (120 days).

Counts against the monthly quota.

| Parameter | Type | Description |
| --- | --- | --- |
| question | string | Only this tracked question, exactly as /questions returns it. |
| engine | string | Only this engine, for example ChatGPT. |
| since | string | From this date, YYYY-MM-DD. |
| until | string | Up to this date, YYYY-MM-DD. |
| limit | integer | Items per page, 1 to 100. Default 50. |
| starting_after | string | next_cursor from the previous page. |

```bash
curl https://www.citeon.ai/api/v1/answers?question=… \
  -H "Authorization: Bearer YOUR_KEY"
```

| Response field | Type | Description |
| --- | --- | --- |
| object | "list" |  |
| data | object[] |  |
| data[].id | string |  |
| data[].question | string |  |
| data[].engine | string |  |
| data[].date | string | A date, YYYY-MM-DD (UTC). |
| data[].names_you | boolean |  |
| data[].recommends_you | boolean |  |
| data[].cites_your_site | boolean \| null | null for answers judged before citations were measured. |
| data[].position | number \| null |  |
| data[].rivals_named | string[] |  |
| data[].cited_domains | string[] |  |
| data[].text | string \| null | The answer as stored, verbatim. null after 120 days, when only the verdict is kept. |
| data[].text_may_be_cut | boolean | true when the stored text reached the limit it was stored with (8,000 characters; 600 for answers stored before 6 Sep 2026), so it may end early. |
| has_more | boolean | true when more items follow; pass next_cursor as starting_after. |
| next_cursor | string \| null | Opaque cursor for the next page, or null. |

### GET /changes

The latest days against the same number of days before, like for like: only question and engine pairs answered in both windows, each counted once. The change in points and the questions, engines, rivals and cited sites that made it.

Counts against the monthly quota.

| Parameter | Type | Description |
| --- | --- | --- |
| days | "7" \| "14" \| "28" | Length of each window: 7, 14 or 28 days. Default 7. |

```bash
curl https://www.citeon.ai/api/v1/changes?days=7 \
  -H "Authorization: Bearer YOUR_KEY"
```

| Response field | Type | Description |
| --- | --- | --- |
| object | "changes" |  |
| measured | boolean |  |
| reason | string \| null | Why a value is null (not measured), or null when everything is measured. |
| days | integer |  |
| window_now | object \| null |  |
| window_now.from | string | A date, YYYY-MM-DD (UTC). |
| window_now.to | string | A date, YYYY-MM-DD (UTC). |
| window_before | object \| null |  |
| window_before.from | string | A date, YYYY-MM-DD (UTC). |
| window_before.to | string | A date, YYYY-MM-DD (UTC). |
| compared | object \| null |  |
| compared.pairs | integer | Question and engine pairs answered in both windows, each counted once. |
| compared.answers_now | integer |  |
| compared.answers_before | integer |  |
| compared.mention_rate_now | number |  |
| compared.mention_rate_before | number |  |
| compared.change_points | number |  |
| compared.recommendation_rate_now | number \| null |  |
| compared.recommendation_rate_before | number \| null |  |
| compared.your_site_cited_rate_now | number \| null |  |
| compared.your_site_cited_rate_before | number \| null |  |
| compared.your_site_cited_reason | string \| null | Why a value is null (not measured), or null when everything is measured. |
| compared.one_answer_moves_points | number |  |
| compared.within_two_answers | boolean | true when two answers could explain the change: it may be noise. |
| questions | object[] | The questions that moved most: up to 6 that took points and 6 that added them, largest first. questions_moved_count has the total. |
| questions[].name | string |  |
| questions[].mention_rate_now | number \| null |  |
| questions[].mention_rate_before | number \| null |  |
| questions[].change_points | number \| null |  |
| questions[].contribution_points | number |  |
| questions[].answers_now | integer |  |
| questions[].answers_before | integer |  |
| questions_moved_count | integer |  |
| engines | object[] | Every engine compared. |
| engines[].name | string |  |
| engines[].mention_rate_now | number \| null |  |
| engines[].mention_rate_before | number \| null |  |
| engines[].change_points | number \| null |  |
| engines[].contribution_points | number |  |
| engines[].answers_now | integer |  |
| engines[].answers_before | integer |  |
| rivals | object[] | Up to 6 rivals that moved most; rivals_moved_count has the total. |
| rivals[].name | string |  |
| rivals[].mention_rate_now | number |  |
| rivals[].mention_rate_before | number |  |
| rivals[].change_points | number |  |
| sources | object[] | Up to 8 cited sites that moved most; sources_moved_count has the total. |
| sources[].domain | string |  |
| sources[].cited_rate_now | number |  |
| sources[].cited_rate_before | number |  |
| sources[].change_points | number |  |
| sources[].is_your_site | boolean |  |
| rivals_moved_count | integer |  |
| sources_moved_count | integer |  |
| not_compared_pairs | integer | Pairs answered in one window only, left out. |
| older_method_answers | integer | Answers judged by the earlier method, left out. |

### GET /ai-visits

Visits AI assistants sent to the site, measured by the workspace's Citeon tracking, by assistant and landing page, as on the Traffic page.

Counts against the monthly quota.

| Parameter | Type | Description |
| --- | --- | --- |
| range_days | "7" \| "14" \| "28" | Days back: 7, 14 or 28. Default 28. |

```bash
curl https://www.citeon.ai/api/v1/ai-visits?range_days=7 \
  -H "Authorization: Bearer YOUR_KEY"
```

| Response field | Type | Description |
| --- | --- | --- |
| object | "ai_visits" |  |
| measured | boolean |  |
| reason | string \| null | Why a value is null (not measured), or null when everything is measured. |
| range_days | integer |  |
| ai_visits | integer \| null |  |
| leads | integer \| null |  |
| all_visits | integer \| null |  |
| by_assistant | object[] |  |
| by_assistant[].assistant | string |  |
| by_assistant[].visits | integer |  |
| by_assistant[].leads | integer |  |
| top_landing_pages | object[] |  |
| top_landing_pages[].path | string |  |
| top_landing_pages[].visits | integer |  |
| top_landing_pages[].leads | integer |  |

### GET /site-audit

Errors, warnings and notices found, clean pages, and each rule found with the pages it hits and their evidence, as on Reports & audit.

Counts against the monthly quota.

No parameters.

```bash
curl https://www.citeon.ai/api/v1/site-audit \
  -H "Authorization: Bearer YOUR_KEY"
```

| Response field | Type | Description |
| --- | --- | --- |
| object | "site_audit" |  |
| measured | boolean |  |
| reason | string \| null | Why a value is null (not measured), or null when everything is measured. |
| audited_at | string \| null | A timestamp, ISO 8601 in UTC. |
| found | object \| null |  |
| found.error | integer |  |
| found.warning | integer |  |
| found.notice | integer |  |
| clean_pages_rate | number \| null | Pages without an error level issue, over pages judged, a percentage (24 means 24%). null when not measured. |
| clean_pages | integer \| null |  |
| pages_judged | integer \| null |  |
| pages_read | integer \| null |  |
| rules | object[] |  |
| rules[].rule | string |  |
| rules[].title | string |  |
| rules[].severity | string |  |
| rules[].site_wide | boolean |  |
| rules[].pages | integer \| null |  |
| rules[].pages_checked | integer \| null |  |
| rules[].pages_found | object[] |  |
| rules[].pages_found[].path | string |  |
| rules[].pages_found[].evidence | string |  |

### GET /authority

DataForSEO's backlinks rank and referring domains for the site and its rivals, from the latest monthly reading. A domain DataForSEO has not crawled has null figures with the reason.

Counts against the monthly quota.

No parameters.

```bash
curl https://www.citeon.ai/api/v1/authority \
  -H "Authorization: Bearer YOUR_KEY"
```

| Response field | Type | Description |
| --- | --- | --- |
| object | "authority" |  |
| measured | boolean |  |
| reason | string \| null | Why a value is null (not measured), or null when everything is measured. |
| vendor | string \| null |  |
| measured_on | string \| null | A date, YYYY-MM-DD (UTC). |
| sites | object[] |  |
| sites[].name | string |  |
| sites[].domain | string |  |
| sites[].is_you | boolean |  |
| sites[].rank | number \| null | DataForSEO backlinks rank, 0 to 100. |
| sites[].referring_domains | number \| null |  |
| sites[].reason | string \| null | Why a value is null (not measured), or null when everything is measured. |

### GET /products

For a shop: every product, then every collection, each in the Products page's order, with the answers naming it, the answers linking its page, AI visits and the tracked questions touching it. Empty for a workspace without a catalogue. The list is computed for each request, so a scan landing between two pages can shift items; page through it in one go.

Counts against the monthly quota.

| Parameter | Type | Description |
| --- | --- | --- |
| range_days | "7" \| "14" \| "28" | Days back: 7, 14 or 28. Default 28. |
| limit | integer | Items per page, 1 to 100. Default 50. |
| starting_after | string | next_cursor from the previous page. |

```bash
curl https://www.citeon.ai/api/v1/products?range_days=7 \
  -H "Authorization: Bearer YOUR_KEY"
```

| Response field | Type | Description |
| --- | --- | --- |
| object | "list" |  |
| data | object[] |  |
| data[].type | "product" \| "collection" |  |
| data[].title | string |  |
| data[].path | string |  |
| data[].state | string |  |
| data[].answers_naming | integer | Answers that wrote this item's own title. |
| data[].answers_citing | integer \| null | Answers linking its page; null before citations were measured. |
| data[].ai_visits | integer \| null | null when tracking is not installed. |
| data[].questions_touching | integer |  |
| data[].brand_mention_rate_on_those_questions | number \| null | Share of those questions' answers naming the brand, a percentage (24 means 24%). null when not measured. |
| has_more | boolean | true when more items follow; pass next_cursor as starting_after. |
| next_cursor | string \| null | Opaque cursor for the next page, or null. |

## Changelog

| Date | Change |
| --- | --- |
| 9 Oct 2026 | v1 launch: /workspace, /usage, /visibility, /questions, /answers, /changes, /ai-visits, /site-audit, /authority, /products; OpenAPI 3.1 file; Request-Id and quota headers. |

Use is covered by the API and MCP Terms at https://www.citeon.ai/terms/api. Breaking changes are announced at least 30 days ahead.
