Skip to content

Visibility Reports

A visibility report is one asynchronous analysis of the website stored in a workspace. The API accepts the run immediately, then exposes its state and result through read endpoints.

Report lifecycle

stateDiagram-v2
    direction TB
    [*] --> queued: POST report
    queued --> running: processing starts
    queued --> failed: run cannot start
    running --> completed: result available
    running --> failed: error or timeout
    completed --> [*]
    failed --> [*]
Status Terminal Meaning
queued No The run was accepted and is waiting to start
running No The visibility analysis is executing
completed Yes result is available
failed Yes result is null and error describes the failure

Poll only while the report is queued or running. A report that has started is limited to approximately ten minutes of analysis time. Queued time is separate, so the partner should apply its own overall polling deadline and backoff policy.

Launch a report

POST /v1/workspaces/{workspace_id}/visibility-reports
Authorization: Bearer <partner-api-key>
Idempotency-Key: customer-visibility-2026-08-31

Required scope: reports:write

Path parameter Type Description
workspace_id string Workspace returned by POST /v1/workspaces
Header Type Required Rules
Idempotency-Key string No 1–255 characters; unique within the workspace

The request has no body. The report uses the website and enabled models stored on the workspace.

Example request:

curl --request POST \
  --url "$NBLICK_API_BASE_URL/v1/workspaces/pws-V1StGXR8_Z5jdHi6B-myT/visibility-reports" \
  --header "Authorization: Bearer $NBLICK_PARTNER_API_KEY" \
  --header "Idempotency-Key: customer-visibility-2026-08-31"

Response — 202 Accepted:

{
  "id": "pvr-8xR2kQpL_5jdHi6B-myT",
  "workspace_id": "pws-V1StGXR8_Z5jdHi6B-myT",
  "status": "queued",
  "result": null,
  "error": null,
  "created_at": "2026-08-31T12:01:00Z",
  "updated_at": null,
  "completed_at": null
}
Status When
202 New report accepted, or existing report returned for the same idempotency key
401 Partner credential is missing or invalid
403 Credential lacks reports:write
404 Workspace does not exist or belongs to another partner
422 Path, header, or idempotency-key validation fails
503 Report was not queued; response code is report_not_queued

Idempotency and retries

  • Repeating the same key in the same workspace returns the original report with 202 and does not launch another run.
  • The returned report may already be running, completed, or failed.
  • The same key can be used independently in another workspace.
  • Omitting the key creates a new report for every accepted request.
  • A 503 report_not_queued response does not consume the key, so retry with the same value.
  • Once a report exists, including a failed report, use a new key to request another analysis.
{
  "detail": {
    "code": "report_not_queued"
  }
}

List reports for a workspace

GET /v1/workspaces/{workspace_id}/visibility-reports
Authorization: Bearer <partner-api-key>

Required scope: reports:read

Query parameters

Parameter Type Default Rules
limit integer 50 Minimum 1, maximum 100
cursor string or null null Exact pagination.next_cursor from the preceding page
status enum or null null queued, running, completed, or failed
created_after RFC 3339 date-time or null null Strict lower bound; timezone required
created_before RFC 3339 date-time or null null Strict upper bound; timezone required

Filters are combined with AND. When both timestamps are supplied, created_after must be earlier than created_before. Results are ordered newest first.

Example request:

curl --get \
  --url "$NBLICK_API_BASE_URL/v1/workspaces/pws-V1StGXR8_Z5jdHi6B-myT/visibility-reports" \
  --header "Authorization: Bearer $NBLICK_PARTNER_API_KEY" \
  --data-urlencode "status=queued" \
  --data-urlencode "limit=50"

Response — 200 OK:

{
  "data": [
    {
      "id": "pvr-8xR2kQpL_5jdHi6B-myT",
      "workspace_id": "pws-V1StGXR8_Z5jdHi6B-myT",
      "status": "queued",
      "result": null,
      "error": null,
      "created_at": "2026-08-31T12:01:00Z",
      "updated_at": null,
      "completed_at": null
    }
  ],
  "pagination": {
    "next_cursor": null,
    "has_more": false
  }
}
Status When
200 Page returned
400 Cursor is invalid for this workspace or the active filters
401 Partner credential is missing or invalid
403 Credential lacks reports:read
404 Workspace does not exist or belongs to another partner
422 Limit, status, timestamp, header, or date range is invalid

To retrieve the latest completed report, request:

GET /v1/workspaces/{workspace_id}/visibility-reports?status=completed&limit=1

If data is empty, the workspace has no completed report.

Retrieve or poll one report

GET /v1/visibility-reports/{report_id}
Authorization: Bearer <partner-api-key>

Required scope: reports:read

Path parameter Type Description
report_id string Globally unique report ID returned when the report was launched

