> ## Documentation Index
> Fetch the complete documentation index at: https://docs.verseodin.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Prompts column glossary

> Plain-English definition of every column on the prompts table — what it carries, when it's null, what example values look like.

The `prompts` table stores one row per `(universe, day, engine,
prompt_id)`. Every endpoint that returns prompt data
([`/universes/{id}/prompts`](/api-reference/prompts/list-prompts),
[`/universes/{id}/prompts/{prompt_id}`](/api-reference/prompts/get-prompt-by-int-id),
[`/prompts/{id}`](/api-reference/prompts/get-prompt-by-uuid))
returns the same column set documented below.

## Identity

<ResponseField name="id" type="string (uuid)" required>
  Primary key. Stable across re-runs only when the underlying
  `(universe, day, engine, prompt_id)` row is upserted in place; if
  a row is deleted and re-created, the UUID changes.

  **Example:** `"a7be38b9-6582-4f33-a239-7045b27f7002"`
</ResponseField>

<ResponseField name="day" type="string (date)" required>
  UTC calendar day this row aggregates. Format `YYYY-MM-DD`.

  **Example:** `"2026-04-27"`
</ResponseField>

<ResponseField name="user_id" type="string (uuid)" required>
  Owner of the universe — same as `query_universe.user_id`.
</ResponseField>

<ResponseField name="universe_id" type="string (uuid)" required>
  The universe this prompt belongs to. FK to `query_universe.id`.
</ResponseField>

<ResponseField name="job_id" type="string (uuid)">
  Background job that produced this row. Multiple prompts share
  one `job_id` per run.
</ResponseField>

<ResponseField name="prompt_id" type="integer" required>
  1-based position of this prompt within the universe. Stable across
  days — `prompt_id=5` on `2026-04-27` is the same prompt as
  `prompt_id=5` on `2026-04-26`.

  **Example:** `1`
</ResponseField>

## Request inputs

<ResponseField name="prompt_text" type="string" required>
  The natural-language query that was sent to the AI assistant.

  **Example:** `"best AI visibility tool for brands"`
</ResponseField>

<ResponseField name="engine" type="string" required>
  AI assistant the prompt was run against — one of `chatgpt`,
  `gemini`, `grok`, `claude`. Lowercase, case-sensitive.
</ResponseField>

<ResponseField name="engine_account" type="string">
  Scraper pipeline that produced the row. Bright Data values:
  `BD_chatgpt`, `BD_gemini`, `BD_grok`, `BD_perplexity`. Empty/null
  for legacy in-process Cloro rows. See [Engines](/concepts/engines).
</ResponseField>

<ResponseField name="website" type="object">
  Universe's website object captured at run time — typically
  `{url, location, brand_tokens?}`.

  **Example:** `{"url": "https://verseodin.com/", "location": "us"}`
</ResponseField>

<ResponseField name="competitor_websites" type="array">
  Competitor URL list captured at run time — JSON array.

  **Example:** `[{"url": "https://semrush.com/"}, {"url": "https://tryprofound.com/"}]`
</ResponseField>

<ResponseField name="priority_level" type="integer">
  Internal scheduling priority. `0` = normal, higher = run sooner.
  Set by the dashboard's "AI agent" generator at `1000` for
  agent-created universes.
</ResponseField>

## Scrape provenance

<ResponseField name="provider" type="string">
  Underlying scraping provider, e.g. `brightdata`. Useful when
  cross-referencing with the Bright Data console.

  **Example:** `"brightdata"`
</ResponseField>

<ResponseField name="attempts" type="integer">
  How many scrape attempts the row consumed before reaching its
  terminal state. Higher numbers indicate retries — useful for
  spotting flaky prompts.
</ResponseField>

<ResponseField name="snapshot_id" type="string">
  Bright Data snapshot identifier — the same string you'd see in
  their dashboard.

  **Example:** `"sd_mogvqssus24jfei5h"`
</ResponseField>

## Lifecycle

<ResponseField name="status" type="string" required>
  `pending` | `processing` | `completed` | `failed`. The terminal
  states are `completed` and `failed`. New rows start as `pending`;
  the consumer flips them to `processing` while running and to
  `completed`/`failed` when done.
</ResponseField>

<ResponseField name="error_text" type="string">
  Failure reason — only set when `status='failed'`. Common values
  include `"empty_answer_after_retries"`, `"snapshot_canceled"`,
  `"download_parse_error"`.
</ResponseField>

<ResponseField name="created_at" type="string (datetime)" required>
  When the row was first inserted by the daily prompts creator.
</ResponseField>

