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

# Twitter news monitoring API to classify posts

> Classify news posts on X with AI: reporting, commentary, or rumor, the source attribution, and the relevance to your topic. 2 credits per analyzed post.

<Panel>
  <Tabs defaultTabIndex={0} sync={false}>
    <Tab title="200" id="response-x-news-classification-200">
      ```json theme={null}
      {
        "results": [
          {
            "tweet": {
              "id": "1893456789012345678",
              "text": "The new headphones sound great. The app keeps crashing.",
              "retweetCount": 4,
              "replyCount": 2,
              "likeCount": 31
            },
            "analysis": {
              "status": "succeeded",
              "answers": [
                {
                  "questionId": "sentiment",
                  "questionVersion": "sentiment:2",
                  "type": "choice",
                  "value": "mixed",
                  "confidence": 0.88
                }
              ],
              "questions": [
                {
                  "id": "sentiment",
                  "version": "sentiment:2"
                }
              ],
              "contextBytes": 612,
              "contextAvailability": {
                "quote": "not_applicable",
                "reply": "not_applicable",
                "author": "available",
                "media": "not_supplied",
                "article": "not_supplied"
              }
            },
            "answers": {
              "sentiment": "mixed",
              "intensity": 1,
              "sarcasm": 0.03
            },
            "sourceDomains": [],
            "cashtags": []
          }
        ],
        "unanalyzed": [
          {
            "id": "1893456789012345679",
            "status": "skipped",
            "reason": "post_unavailable"
          }
        ],
        "analysisSummary": {
          "schemaVersion": 1,
          "rows": {
            "analyzed": 1,
            "failed": 0,
            "skipped": 0
          },
          "engagement": 37,
          "questions": {
            "sentiment": {
              "type": "choice",
              "counts": {
                "positive": 0,
                "negative": 0,
                "mixed": 1,
                "neutral": 0,
                "unclear": 0
              },
              "shares": {
                "positive": 0,
                "negative": 0,
                "mixed": 1,
                "neutral": 0,
                "unclear": 0
              }
            }
          },
          "targets": []
        },
        "has_next_page": false,
        "next_cursor": ""
      }
      ```
    </Tab>

    <Tab title="400" id="response-x-news-classification-400">
      ```json theme={null}
      {
        "error": "invalid_input",
        "message": "Invalid input. Check the request body."
      }
      ```
    </Tab>

    <Tab title="401" id="response-x-news-classification-401">
      ```json theme={null}
      {
        "error": "unauthenticated",
        "message": "Authentication required."
      }
      ```
    </Tab>

    <Tab title="402" id="response-x-news-classification-402">
      ```json theme={null}
      {
        "error": "insufficient_credits",
        "message": "Insufficient credits. Top up or subscribe to continue."
      }
      ```
    </Tab>

    <Tab title="403" id="response-x-news-classification-403">
      ```json theme={null}
      {
        "error": "x_account_protected",
        "message": "Account is protected. Choose a public account."
      }
      ```
    </Tab>

    <Tab title="424" id="response-x-news-classification-424">
      ```json theme={null}
      {
        "error": "x_api_unavailable",
        "message": "X data source temporarily unavailable. Try again later."
      }
      ```
    </Tab>

    <Tab title="429" id="response-x-news-classification-429">
      ```json theme={null}
      {
        "error": "rate_limit_exceeded",
        "message": "Too many requests. Try again later.",
        "retryAfter": 60
      }
      ```
    </Tab>

    <Tab title="502" id="response-x-news-classification-502">
      ```json theme={null}
      {
        "error": "x_api_unavailable",
        "message": "X data source temporarily unavailable. Try again later."
      }
      ```
    </Tab>

    <Tab title="503" id="response-x-news-classification-503">
      ```json theme={null}
      {
        "error": "x_api_unavailable",
        "message": "Xquik is busy right now. Retry shortly."
      }
      ```
    </Tab>
  </Tabs>
</Panel>

<blockquote className="agent-llms-directive">
  For the complete documentation index, see <a href="/llms.txt">llms.txt</a>.
