Question Endpoint

Question Endpoint

Ask a question against your Context Link and receive a short paragraph answer with citations. Unlike the context endpoint (which returns the raw matching chunks), this endpoint runs retrieval then passes the context to a small LLM that composes a single concise response grounded in your sources.

Pro plan: this endpoint is available on Pro plans only. Requests from non-Pro accounts return 402 Payment Required.

How to invoke it

From an AI assistant (skill-driven)

With the ask-question skill installed, these phrases trigger it automatically:

  • "ask context link what our refund policy is"
  • "ask my docs when onboarding changed"
  • "use context link to answer: …"
  • "what does my knowledge base say about …"

In Claude Code specifically, the slash command /ask-question also invokes the skill directly.

Download the skill on the Installation page for Claude Chat, Claude Cowork, or Codex.

Two ways to call the endpoint directly

1. Via your Context Link subdomain (simplest, paste into any AI chat):

https://YOUR-SUBDOMAIN.context-link.ai/q/what-is-pricing?p=YOUR_PIN
https://YOUR-SUBDOMAIN.context-link.ai/question/what-is-pricing?p=YOUR_PIN

Both paths hit the same endpoint. Use dashes-for-spaces in the question slug. Response negotiates on Accept (defaults to HTML for ChatGPT / Gemini user agents, JSON or Markdown otherwise).

2. Via the authenticated API (for servers and integrations):

GET /api/v1/question?query=what-is-pricing

Quick reference

Property Value
Endpoint GET /api/v1/question
Authentication API key via Authorization header
Rate limit 2 requests per 10 seconds
Monthly cap Counts against your Pro LLM allowance (1,000 requests/month, shared across LLM-powered features)
Response format JSON
Cache duration 1 hour per unique query + mode combination

Parameters

Parameter Type Required Description
query string Yes The question to ask. Dashes and underscores are converted to spaces.
mode string No Optional mode name to weight results (e.g. customer-support).

Status codes

Code Description
200 Answer returned (may be no_context when nothing relevant was found)
400 Query parameter is missing
401 API key is missing or subscription required
402 Pro plan required
404 API key is invalid
429 Rate limit exceeded, or monthly LLM allowance exceeded
503 LLM service temporarily unavailable, retry

Examples

Basic usage

curl -X GET "https://context-link.ai/api/v1/question?query=what-is-our-refund-policy" \
     -H "Authorization: your-api-key-here"

Response:

{
    "result": "ok",
    "answer": "Our refund policy allows full refunds within 30 days of purchase, no questions asked [1]. Refunds are processed back to the original payment method within 5 business days [2].",
    "citations": [
        { "n": 1, "title": "Refund policy", "url": "https://example.com/refunds" },
        { "n": 2, "title": "Billing operations SOP", "url": "https://notion.so/..." }
    ],
    "format": "markdown"
}

No context found

When the query doesn't match any indexed content, result is "no_context" and answer is null:

{
    "result": "no_context",
    "answer": null,
    "citations": [],
    "format": "markdown"
}

LLM temporarily unavailable

If the upstream LLM call fails after retries, the endpoint returns HTTP 503 with:

{
    "result": "llm_unavailable",
    "answer": null,
    "citations": [],
    "format": "markdown"
}

This is distinct from no_context so callers can retry rather than telling the end user "nothing found."

With mode

curl -X GET "https://context-link.ai/api/v1/question?query=onboarding-checklist&mode=customer-support" \
     -H "Authorization: your-api-key-here"

Python example

import requests

api_key = "your-api-key-here"
response = requests.get(
    "https://context-link.ai/api/v1/question",
    params={"query": "what are our office hours"},
    headers={"Authorization": api_key}
)
data = response.json()
print(data["answer"])
for c in data["citations"]:
    print(f"[{c['n']}] {c['title']}: {c['url']}")

JavaScript example

const axios = require('axios');

axios.get('https://context-link.ai/api/v1/question', {
    params: { query: 'what are our office hours' },
    headers: { 'Authorization': 'your-api-key-here' }
}).then(r => {
    console.log(r.data.answer);
    r.data.citations.forEach(c => console.log(`[${c.n}] ${c.title}: ${c.url}`));
});

Ruby example

require 'net/http'
require 'json'
require 'uri'

uri = URI('https://context-link.ai/api/v1/question')
uri.query = URI.encode_www_form(query: 'what are our office hours')

req = Net::HTTP::Get.new(uri)
req['Authorization'] = 'your-api-key-here'

res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)
puts data['answer']

Subdomain form (details)

The /q/{question} and /question/{question} paths both hit the same endpoint on your subdomain. Use whichever reads better in context:

# JSON
curl -H "Accept: application/json" \
     "https://YOUR-SUBDOMAIN.context-link.ai/q/what-is-pricing?p=YOUR_PIN"

# Markdown (for pasting into docs)
curl -H "Accept: text/markdown" \
     "https://YOUR-SUBDOMAIN.context-link.ai/q/what-is-pricing?p=YOUR_PIN"

# Plain text (just the answer, no citations footer)
curl -H "Accept: text/plain" \
     "https://YOUR-SUBDOMAIN.context-link.ai/q/what-is-pricing?p=YOUR_PIN"

If you omit the Accept header and you're on ChatGPT or Gemini, you'll get HTML by default (they render Markdown poorly). All other agents get JSON.

Response format

{
    "result": "ok" | "no_context" | "llm_unavailable",
    "answer": "paragraph with inline [1] citations" | null,
    "citations": [{ "n": 1, "title": "...", "url": "..." }],
    "format": "markdown"
}
  • result:
    • "ok": an answer was produced from your context.
    • "no_context": no relevant source material was found (HTTP 200). Don't retry.
    • "llm_unavailable": retrieval succeeded but the LLM call failed (HTTP 503). Retry.
  • answer: a single paragraph (≤ ~120 words), with inline [N] markers referencing the citations array. null when result is "no_context" or "llm_unavailable".
  • citations: only the sources the LLM actually used to compose the answer. Citation numbers are contiguous ([1], [2], [3] ...) and always resolve to an entry in this array.

Error responses

// 400 Bad Request
{ "message": "A query is required" }

// 402 Payment Required
{ "message": "The question endpoint is a Pro-plan feature." }

// 429 Too Many Requests (allowance)
{ "message": "Monthly question allowance exceeded. Resets at the start of next month." }

// 503 Service Unavailable
{ "result": "llm_unavailable", "answer": null, "citations": [], "format": "markdown" }