> ## 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 stock & crypto signals API for cashtags

> Read bullish and bearish stock and crypto stances in X posts with AI. Get content type, conviction, relevance, and cashtag totals. 2 credits per analyzed post.

<Panel>
  <Tabs defaultTabIndex={0} sync={false}>
    <Tab title="200" id="response-x-market-signals-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-market-signals-400">
      ```json theme={null}
      {
        "error": "invalid_input",
        "message": "Invalid input. Check the request body."
      }
      ```
    </Tab>

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

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

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

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

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

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

    <Tab title="503" id="response-x-market-signals-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>

Market signals reads each post with AI and answers 4 questions about an asset.
The endpoint is `POST /api/v1/x/analysis/market-signals`.

| Answer | Type | Values |
| - | - | - |
| `stance` | Choice | `bullish`, `bearish`, `neutral`, `mixed`, or `unclear` |
| `content` | Choice | `analysis`, `news`, `trade`, `promotion`, `humor`, `question`, or `unclear` |
| `conviction` | Score | `0` no stance or hedged, `1` a reasoned view, `2` a firm call |
| `relevance` | Probability | From `0` to `1`, the chance the post treats the target as an asset |

The summary counts bullish and bearish posts per cashtag. Name the asset in
`analysis.targets`.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://xquik.com/api/v1/x/analysis/market-signals \
    -H "x-api-key: xq_your_api_key_here" \
    -H "Content-Type: application/json" \
    -d '{
      "query": "$NVDA lang:en",
      "limit": 50,
      "analysis": { "targets": [{ "name": "NVIDIA", "aliases": ["NVDA"] }] }
    }' | jq
  ```

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

  const signalRows = data.results
    .filter((result) => result.answers.relevance >= 0.5)
    .filter((result) => result.answers.content !== "promotion")
    .map((result) => ({
      tweet_id: result.tweet.id,
      stance: result.answers.stance,
      content: result.answers.content,
      conviction: result.answers.conviction,
      cashtags: result.cashtags,
    }));
  const cashtagSignals = data.analysisSummary.cashtags.map(({ cashtag, signal }) => ({
    cashtag,
    ...signal,
  }));

  process.stdout.write(`${JSON.stringify({ rows: signalRows.length, cashtagSignals })}\n`);
  ```

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

  response = requests.post(
      "https://xquik.com/api/v1/x/analysis/market-signals",
      headers={"x-api-key": "xq_your_api_key_here"},
      json={
          "query": "$NVDA lang:en",
          "limit": 50,
          "analysis": {"targets": [{"name": "NVIDIA", "aliases": ["NVDA"]}]},
      },
      timeout=120,
  )
  data = response.json()
  if not response.ok:
      raise RuntimeError(f"{data['error']}: {data['message']}")

  signal_rows = [
      {
          "tweet_id": result["tweet"]["id"],
          "stance": result["answers"]["stance"],
          "content": result["answers"]["content"],
          "conviction": result["answers"]["conviction"],
          "cashtags": result["cashtags"],
      }
      for result in data["results"]
      if result["answers"]["relevance"] >= 0.5 and result["answers"]["content"] != "promotion"
  ]
  cashtag_signals = [
      {"cashtag": entry["cashtag"], **entry.get("signal", {})}
      for entry in data["analysisSummary"]["cashtags"]
  ]
  print(json.dumps({"rows": len(signal_rows), "cashtag_signals": cashtag_signals}))
  ```
</CodeGroup>

The snippets keep relevant posts that are not promotion, then print the signal
per cashtag. They do not print the full response.

## Name the asset

Put the asset in `analysis.targets`, with its ticker and other names as
aliases. A post mentions the target when its text contains the name or an
alias, in any letter case.

```json theme={null}
{ "name": "NVIDIA", "aliases": ["NVDA", "Nvidia"] }
```

`relevance` says whether a post discusses the target as an asset, a position,
or a price. Posts about the wider market, competitors, or suppliers do not
count. Neither does a ticker in a list of tags.

Filter rows on `relevance` before you count stances. The snippets keep posts
from `0.5`.

## Read the market answers

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

| `stance` | Meaning |
| - | - |
| `bullish` | Expects the price or outlook to rise |
| `bearish` | Expects the price or outlook to fall |
| `neutral` | Discusses the asset without a direction |
| `mixed` | Combines rising and falling expectations |
| `unclear` | Names no identifiable asset or states no view |

`stance` classifies the author's own view, not quoted views or ads.

| `content` | Meaning |
| - | - |
| `analysis` | Reasoning from data, charts, fundamentals, or events |
| `news` | Reports an event, filing, or announcement |
| `trade` | Describes a position, entry, exit, or trade plan |
| `promotion` | Sells a service, signal group, or product, or shills an asset |
| `humor` | A joke, meme, or venting without a claim |
| `question` | Asks for views or information |
| `unclear` | Not enough context |

`conviction` judges how firmly the text states the stance, not engagement or
follower counts. A post with no stance on the target scores `0`. It can have
decimals, such as `1.6` between a reasoned view and a firm call.

The answers describe what posts say, not whether claims are true. They are not
investment advice.

## Read the signal per cashtag

`analysisSummary.cashtags` lists up to 20 cashtags, most posts first. Each entry
has `rows`, the category counts in `choices`, and `signal`.

`signal` holds `bullish` and `bearish` post counts and a `score` from `-1` to
`1`. The score is bullish minus bearish posts, divided by the cashtag's posts.

`results[].cashtags` lists the cashtags in each post's text, in upper case. A
post with 2 cashtags counts toward both.

`analysisSummary.targets` counts the posts that mention each target, with their
category counts.

## 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"
}
```