</blockquote>

<Callout icon="coins" color="#5c3327">
  **2 credits per analyzed post** · [All plans](https://xquik.com/#pricing) from \$0.00012/credit · Supports [guest paid reads](/guides/guest-wallets)
</Callout>

News classification reads each post with AI and answers 3 questions about your
topic. The endpoint is `POST /api/v1/x/analysis/news`.

| Answer | Type | Values |
| - | - | - |
| `format` | Choice | `reporting`, `commentary`, `speculation`, `promotion`, `satire`, `unrelated`, or `unclear` |
| `attribution` | Choice | `named`, `linked`, `firsthand`, `absent`, or `unclear` |
| `relevance` | Probability | From `0` to `1`, the chance the post concerns your topic |

Name the topic in `analysis.targets`. The answers classify what a post says.
They do not check whether its claims are true.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://xquik.com/api/v1/x/analysis/news \
    -H "x-api-key: xq_your_api_key_here" \
    -H "Content-Type: application/json" \
    -d '{
      "query": "(Artemis OR SLS OR Orion) NASA lang:en -filter:nativeretweets",
      "limit": 50,
      "analysis": {
        "targets": [{ "name": "Artemis program", "aliases": ["Artemis II", "SLS", "Orion"] }]
      }
    }' | jq
  ```

  ```javascript Node.js theme={null}
  const response = await fetch("https://xquik.com/api/v1/x/analysis/news", {
    method: "POST",
    headers: {
      "x-api-key": "xq_your_api_key_here",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      query: "(Artemis OR SLS OR Orion) NASA lang:en -filter:nativeretweets",
      limit: 50,
      analysis: {
        targets: [{ name: "Artemis program", aliases: ["Artemis II", "SLS", "Orion"] }],
      },
    }),
  });
  const data = await response.json();
  if (!response.ok) throw new Error(`${data.error}: ${data.message}`);

  const sourcedReports = data.results
    .filter((result) => result.answers.relevance >= 0.5)
    .filter((result) => result.answers.format === "reporting")
    .filter((result) => ["named", "linked"].includes(result.answers.attribution))
    .map((result) => ({
      tweet_id: result.tweet.id,
      text: result.tweet.text,
      sources: result.sourceDomains,
    }));
  const topSources = data.analysisSummary.sourceDomains.slice(0, 5);

  process.stdout.write(`${JSON.stringify({ reports: sourcedReports.length, topSources })}\n`);
  ```

  ```python Python theme={null}
  import json
  import requests

  response = requests.post(
      "https://xquik.com/api/v1/x/analysis/news",
      headers={"x-api-key": "xq_your_api_key_here"},
      json={
          "query": "(Artemis OR SLS OR Orion) NASA lang:en -filter:nativeretweets",
          "limit": 50,
          "analysis": {
              "targets": [{"name": "Artemis program", "aliases": ["Artemis II", "SLS", "Orion"]}],
          },
      },
      timeout=120,
  )
  data = response.json()
  if not response.ok:
      raise RuntimeError(f"{data['error']}: {data['message']}")

  sourced_reports = [
      {
          "tweet_id": result["tweet"]["id"],
          "text": result["tweet"]["text"],
          "sources": result["sourceDomains"],
      }
      for result in data["results"]
      if result["answers"]["relevance"] >= 0.5
      and result["answers"]["format"] == "reporting"
      and result["answers"]["attribution"] in ("named", "linked")
  ]
  top_sources = data["analysisSummary"]["sourceDomains"][:5]
  print(json.dumps({"reports": len(sourced_reports), "top_sources": top_sources}))
  ```
</CodeGroup>

The snippets keep relevant reports that cite a source, then print the most
linked sites. They do not print the full response.

## Name the topic

Put the topic in `analysis.targets`, with its other names as aliases. A topic
can be an event, a company, a person, a ticker, or a product.

```json theme={null}
{ "name": "Artemis program", "aliases": ["Artemis II", "SLS", "Orion"] }
```

`relevance` is high only when the post names the topic or reports an event
about it. Posts about the same industry, competitors, or the wider market do
not count. Filter rows on `relevance` before you count answers.

## Read the news answers

`results[].answers` holds each decision by question ID.

| `format` | Meaning |
| - | - |
| `reporting` | Reports a specific event or announcement |
| `commentary` | Opinion or interpretation of events |
| `speculation` | An uncertain prediction or a rumor |
| `promotion` | Advertising or promotional content |
| `satire` | Parody or satire |
| `unrelated` | Not about the topic |
| `unclear` | Not enough context |

| `attribution` | Meaning |
| - | - |
| `named` | Names the source, such as an outlet, a report, or a quoted person |
| `linked` | Links to a source without naming it |
| `firsthand` | The author reports their own observation or announcement |
| `absent` | Gives no source for its claims |
| `unclear` | Attribution cannot be determined |

`attribution` says whether a source is given. It does not rate the source.

## Separate reports from rumors

Keep `reporting` with `named` or `linked` attribution for sourced news. Watch
`speculation` with `absent` attribution for rumors that spread without a
source.

`analysisSummary.questions.format.shares` holds each format's share of posts.
Store it per run to see when speculation outgrows reporting.

## Track the sources

`results[].sourceDomains` lists the sites each post links to. The summary's
`sourceDomains` counts posts per site, most posts first, up to 20.

For more posts than 1 call returns, send the same body again with `cursor` set
to `next_cursor`. Add `sinceTime` and `untilTime` to read 1 day or 1 hour.

```json theme={null}
{
  "query": "Artemis II",
  "sinceTime": "2026-09-25T00:00:00Z",
  "untilTime": "2026-09-26T00:00:00Z",
  "analysis": { "targets": [{ "name": "Artemis program" }] }
}
```

## Pick the posts to analyze

Send `tweetIds`, `texts`, or a search, never more than 1. Sending none, or more
than 1, returns `400 invalid_input`.

| Source | Send | Posts analyzed |
| - | - | - |
| Post IDs | `tweetIds`, up to 100 post IDs or post URLs | Each post once |
| Your own texts | `texts`, up to 100 strings | Each text. Reads nothing from X |
| A search | 1 or more of the search fields below | Up to `limit` posts, 20 by default |

A search combines every search field you send into 1 X search.

| Search field | Posts it finds |
| - | - |
| `query` | An X search, with the operators of [Search Tweets](/api-reference/x/search-tweets) |
| `username` | 1 account's posts. A handle, `@handle`, or profile URL |
| `listId` | A public List's posts. A List ID or URL |
| `quotesOf` | The quotes of 1 post. A post ID or URL |
| `repliesTo` | The replies in 1 post's conversation. A post ID or URL |
| `sinceTime` & `untilTime` | Posts between 2 times. An ISO 8601 time or Unix seconds |

`queryType` sets the order, `Latest` or `Top`. For more posts than 1 call
returns, send the same search again with `cursor` set to `next_cursor`. Stop
when `has_next_page` is `false`.

```json theme={null}
{
  "username": "NASA",
  "sinceTime": "2026-09-25T00:00:00Z",
  "untilTime": "2026-09-26T00:00:00Z"
}
```

## Compare with an earlier answer

Send the `results` of an earlier call as `baseline` to see what changed. Each
row in the new `results` gets `monitor`, and `analysisSummary.monitor` counts
the posts per status. The comparison costs nothing extra.

```json theme={null}
{
  "query": "Sony WH-1000XM6 lang:en",
  "baseline": [
    { "id": "1893456789012345678", "answers": { "sentiment": "positive", "intensity": 1.2 } }
  ]
}
```

A baseline row needs the post's `id`, or `tweet.id`, and its `answers`. Send
whole result rows when you have them. Their `monitor` carries the settings'
fingerprint, so rows from other settings show as `not_comparable`.

| `monitor.status` | Meaning |
| - | - |
| `first_run` | You sent no baseline |
| `new_to_baseline` | The baseline has no row for this post |
| `unchanged` | Every decision matches the baseline |
| `changed` | At least 1 decision clearly moved. `changes` lists each 1 |
| `not_comparable` | Other settings made the row, or it answers none of these questions |

A decision counts as changed only when the new answer clearly leaves the old
one, so near ties between calls stay `unchanged`. Keep `analysis` the same
between calls for comparable answers.

## Budget the analysis

Each analyzed post costs 2 credits. Each text in `texts` costs the same. Posts
in `unanalyzed` cost nothing.

When credits cover fewer posts than you asked for, fewer come back. The posts
left over appear in `unanalyzed` with `insufficient_credits`. If credits cover
no post, the call returns `402 insufficient_credits`.

| `unanalyzed[].reason` | Meaning | What to do |
| - | - | - |
| `post_unavailable` | X returns no such post | Skip the post |
| `missing_text` | The post has no text | Skip the post |
| `insufficient_credits` | Credits ran out | Add credits, then send it again |
| `context_limit` | The settings leave the post no room | Shorten the context or questions |
| Any other reason | The analysis failed (`status: "failed"`) | Send the post again |

## Body

<ParamField body="tweetIds" type="string[]">
  Up to 100 post IDs or post URLs, such as `x.com/nasa/status/20`. A post named
  twice is analyzed once. Send `tweetIds`, `texts`, or a search, not more than 1.
</ParamField>

<ParamField body="query" type="string">
  X search to analyze, with the operators of [Search Tweets](/api-reference/x/search-tweets).
</ParamField>

<ParamField body="username" type="string">
  Analyze 1 account's posts. Send a handle, with or without `@`, or a profile URL.
</ParamField>

<ParamField body="listId" type="string">
  Analyze a public List's posts. Send its ID or URL.
</ParamField>

<ParamField body="quotesOf" type="string">
  Analyze the quotes of 1 post. Send its ID or URL.
</ParamField>

<ParamField body="repliesTo" type="string">
  Analyze the replies in 1 post's conversation. Send its ID or URL.
</ParamField>

<ParamField body="sinceTime" type="string">
  Inclusive start of the search, such as `2026-09-25T00:00:00Z`. Unix seconds
  also work. A time without an offset is UTC.
</ParamField>

<ParamField body="untilTime" type="string">
  Exclusive end of the search. Unix seconds also work. A time without an offset
  is UTC.
</ParamField>

<ParamField body="queryType" type="string">
  Search order: `Latest` or `Top`. Defaults to `Latest`.
</ParamField>

<ParamField body="limit" type="integer">
  Maximum posts to analyze from the search. Range: `1-100`. Defaults to `20`.
  Credits can return fewer.
</ParamField>

<ParamField body="cursor" type="string">
  The `next_cursor` of the page before. Send the same search with it.
</ParamField>

<ParamField body="texts" type="string[]">
  Up to 100 texts of your own, such as drafts. Each must contain words. Reads
  nothing from X.
</ParamField>

<ParamField body="baseline" type="object[]">
  Rows of an earlier answer to compare with, up to 10,000, such as its
  `results`. Each needs the post's `id`, or `tweet.id`, and its `answers`. Each
  new result's `monitor` says whether the post is new, changed, or unchanged.
  The comparison costs nothing extra.
</ParamField>

<ParamField body="analysis" type="object">
  Optional settings. Leave it out to ask the route's own questions.

  <Expandable title="Analysis fields">
    <ParamField body="targets" type="object[]">
      Up to 100 brands, people, assets, or topics the questions are about. Each
      has a `name` and optional `aliases`, such as a ticker or product name.
    </ParamField>

    <ParamField body="context" type="string">
      Background the AI reads with every post, such as your product or market.
    </ParamField>

    <ParamField body="questions" type="object[]">
      1 to 8 questions of your own, which replace the route's questions. Each
      needs an `id`, a `type` of `choice`, `score`, or `probability`, a
      `version`, and `instructions`. A choice adds `categories`, a score adds
      `levels`, and a probability can add `criteria`.
    </ParamField>

    <ParamField body="preset" type="string">
      A ready set of questions, used when `questions` is left out: `brand`,
      `complaints`, `competitors`, `purchase_intent`, `product_feedback`,
      `news`, `sentiment`, or `market`. `complaints`, `competitors`,
      `purchase_intent`, and `product_feedback` need `targets`.
    </ParamField>

    <ParamField body="maxContextBytes" type="integer">
      Bytes of post, quote, and settings the AI reads. Range: `1-64000`.
      Defaults to `64000`. Xquik cuts a longer post to fit.
    </ParamField>

    <ParamField body="concurrency" type="integer">
      Posts analyzed at the same time. Range: `1-16`. Defaults to `16`.
    </ParamField>
  </Expandable>
</ParamField>

## Headers

<ParamField header="x-api-key" type="string">
  Full account API key. An OAuth bearer token also works.
</ParamField>

<ParamField header="Authorization" type="string">
  Send `Bearer xq_your_guest_key_here` for an active `paid_reads` guest key.
</ParamField>

<ParamField header="Content-Type" type="string" required>
  Must be `application/json`. The body can be up to 256 KB.
</ParamField>

## Response

### 200 OK

<ResponseField name="results" type="object[]">
  Each analyzed post with its answers. Each row costs 2 credits.

  <Expandable title="Result fields">
    <ResponseField name="tweet" type="object">
      The post, as [Search Tweets](/api-reference/x/search-tweets) returns it. Your own texts have the IDs `text:1`, `text:2`, and so on.
    </ResponseField>

    <ResponseField name="answers" type="object">
      Each decision by question ID. `format` and `attribution` are categories, and `relevance` a probability from `0` to `1`.
    </ResponseField>

    <ResponseField name="analysis" type="object">
      The answers in full. `status` is `succeeded`. `answers` gives each answer's `value`, `confidence`, and `probabilities`, or a `probability`. `questions` names the ID and version of each question. `contextBytes` and `contextAvailability` say what the AI read beside the post's text.
    </ResponseField>

    <ResponseField name="sourceDomains" type="string[]">
      Hostnames the post links to, without `t.co`.
    </ResponseField>

    <ResponseField name="cashtags" type="string[]">
      Cashtags in the post's text, in upper case.
    </ResponseField>

    <ResponseField name="monitor" type="object">
      The comparison with `baseline`: `status`, `changedQuestionIds`, `changes` with each `previous` and `current` decision, and the settings' `configurationFingerprint`.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="unanalyzed" type="object[]">
  Each post without an analysis. These cost nothing.

  <Expandable title="Unanalyzed fields">
    <ResponseField name="id" type="string">
      Post ID, or `text:1` and so on for your own texts.
    </ResponseField>

    <ResponseField name="status" type="string">
      `skipped` or `failed`.
    </ResponseField>

    <ResponseField name="reason" type="string">
      `post_unavailable`, `missing_text`, `insufficient_credits`, or `context_limit`. Any other reason means the analysis failed. Send the post again.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="analysisSummary" type="object">
  Totals of the answers across the analyzed posts.

  <Expandable title="Summary fields">
    <ResponseField name="schemaVersion" type="integer">
      Version of the summary's shape.
    </ResponseField>

    <ResponseField name="rows" type="object">
      Posts by outcome: `analyzed`, `failed`, and `skipped`.
    </ResponseField>

    <ResponseField name="engagement" type="integer">
      Likes, reposts, replies, and quotes of the analyzed posts.
    </ResponseField>

    <ResponseField name="questions" type="object">
      Totals by question ID. `format` and `attribution` have `counts`, `shares`, `engagementShares`, and `top` posts per category. `relevance` has `mean`, `yes`, and `no`.
    </ResponseField>

    <ResponseField name="targets" type="object[]">
      Per target in `analysis.targets`: `name`, `mentions`, `share`, `engagement`, `choices`, and `top` posts.
    </ResponseField>

    <ResponseField name="cashtags" type="object[]">
      Posts and category counts per cashtag, most posts first, up to 20.
    </ResponseField>

    <ResponseField name="sourceDomains" type="object[]">
      Posts per linked hostname, most posts first, up to 20.
    </ResponseField>

    <ResponseField name="monitor" type="object">
      Posts per `monitor.status` in `statuses`, and up to 50 changed posts in `changedRows`.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="has_next_page" type="boolean">Whether the search has more posts. Always `false` for `tweetIds` and `texts`.</ResponseField>
<ResponseField name="next_cursor" type="string">Send it as `cursor` with the same search for the next page. Empty when there is none.</ResponseField>

```json theme={null}
{
  "results": [
    {
      "tweet": {
        "id": "1893456789012345678",
        "text": "NASA confirms the Artemis II crew will fly in April, per today's briefing. nasa.gov/artemis",
        "likeCount": 512,
        "retweetCount": 88,
        "replyCount": 40
      },
      "analysis": {
        "status": "succeeded",
        "answers": [
          {
            "questionId": "format",
            "questionVersion": "news:3",
            "type": "choice",
            "value": "reporting",
            "confidence": 0.94,
            "probabilities": {
              "reporting": 0.94,
              "commentary": 0.02,
              "speculation": 0.02,
              "promotion": 0.01,
              "satire": 0,
              "unrelated": 0,
              "unclear": 0.01
            }
          },
          {
            "questionId": "attribution",
            "questionVersion": "news:3",
            "type": "choice",
            "value": "named",
            "confidence": 0.9,
            "probabilities": {
              "named": 0.9,
              "linked": 0.07,
              "firsthand": 0.01,
              "absent": 0.01,
              "unclear": 0.01
            }
          },
          {
            "questionId": "relevance",
            "questionVersion": "news:3",
            "type": "probability",
            "probability": 0.99
          }
        ]
      },
      "answers": { "format": "reporting", "attribution": "named", "relevance": 0.99 },
      "sourceDomains": ["nasa.gov"],
      "cashtags": []
    }
  ],
  "unanalyzed": [],
  "analysisSummary": {
    "schemaVersion": 1,
    "rows": { "analyzed": 1, "failed": 0, "skipped": 0 },
    "engagement": 640,
    "questions": {
      "format": {
        "type": "choice",
        "counts": {
          "reporting": 1,
          "commentary": 0,
          "speculation": 0,
          "promotion": 0,
          "satire": 0,
          "unrelated": 0,
          "unclear": 0
        }
      }
    },
    "targets": [
      {
        "name": "Artemis program",
        "mentions": 1,
        "share": 1,
        "engagement": 640,
        "choices": { "format": { "reporting": 1 }, "attribution": { "named": 1 } },
        "top": {
          "format": { "reporting": [{ "tweetId": "1893456789012345678", "engagement": 640 }] }
        }
      }
    ],
    "cashtags": [],
    "sourceDomains": [{ "domain": "nasa.gov", "posts": 1 }]
  },
  "has_next_page": false,
  "next_cursor": ""
}
```

### 400 Invalid input

```json theme={null}
{
  "error": "invalid_input",
  "message": "Send tweetIds, texts, or a search such as query or username."
}
```

The body names no posts, names more than 1 source, or has an invalid field.
The message says what to send instead. The request costs nothing.

### 401 Unauthenticated

Anonymous requests get `WWW-Authenticate: Bearer` and a guest wallet checkout action. This is not a Payment challenge.

```json theme={null}
{ "error": "unauthenticated" }
```

Missing or invalid API key. Check the `x-api-key` header value.

### 402 Payment required

Full account keys can receive `no_subscription`, `subscription_inactive`, `no_credits`, or `insufficient_credits` with account payment options. Guest keys receive only the guest top-up action.

The failed request creates no checkout. Ask the user to confirm before calling any checkout or top-up route.

### 403 Protected account

```json theme={null}
{ "error": "x_account_protected" }
```

A search that needs a protected author returns this. Choose a public account.
The request costs nothing.

### 502 X API unavailable

```json theme={null}
{ "error": "x_api_unavailable" }
```

The read service returned an error. Retry after a short delay.

### 503 Service busy

```json theme={null}
{ "error": "x_api_unavailable" }
```

Xquik is busy. Wait for the `Retry-After` header, then send the request again.
The request costs nothing.

### 429 Rate limit exceeded

```json theme={null}
{ "error": "rate_limit_exceeded", "retryAfter": 60 }
```

You exceeded your tier rate limit. Wait for the `Retry-After` header before retrying.

### 424 Dependency failed

```json theme={null}
{ "error": "x_api_unavailable" }
```

The normalized v1 response contract can return 424 when the read service is unavailable.

## News monitoring API questions

### How do I monitor news about a topic on X?

Search the topic in `query` and name it in `analysis.targets`. Each row in
`results` holds the post's `format`, `attribution`, and `relevance`.

### Does it check whether a post is true?

No. The answers say what kind of post it is and whether it names a source.
They do not verify claims or rate the source.

### How do I find rumors?

Keep rows whose `format` is `speculation`. Rows with `absent` attribution give
no source for their claims.

### Can I follow 1 outlet or reporter?

Yes. Send their handle in `username`, and name your topic in
`analysis.targets`.

### How much does news classification cost?

Each analyzed post costs 2 credits. Posts in `unanalyzed` and refused requests
cost nothing.

### Does this replace X's official API?

No. This page documents Xquik, an independent third-party service.
It does not document X's official API.

<Note>
  **Next steps.** [Market signals](/api-reference/x/market-signals) reads stock and crypto stances, or [Classify posts](/api-reference/x/classify-tweets) asks your own questions.
</Note>

<div className="related-api-links">
  <Accordion title="Related tweet, reply & media APIs" icon="link">
    * Tweets: [Get tweet](/api-reference/x/get-tweet) · [Batch tweets](/api-reference/x/batch-tweets) · [Tweet thread](/api-reference/x/tweet-thread) · [Hidden replies](/api-reference/x/tweet-hidden-replies) · [Translate tweet](/api-reference/x/tweet-translation) · [Embed tweet](/api-reference/x/tweet-embed) · [Resolve links](/api-reference/x/resolve-links) · [Tweet subtitles](/api-reference/x/tweet-subtitles) · [X Article](/api-reference/x/get-article)
    * Analysis: [Sentiment analysis](/api-reference/x/sentiment-analysis) · [Brand mentions](/api-reference/x/brand-monitoring) · [News classification](/api-reference/x/news-classification) · [Market signals](/api-reference/x/market-signals) · [Viral score](/api-reference/x/viral-score) · [Classify posts](/api-reference/x/classify-tweets)
    * Engagement: [Tweet replies](/api-reference/x/tweet-replies) · [Quote tweets](/api-reference/x/tweet-quotes) · [Likers](/api-reference/x/favoriters) · [Reposters](/api-reference/x/retweeters) · [Check repost](/api-reference/x/tweet-repost-check)
    * Profiles: [User tweets](/api-reference/x/user-tweets) · [Batch user tweets](/api-reference/x/batch-user-tweets) · [User replies](/api-reference/x/user-replies) · [User likes](/api-reference/x/user-likes) · [User media](/api-reference/x/user-media) · [User highlights](/api-reference/x/user-highlights) · [User articles](/api-reference/x/user-articles)
    * Feeds: [List tweets](/api-reference/x/list-tweets) · [Trends](/api-reference/x/trends) · [Trend locations](/api-reference/x/trend-locations) · [Search Spaces](/api-reference/x/search-spaces) · [Get Space](/api-reference/x/get-space) · [Space replay](/api-reference/x/space-replay) · [Get broadcast](/api-reference/x/get-broadcast) · [Hashflags](/api-reference/x/hashflags) · [Search places](/api-reference/x/search-places) · [Download media](/api-reference/x/download-media)
  </Accordion>
</div>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.