Skip to content

Quickstart

This walkthrough goes from a customer website to a completed visibility report and generated article.

Before you begin

You need:

  • the partner-specific API hostname supplied by nBlick;
  • a partner API key with workspaces:write, reports:write, reports:read, actions:write, and actions:read.

Add workspaces:read if the integration also lists or retrieves workspaces.

export NBLICK_API_BASE_URL="https://<partner-slug>.api.nblick.com"
export NBLICK_PARTNER_API_KEY="nbp_..."

Keep the API key in the partner backend. Do not expose it to browser or mobile clients.

1. Create or reuse a workspace

curl --request POST \
  --url "$NBLICK_API_BASE_URL/v1/workspaces" \
  --header "Authorization: Bearer $NBLICK_PARTNER_API_KEY" \
  --header "Content-Type: application/json" \
  --header "X-External-Actor-Id: operator-42" \
  --data '{
    "website": "https://customer.example",
    "models": [
      {"id": "openai", "enabled": true},
      {"id": "gemini", "enabled": true},
      {"id": "claude", "enabled": false}
    ]
  }'

Response — 201 Created:

{
  "id": "pws-V1StGXR8_Z5jdHi6B-myT",
  "website": "https://customer.example/",
  "status": "active",
  "models": [
    {"id": "openai", "enabled": true},
    {"id": "gemini", "enabled": true},
    {"id": "claude", "enabled": false}
  ],
  "created_at": "2026-08-31T12:00:00Z",
  "updated_at": null
}

Save the workspace ID. Repeating the canonical website returns the same workspace and preserves its original model selection.

export WORKSPACE_ID="pws-V1StGXR8_Z5jdHi6B-myT"

2. Launch a visibility report

The request has no JSON body.

curl --request POST \
  --url "$NBLICK_API_BASE_URL/v1/workspaces/$WORKSPACE_ID/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
}
export REPORT_ID="pvr-8xR2kQpL_5jdHi6B-myT"

Reuse the same Idempotency-Key only when retrying this logical run. Once a report exists, the key always returns that report, including if it later fails.

3. Poll the report

curl \
  --url "$NBLICK_API_BASE_URL/v1/visibility-reports/$REPORT_ID" \
  --header "Authorization: Bearer $NBLICK_PARTNER_API_KEY"

Continue while status is queued or running. Stop when it is completed or failed.

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": []
    },
    "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"
}

Save the action ID for an action whose executable field is true.

export ACTION_ID="act-fG8kdE3yP0aX7sL2mN9qR"

4. Launch content generation

Executing without a body uses the action payload exactly. This example changes the title and adds one reference URL for this attempt.

curl --request POST \
  --url "$NBLICK_API_BASE_URL/v1/actions/$ACTION_ID/executions" \
  --header "Authorization: Bearer $NBLICK_PARTNER_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "payload_override": {
      "article_title": "A practical guide to choosing a remote hiring platform",
      "resource_urls": ["https://customer.example/remote-hiring"]
    }
  }'

Response — 202 Accepted:

{
  "id": "aex-P6vB2nQ8rD4kW1yH7cM5t",
  "action_id": "act-fG8kdE3yP0aX7sL2mN9qR",
  "status": "running",
  "attempt": 1,
  "output_type": "article",
  "output_id": "art-K9sD3fL6qT1vN8wC4xR2p",
  "output_url": null,
  "error": null,
  "created_at": "2026-08-31T12:10:00Z",
  "started_at": "2026-08-31T12:10:01Z",
  "completed_at": null,
  "updated_at": "2026-08-31T12:10:01Z"
}
export EXECUTION_ID="aex-P6vB2nQ8rD4kW1yH7cM5t"

A successful launch normally returns running. The execution lifecycle also includes queued before generation starts.

5. Poll the action execution

curl \
  --url "$NBLICK_API_BASE_URL/v1/action-executions/$EXECUTION_ID" \
  --header "Authorization: Bearer $NBLICK_PARTNER_API_KEY"

Continue while status is queued or running. Stop when it is succeeded or failed.

Response — 200 OK after success:

{
  "id": "aex-P6vB2nQ8rD4kW1yH7cM5t",
  "action_id": "act-fG8kdE3yP0aX7sL2mN9qR",
  "status": "succeeded",
  "attempt": 1,
  "output_type": "article",
  "output_id": "art-K9sD3fL6qT1vN8wC4xR2p",
  "output_url": "/v1/action-executions/aex-P6vB2nQ8rD4kW1yH7cM5t/output",
  "error": null,
  "created_at": "2026-08-31T12:10:00Z",
  "started_at": "2026-08-31T12:10:01Z",
  "completed_at": "2026-08-31T12:13:00Z",
  "updated_at": "2026-08-31T12:13:00Z"
}

6. Retrieve the generated article

curl \
  --url "$NBLICK_API_BASE_URL/v1/action-executions/$EXECUTION_ID/output" \
  --header "Authorization: Bearer $NBLICK_PARTNER_API_KEY"

Response — 200 OK:

{
  "output_type": "article",
  "output": {
    "id": "art-K9sD3fL6qT1vN8wC4xR2p",
    "status": "completed",
    "article_title": "A practical guide to choosing a remote hiring platform",
    "language": "en",
    "category": "comparison",
    "meta_title": "How to choose a remote hiring platform",
    "meta_description": "Compare the capabilities that matter when hiring remote professionals.",
    "slug": "choose-remote-hiring-platform",
    "content": "# How to choose a remote hiring platform\n\nStart with the roles, skills, and engagement model your team needs...",
    "images": [
      {
        "url": "https://partner.api.nblick.com/v1/action-executions/aex-P6vB2nQ8rD4kW1yH7cM5t/output/images/0?expires=1788179400&signature=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
        "mime_type": "image/webp",
        "alt_text": "A distributed team reviewing remote candidates",
        "caption": "Evaluate remote hiring platforms against your workflow.",
        "section_hint": "after_intro",
        "width": 1200,
        "height": 630,
        "is_placeholder": false
      }
    ],
    "article_plan": null,
    "sources": [
      {
        "title": "Remote hiring",
        "url": "https://customer.example/remote-hiring"
      }
    ],
    "created_at": "2026-08-31T12:10:01Z",
    "updated_at": "2026-08-31T12:13:00Z"
  }
}

7. Download article images

Use each images[].url exactly as returned. It is short-lived and already signed, so do not add the bearer API key.

curl \
  --output "remote-hiring.webp" \
  "https://partner.api.nblick.com/v1/action-executions/aex-P6vB2nQ8rD4kW1yH7cM5t/output/images/0?expires=1788179400&signature=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"

If the URL has expired, retrieve the generated output again for a fresh URL. To regenerate or replace an existing article image, follow Generate or replace an article image.

Next steps