<ResponseField name="started_at" type="string (datetime)">
  When the consumer claimed the row for processing. Null while
  `status` is still `pending`.
</ResponseField>

<ResponseField name="finished_at" type="string (datetime)">
  When the row reached its terminal state (`completed` or `failed`).
  Null while still processing.
</ResponseField>

## Response data — the AI answer + citations

<ResponseField name="response_text" type="string">
  **Full AI answer body** as returned by the assistant. Plain text
  with markdown formatting preserved (the AI's own bullet lists,
  headings, etc.). Empty / null while `status` is pending or
  processing; populated when `status='completed'`.

  **Example (truncated):**

  ```
  There isn't a single "best" AI visibility tool for brands —
  because the right choice depends on your team size, budget, and
  whether you want insights vs. execution. Here's a grounded
  breakdown 👇 ...
  ```
</ResponseField>

<ResponseField name="appeared_links" type="array (string)">
  Every URL the AI mentioned in its answer, in order of appearance.
  May contain duplicates (the AI may cite the same URL multiple
  times). Each item is a fully-qualified URL string.

  **Example:** `["https://verseodin.com/", "https://semrush.com/blog/...", "https://semrush.com/blog/..."]`
</ResponseField>

<ResponseField name="appeared_links_unique" type="array (string)">
  De-duplicated `appeared_links`, preserving first-appearance order.
</ResponseField>

<ResponseField name="appeared_links_run1" type="array (string)">
  Links from scrape "run 1". Bright Data fires one run per snapshot,
  so for BD-produced rows this equals `appeared_links`. Cloro's
  legacy double-run architecture used both `_run1` and `_run2`.
</ResponseField>

<ResponseField name="appeared_links_run2" type="array (string)">
  Links from scrape run 2 (legacy Cloro). Always empty `[]` for
  Bright Data rows.
</ResponseField>

<ResponseField name="my_citations" type="array (string)">
  URLs from the AI's answer that point at **your** domain — matched
  against the universe's `website.url`. Subset of
  `appeared_links_unique` filtered to only your own domain.

  **Example:** `["https://verseodin.com/blog/ai-visibility"]`
</ResponseField>

<ResponseField name="competitor_citations" type="array (string)">
  URLs from the AI's answer that point at any **competitor** domain
  — matched against the universe's competitor list.

  **Example:** `["https://semrush.com/blog/ai-overviews"]`
</ResponseField>

## Stats — per-prompt counts

<ResponseField name="total_citations_count" type="integer">
  Total cited URLs in this answer (yours + competitor + uncategorised).
  Equivalent to `len(appeared_links_unique)`.
</ResponseField>

<ResponseField name="my_domain_citations_count" type="integer">
  How many citations to your domain. Equivalent to
  `len(my_citations)`.
</ResponseField>

<ResponseField name="my_brand_mentions_count" type="integer">
  Times your brand name was mentioned in the answer text — independent
  of citations. Counts substring matches against the universe's
  `brand_tokens` list.
</ResponseField>

## Model metadata

<ResponseField name="model_used" type="string">
  Model identifier the AI returned — e.g. `gpt-4o`, `gpt-5-3`,
  `gemini-2.5-pro`. Useful when comparing answers across model
  versions.
</ResponseField>

<ResponseField name="web_search_triggered" type="boolean">
  Whether the AI invoked web search while answering. Search-backed
  answers tend to cite more sources; useful for filtering.
</ResponseField>

<ResponseField name="cost_milli_cents" type="integer">
  Cost of producing this row in 1/1000 of a cent
  (so `1234` means \$0.01234). Internal accounting field —
  exposed so customers running their own cost reconciliation
  can compare against their billing.
</ResponseField>

## Filtering recipes

```bash theme={null}
# Only rows that successfully scraped
GET /api/v1/universes/<id>/prompts?status=completed

# Only rows where your brand was mentioned at least once
# (filter client-side after pulling — there's no my_brand_mentions_count
# query parameter today)

# Just one prompt's full record by integer position
GET /api/v1/universes/<id>/prompts/1

# Or by UUID if you have it from another endpoint
GET /api/v1/prompts/a7be38b9-6582-4f33-a239-7045b27f7002

# Iterate every prompt over the last 7 days
for day in $(curl -sH "Authorization: Bearer $KEY" \
  "https://verseodin.com/api/v1/universes/<id>/days" \
  | jq -r '.data[:7] | .[]'); do
  curl -sH "Authorization: Bearer $KEY" \
    "https://verseodin.com/api/v1/universes/<id>/prompts?day=$day&status=completed&limit=1000"
done
```
