---
title: "Read an AI citation test, poll until it is done"
method: GET
path: "/api/v1/tools/citation-check"
tags: ["v1", "Free tools"]
---

# Read an AI citation test, poll until it is done

`GET /api/v1/tools/citation-check`

## Request

- Base URL: `https://app.serpmantics.com` (the document declares no server; this is the origin it was published from)
- URL: `https://app.serpmantics.com/api/v1/tools/citation-check`
- Auth: one of:
  - none
  - HTTP bearer

Returns the test started by `POST /api/v1/tools/citation-check`. While `status` is `pending` or
`running`, call again every 3 seconds: each engine fills in as soon as it has answered. When
`status` is `done`, at least one engine answered; `summary.citedBy` engines cite your domain out
of `summary.enginesAnswered` engines that answered. When `status` is `failed`, `failureCode` says
why (NO_ENGINE_ANSWERED, TIMEOUT, INTERNAL).

Per engine: `cited` is true when a source of the answer is on your registrable domain or one of
its subdomains, and `citedUrls` lists those pages; `mentioned` is true when your brand name appears
in the answer text, which is NOT a citation. `status` no_answer means the engine showed no answer
for this question (Google often shows no AI Overview), which is not a failure.

No quota is consumed. The `checkId` is random: whoever holds it can read the test, which is what
makes share links work. Tests expire after 30 days. Reads that are not attributed to an account are
capped at 1000 per IP address and per UTC day, far above any legitimate polling: crossing it returns
429 READ_RATE_LIMITED with `Retry-After`.

## Query parameters

- `checkId` string, required

## Response `200`

The test, in progress or finished.

- object
  - `success` boolean
  - `data` object
    - `checkId` string, required
    - `status` 'pending' | 'running' | 'done' | 'failed', required
    - `failureCode` 'NO_ENGINE_ANSWERED' | 'TIMEOUT' | 'INTERNAL' | 'null', nullable: Why the test failed, absent or null unless status is failed.
    - `domain` string, required: The registrable domain that was tested.
    - `question` string, required
    - `market` 'fr-FR' | 'en-US' | 'es-ES' | 'de-DE' | 'it-IT', required
    - `createdAt` string, date-time, required
    - `updatedAt` string, date-time, required
    - `engines` object[], required
      - `engine` 'chatgpt' | 'perplexity' | 'google_ai_overview'
      - `status` 'pending' | 'done' | 'no_answer' | 'failed'
      - `answerExcerpt` string, nullable
      - `citations` object[]
        - `position` integer
        - `url` string
        - `domain` string
        - `title` string, nullable
      - `cited` boolean: A source of the answer is on the tested domain or one of its subdomains.
      - `citedUrls` string[]
      - `mentioned` boolean: The brand name appears in the answer text. Being named is not being cited as a source.
    - `summary` object, required
      - `citedBy` integer
      - `enginesAnswered` integer
      - `competitors` object[]: Domains cited instead of yours, across engines.
        - `domain` string
        - `engines` string[]
        - `count` integer

## Other responses

- `400`: INVALID_CHECK_ID, checkId is missing or malformed.
- `404`: NOT_FOUND, no test matches this checkId.
- `429`: READ_RATE_LIMITED, anti-abuse ceiling on reads that are not attributed to an account, 1000 per IP address and per UTC day. It is not a usage quota. `details.limit`, `Retry-After` and `details.reset_at` describe it. Reads authenticated with an API key are not subject to it.
- `502`: UPSTREAM_ERROR, the test service did not answer.

---

[API](https://skmtc.dev/serpmantics/apis/api-serpmantics.md) · [All operations](https://skmtc.dev/serpmantics/apis/api-serpmantics/llms.txt) · [OpenAPI document](https://skmtc.dev/serpmantics/apis/api-serpmantics/revisions/e71b28ef35a8?raw)