Example request:

curl \
  --url "$NBLICK_API_BASE_URL/v1/visibility-reports/pvr-8xR2kQpL_5jdHi6B-myT" \
  --header "Authorization: Bearer $NBLICK_PARTNER_API_KEY"

Response — 200 OK after completion:

{
  "id": "pvr-8xR2kQpL_5jdHi6B-myT",
  "workspace_id": "pws-V1StGXR8_Z5jdHi6B-myT",
  "status": "completed",
  "result": {
    "report": {
      "brand_name": "Customer",
      "url": "https://customer.example/",
      "category": "Remote hiring",
      "description": "A platform that helps companies hire remote professionals.",
      "visibility_score": 0.5,
      "ai_visibility_score": 50,
      "score_band": "good",
      "scoring_version": 2,
      "score_breakdown": {
        "mention_rate": {"value": 0.5, "weight": 0.4, "points": 20.0},
        "platform_coverage": {"value": 0.5, "weight": 0.2, "points": 10.0},
        "avg_rank": {"value": 0.5, "weight": 0.2, "points": 10.0},
        "sentiment": {"value": 0.5, "weight": 0.1, "points": 5.0},
        "competitive_gap": {"value": 0.5, "weight": 0.1, "points": 5.0}
      },
      "answers_analyzed": 2,
      "overall": {
        "visibility_pct": 0.5,
        "mean_reciprocal_rank": 0.5,
        "citation_share": 1.0,
        "sentiment_counts": {"positive": 1, "neutral": 0, "negative": 0},
        "mention_count": 1,
        "answers_analyzed": 2,
        "branded_answers": 0
      },
      "per_engine": {
        "openai": {
          "visibility_pct": 1.0,
          "mean_reciprocal_rank": 1.0,
          "citation_share": 1.0,
          "sentiment_counts": {"positive": 1, "neutral": 0, "negative": 0},
          "mention_count": 1,
          "answers_analyzed": 1,
          "branded_answers": 0
        },
        "gemini": {
          "visibility_pct": 0.0,
          "mean_reciprocal_rank": 0.0,
          "citation_share": null,
          "sentiment_counts": {"positive": 0, "neutral": 0, "negative": 0},
          "mention_count": 0,
          "answers_analyzed": 1,
          "branded_answers": 0
        }
      },
      "competitors": [
        {
          "name": "Competitor A",
          "category": "Remote hiring platform",
          "mention_count": 2,
          "visibility_pct": 1.0,
          "share_of_voice": 0.67,
          "mean_reciprocal_rank": 0.75
        },
        {
          "name": "Customer",
          "category": "Remote hiring platform",
          "mention_count": 1,
          "visibility_pct": 0.5,
          "share_of_voice": 0.33,
          "mean_reciprocal_rank": 0.5
        }
      ],
      "prompts": [
        {
          "text": "What is the best platform for hiring remote professionals?",
          "category": "recommendation",
          "responses": [
            {
              "engine": "openai",
              "model_id": "gpt-5-mini",
              "answer_text": "Customer and Competitor A are two options for hiring remote professionals.",
              "citations": [
                {
                  "url": "https://customer.example/remote-hiring",
                  "title": "Remote hiring",
                  "snippet": "Find remote professionals for your next project."
                }
              ]
            },
            {
              "engine": "gemini",
              "model_id": "gemini-2.5-flash",
              "answer_text": "Competitor A is a widely used option for remote hiring.",
              "citations": []
            }
          ]
        }
      ],
      "root_files": [
        {
          "name": "llms.txt",
          "url": "https://customer.example/llms.txt",
          "present": false,
          "status_code": 404,
          "content_type": "text/html",
          "size_bytes": 0,
          "error": null,
          "blocked_agents": []
        },
        {
          "name": "robots.txt",
          "url": "https://customer.example/robots.txt",
          "present": true,
          "status_code": 200,
          "content_type": "text/plain",
          "size_bytes": 284,
          "error": null,
          "blocked_agents": []
        }
      ]
    },
    "proposed_articles": [
      {
        "prompt_text": "best remote hiring platform",
        "category": "comparison",
        "impact": "high",
        "impact_score": 0.82,
        "competitors": ["Competitor A"],
        "engines_missing": 1,
        "engines_total": 2,
        "source": "observed"
      }
    ],
    "action_list": [
      {
        "id": "act-fG8kdE3yP0aX7sL2mN9qR",
        "workspace_id": "pws-V1StGXR8_Z5jdHi6B-myT",
        "report_id": "pvr-8xR2kQpL_5jdHi6B-myT",
        "type": "create_article",
        "status": "recommended",
        "priority": "high",
        "executable": true,
        "target_engines": ["gemini"],
        "title": "Publish a remote hiring comparison guide",
        "description": "Create a practical comparison page for remote hiring buyers.",
        "why_it_matters": "The brand is absent from high-intent comparison answers.",
        "expected_impact": "Improve future mentions and citation share.",
        "evidence": {},
        "payload": {
          "article_title": "How to choose a remote hiring platform",
          "category": "comparison",
          "language": "en",
          "word_range": "1500-2000",
          "additional_information": null,
          "prompt_ids": ["report:prompt:0"],
          "generate_images": true,
          "image_count": 2,
          "include_faq": true,
          "resource_urls": []
        },
        "first_recommended_at": "2026-08-31T12:07:00Z",
        "last_recommended_at": "2026-08-31T12:07:00Z",
        "created_at": "2026-08-31T12:07:00Z",
        "updated_at": null
      }
    ]
  },
  "error": null,
  "created_at": "2026-08-31T12:01:00Z",
  "updated_at": "2026-08-31T12:07:00Z",
  "completed_at": "2026-08-31T12:07:00Z"
}
Status When
200 Report returned in its current state
401 Partner credential is missing or invalid
403 Credential lacks reports:read
404 Report does not exist or belongs to another partner
422 Header validation fails