`query` takes cashtags and operators, such as `$NVDA lang:en`. Send `username`
to read 1 trader's or analyst's posts.

## 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. `stance` and `content` are categories, `conviction` a level from `0`, 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. `stance` and `content` have `counts`, `shares`, `engagementShares`, and `top` posts per category. `conviction` has `mean`, `engagementWeightedMean`, and `levels`. `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[]">
      Per cashtag, most posts first, up to 20: `cashtag`, `rows`, `choices`, and `signal` with `bullish`, `bearish`, and `score`.
    </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": "$NVDA cleared its 50-day average on volume. Adding to my position, target 160.",
        "likeCount": 212,
        "retweetCount": 18,
        "replyCount": 25
      },
      "analysis": {
        "status": "succeeded",
        "answers": [
          {
            "questionId": "stance",
            "questionVersion": "market:4",
            "type": "choice",
            "value": "bullish",
            "confidence": 0.94,
            "probabilities": {
              "bullish": 0.94,
              "bearish": 0.01,
              "neutral": 0.02,
              "mixed": 0.02,
              "unclear": 0.01
            }
          },
          {
            "questionId": "relevance",
            "questionVersion": "market:4",
            "type": "probability",
            "probability": 0.97
          }
        ]
      },
      "answers": { "stance": "bullish", "content": "trade", "conviction": 2, "relevance": 0.97 },
      "sourceDomains": [],
      "cashtags": ["$NVDA"]
    }
  ],
  "unanalyzed": [],
  "analysisSummary": {
    "schemaVersion": 1,
    "rows": { "analyzed": 1, "failed": 0, "skipped": 0 },
    "engagement": 255,
    "questions": {
      "stance": {
        "type": "choice",
        "counts": { "bullish": 1, "bearish": 0, "neutral": 0, "mixed": 0, "unclear": 0 }
      }
    },
    "targets": [
      {
        "name": "NVIDIA",
        "mentions": 1,
        "share": 1,
        "engagement": 255,
        "choices": { "stance": { "bullish": 1 } },
        "top": {
          "stance": { "bullish": [{ "tweetId": "1893456789012345678", "engagement": 255 }] }
        }
      }
    ],
    "cashtags": [
      {
        "cashtag": "$NVDA",
        "rows": 1,
        "choices": { "stance": { "bullish": 1 }, "content": { "trade": 1 } },
        "signal": { "bullish": 1, "bearish": 0, "score": 1 }
      }
    ],
    "sourceDomains": []
  },
  "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.

## Stock & crypto sentiment API questions

### How do I get the sentiment of a stock or coin on X?

Search its cashtag in `query` and name it in `analysis.targets`. Each row in
`results` holds the post's `stance`, and `analysisSummary.cashtags` counts
bullish and bearish posts.

### What does the cashtag score mean?

`signal.score` is bullish minus bearish posts, divided by the cashtag's posts.
`1` means every post is bullish, and `-1` means every post is bearish.

### How do I drop spam and shilling?

Skip rows whose `content` is `promotion`, and keep rows with high `relevance`.
That drops signal groups, ads, and tickers used as tags.

### Does it work for crypto?

Yes. Name the coin in `analysis.targets`, such as `Bitcoin` with the alias
`BTC`. Cashtags like `$BTC` count in `analysisSummary.cashtags`.

### How much do market signals 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.** [Sentiment analysis](/api-reference/x/sentiment-analysis) reads the general attitude of posts, or [Search Tweets](/api-reference/x/search-tweets) previews the posts a query returns.
</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.