The report ID is globally unique, so this path does not include workspace_id. The response still includes workspace_id for association in the partner system.

Report response fields

Field Type Nullable Description
id string No Opaque report identifier
workspace_id string No Workspace analyzed by the report
status enum No queued, running, completed, or failed
result object Yes Populated only when status is completed
error string Yes Populated only when status is failed
created_at date-time No UTC creation timestamp
updated_at date-time Yes UTC timestamp of the last status or result update
completed_at date-time Yes Equal to updated_at only for a completed report

Completed result

Field Type Description
result.report object Typed visibility analysis
result.proposed_articles array Typed content opportunities
result.action_list array Actions in the same shape returned by the Actions API

result.report contains these fields:

Field Type Notes
brand_name string Brand identified from the website
url string URL analyzed
category string Brand category
description string Brand description
visibility_score number Weighted mention rate
ai_visibility_score integer Composite 0–100 score
score_band enum poor, fair, good, or excellent
scoring_version integer Compare scores within the same version
score_breakdown object or null mention_rate, platform_coverage, avg_rank, sentiment, and competitive_gap; each has value, weight, and points
answers_analyzed integer Number of answers behind the report
overall object Aggregate visibility scores
per_engine object Engine name to visibility scores
competitors array Competitor visibility rows
prompts array Prompts, responses, and citations used in the report
root_files array Root-file checks

overall and each per_engine value contain visibility_pct, mean_reciprocal_rank, citation_share, sentiment_counts, mention_count, answers_analyzed, and branded_answers.

Each competitors[] row contains:

Field Type Description
name string Brand or competitor name
category string Category assigned to the row
mention_count integer Number of analyzed answers that mentioned it
visibility_pct number Visibility rate
share_of_voice number Share of weighted visibility
mean_reciprocal_rank number or null Mean reciprocal rank across analyzed answers

The array can include the audited brand's own row so the partner can compare it with competitors.

Each prompts[] item contains text, a prompt category, and responses. Each response contains engine, model_id, answer_text, and citations. A citation requires url and can also contain nullable title and snippet.

Each root_files[] item contains:

Field Type Description
name string Checked filename
url string Checked root URL
present boolean Whether the expected root file was found
status_code integer or null HTTP status when available
content_type string or null Returned media type
size_bytes integer Response size
error string or null Request failure when one occurred
blocked_agents array of strings Known AI crawlers blocked by robots.txt

proposed_articles[] contains:

Field Type Values or meaning
prompt_text string Query worth addressing
category enum brand_discovery, category_discovery, recommendation, comparison, or buying_intent
impact enum high, medium, or low
impact_score number 0–1 opportunity score
competitors array of strings Competitors associated with the opportunity
engines_missing integer Answers that omitted the brand
engines_total integer Answers analyzed for the query
source enum observed or suggested

See Actions & Generated Content for the complete action shape and execution workflow.

Failed reports

A failed report remains retrievable with 200 OK:

{
  "id": "pvr-8xR2kQpL_5jdHi6B-myT",
  "workspace_id": "pws-V1StGXR8_Z5jdHi6B-myT",
  "status": "failed",
  "result": null,
  "error": "The visibility analysis could not be completed.",
  "created_at": "2026-08-31T12:01:00Z",
  "updated_at": "2026-08-31T12:05:00Z",
  "completed_at": null
}

A timed-out analysis uses:

The visibility analysis timed out before it could be completed.

An HTTP failure describes the API request. A report with status: "failed" describes the asynchronous run. Check both.