> ## 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.

# Compare 2 cached tweet writing profiles with Xquik

> Compare 2 cached tweet writing profiles for X usernames or custom labels. Retrieve both sample sets, authors, timestamps, counts, and ownership status.

<Panel>
  <Tabs defaultTabIndex={0} sync={false}>
    <Tab title="200" id="response-styles-compare-200">
      ```json theme={null}
      {
        "style1": {
          "xUsername": "elonmusk",
          "tweetCount": 50,
          "isOwnAccount": true,
          "fetchedAt": "2025-01-15T12:00:00Z",
          "tweets": [
            {
              "id": "1234567890",
              "text": "Just launched our new feature!"
            }
          ]
        },
        "style2": {
          "xUsername": "BillGates",
          "tweetCount": 40,
          "isOwnAccount": false,
          "fetchedAt": "2025-01-15T12:00:00Z",
          "tweets": [
            {
              "id": "9876543210",
              "text": "Climate change is a global challenge."
            }
          ]
        }
      }
      ```
    </Tab>

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

    <Tab title="401" id="response-styles-compare-401">
      ```json theme={null}
      {
        "error": "unauthenticated",
        "message": "Authentication required. Provide a valid API key or bearer token."
      }
      ```
    </Tab>

    <Tab title="404" id="response-styles-compare-404">
      ```json theme={null}
      {
        "error": "not_found",
        "message": "Resource not found."
      }
      ```
    </Tab>

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

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

<Callout icon="circle-check" color="#16a34a">
  **Free.** This endpoint does not consume credits.
</Callout>

## Retrieve 2 cached tweet writing profiles

Call this endpoint to retrieve 2 cached writing profiles together. Supply 2 X
usernames, 2 custom labels, or one of each.

Xquik performs 2 account-scoped cache lookups. It does not contact X, refresh
tweets, or calculate a writing-style score.

The response keeps request order. `style1` matches `username1`. `style2`
matches `username2`.

<CodeGroup>
  ```bash cURL theme={null}
  curl -G https://xquik.com/api/v1/styles/compare \
    --data-urlencode "username1=xquik" \
    --data-urlencode "username2=product updates" \
    -H "x-api-key: xq_YOUR_KEY_HERE" | jq
  ```

  ```javascript Node.js theme={null}
  const params = new URLSearchParams({
    username1: "xquik",
    username2: "product updates",
  });
  const response = await fetch(`https://xquik.com/api/v1/styles/compare?${params}`, {
    method: "GET",
    headers: {
      "x-api-key": "xq_YOUR_KEY_HERE",
    },
  });

  const result = await response.json();
  if (!response.ok) {
    throw new Error(`${result.error}: ${result.message}`);
  }
  ```

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

  response = requests.get(
      "https://xquik.com/api/v1/styles/compare",
      params={"username1": "xquik", "username2": "product updates"},
      headers={"x-api-key": "xq_YOUR_KEY_HERE"},
      timeout=30,
  )
  response.raise_for_status()
  result = response.json()
  ```

  ```go Go theme={null}
  package main

  import (
      "encoding/json"
      "fmt"
      "net/http"
      "net/url"
  )

  func main() {
      endpoint, err := url.Parse("https://xquik.com/api/v1/styles/compare")
      if err != nil {
          panic(err)
      }
      query := endpoint.Query()
      query.Set("username1", "xquik")
      query.Set("username2", "product updates")
      endpoint.RawQuery = query.Encode()

      req, err := http.NewRequest(http.MethodGet, endpoint.String(), nil)
      if err != nil {
          panic(err)
      }
      req.Header.Set("x-api-key", "xq_YOUR_KEY_HERE")

      resp, err := http.DefaultClient.Do(req)
      if err != nil {
          panic(err)
      }
      defer resp.Body.Close()

      var result map[string]interface{}
      if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
          panic(err)
      }
      if resp.StatusCode != http.StatusOK {
          panic(fmt.Sprintf("style comparison failed: %v", result))
      }
  }
  ```
</CodeGroup>

## Select comparable tweet style keys

Both query values use the same keys as [Get Style](/api-reference/styles/get).
Xquik lowercases each value before lookup.

| Profile source | Query value | Example |
| - | - | - |
| [Analyze & Cache Style](/api-reference/styles/analyze) | Returned `xUsername` | `xquik` |
| [Save Custom Style](/api-reference/styles/save) | Returned lowercase label | `product updates` |
| [List Styles](/api-reference/styles/list) | Any `styles[].xUsername` | `founder voice` |

The query parameter names say `username`. They also accept saved custom labels.
Do not send numeric database IDs.

Use 2 different keys. The API accepts the same key
twice, but both response objects then contain the same profile.

## Understand what compare styles returns

This endpoint groups 2 stored sample sets into one response. It does not
generate conclusions about voice, tone, vocabulary, readability, or sentiment.

| Response field | Meaning | Comparison use |
| - | - | - |
| `style1` | Profile selected by `username1` | Treat as the first sample set. |
| `style2` | Profile selected by `username2` | Treat as the second sample set. |
| `xUsername` | Lowercase X username or custom label | Keep each profile key. |
| `tweetCount` | Stored tweet sample count | Check whether sample sizes differ. |
| `isOwnAccount` | Stored ownership classification | Separate owned and external profiles. |
| `fetchedAt` | ISO 8601 cache timestamp | Check whether collection times differ. |
| `tweets` | Cached or supplied tweet examples | Perform your approved comparison. |

The 2 profiles can have different sample counts. They can also have different
cache timestamps. Compare equivalent subsets when those differences matter.

## Inspect every tweet writing sample

Both `style1.tweets[]` and `style2.tweets[]` use this public contract:

| Tweet field | Required | Meaning |
| - | - | - |
| `id` | Yes | Stored Tweet ID or generated custom-sample ID |
| `text` | Yes | Cached tweet or supplied writing example |
| `authorUsername` | No | X author username or custom label |
| `createdAt` | No | ISO 8601 tweet or custom-sample timestamp |

Keep Tweet IDs as strings. JavaScript numbers cannot represent every X
Tweet ID exactly.

Do not send generated custom-sample IDs to X tweet endpoints. They identify
local writing examples only.

```json theme={null}
{
  "style1": {
    "xUsername": "xquik",
    "tweetCount": 2,
    "fetchedAt": "2026-07-31T10:30:00.000Z",
    "isOwnAccount": true,
    "tweets": [
      {
        "id": "1950882898740914261",
        "text": "Export tweet replies to JSON or CSV.",
        "authorUsername": "xquik",
        "createdAt": "2026-07-31T09:00:00.000Z"
      }
    ]
  },
  "style2": {
    "xUsername": "product updates",
    "tweetCount": 2,
    "fetchedAt": "2026-07-31T10:35:00.000Z",
    "isOwnAccount": false,
    "tweets": [
      {
        "id": "0",
        "text": "Ship notes should name the endpoint and user outcome.",
        "authorUsername": "product updates",
        "createdAt": "2026-07-31T10:35:00.000Z"
      }
    ]
  }
}
```

## Compare tweet writing with observable features

Voice describes a consistent brand personality. Tone can change with context.
This API returns the source text needed for your own review.

Use observable text features before assigning subjective labels:

| Writing feature | Calculation | Review question |
| - | - | - |
| Post length | Compare median `text.length` | Which profile writes shorter tweets? |
| Questions | Count samples containing `?` | Which profile asks readers more often? |
| Links | Count samples containing an HTTP URL | Which profile cites external pages? |
| Hashtags | Count `#` tokens | Which profile uses topic labels? |
| Openings | Compare each sample's first sentence | Which recurring openings appear? |
| Vocabulary | Compare repeated meaningful words | Which terms distinguish each profile? |
| Cadence | Compare available `createdAt` values | Were the samples posted in similar periods? |

Review examples in context. A small or stale cache cannot prove a permanent
brand voice. Avoid copying personal phrases without authorization.

## Separate writing style from Twitter analytics

Compare Styles returns no likes, replies, reposts, quotes, bookmarks, views,
followers, or impressions. It cannot prove which writing style performs better.

Use [Analyze Performance](/api-reference/styles/performance) for current tweet
engagement. Compare equivalent periods and sample sizes before drawing an
outcome conclusion.

## Compare equivalent tweet samples

1. List cached profiles with the same Xquik credential.
2. Select 2 returned profile keys.
3. Review `fetchedAt` and `tweetCount` for both profiles.
4. Refresh stale X profiles through Analyze when required.
5. Call Compare Styles with both URL-encoded keys.
6. Compare equivalent tweet subsets using observable features.
7. Store both source keys with any conclusion you draw.

The endpoint does not modify either cache. Repeating the same request returns
the stored profiles until another route changes them.

## Handle tweet style comparison errors

| Status | Error | Meaning | Recovery |
| - | - | - | - |
| `200` | None | Both profiles exist | Compare `style1` and `style2` in order. |
| `400` | `missing_params` | One or both query values are absent | Send both non-empty query parameters. |
| `401` | `unauthenticated` | The credential is missing or invalid | Replace the API key or bearer token. |
| `404` | `style_not_found` | At least one account-scoped key is missing | List profiles, then create the missing cache. |
| `429` | `rate_limit_exceeded` | The request exceeded the rate limit | Wait for `Retry-After`, then retry once. |

A `404` response does not identify which key failed. Call Get Style for each
key when you need to isolate the missing profile.

The contract documents no `402` response. Comparing cached profiles
costs no credits.

## Query parameters

<ParamField query="username1" type="string" required>
  First X username or saved custom style label. Xquik lowercases this value and
  returns its profile as `style1`.
</ParamField>

<ParamField query="username2" type="string" required>
  Second X username or saved custom style label. Xquik lowercases this value and
  returns its profile as `style2`.
</ParamField>

## Headers

Send `x-api-key` with an Xquik API key. OAuth clients can send a bearer token
through the `Authorization` header instead.

<ParamField header="x-api-key" type="string" required>
  Your Xquik API key. Generate one from the [dashboard](https://xquik.com/dashboard).
</ParamField>

## Response

### 200 OK

<ResponseField name="style1" type="object">
  First cached profile.

  <ResponseField name="xUsername" type="string">Lowercase X username or custom label.</ResponseField>
  <ResponseField name="tweetCount" type="number">Stored tweet writing sample count.</ResponseField>
  <ResponseField name="isOwnAccount" type="boolean">Stored ownership classification.</ResponseField>
  <ResponseField name="fetchedAt" type="string">ISO 8601 cache fetch or custom-save timestamp.</ResponseField>

  <ResponseField name="tweets" type="object[]">
    Cached or supplied tweet writing samples.

    <Expandable title="First profile tweet fields">
      <ResponseField name="id" type="string">Tweet ID or generated custom-sample ID.</ResponseField>
      <ResponseField name="text" type="string">Cached tweet or supplied writing example.</ResponseField>
      <ResponseField name="authorUsername" type="string">Optional author username or custom label.</ResponseField>
      <ResponseField name="createdAt" type="string">Optional ISO 8601 sample timestamp.</ResponseField>
    </Expandable>
  </ResponseField>
</ResponseField>

<ResponseField name="style2" type="object">
  Second cached profile. It follows the same contract as `style1`.
</ResponseField>

### 400 Missing parameters

```json theme={null}
{ "error": "missing_params", "message": "Both usernames are required" }
```

One or both query values are missing. Send `username1` and `username2`.

### 401 Unauthenticated

```json theme={null}
{ "error": "unauthenticated", "message": "Missing or invalid API key" }
```

Authentication failed. Replace the missing or invalid credential.

### 404 Style not found

```json theme={null}
{ "error": "style_not_found", "message": "No cached style found for this username" }
```

At least one cache key is missing for this Xquik account. List styles first.

### 429 Rate limited

```json theme={null}
{
  "error": "rate_limit_exceeded",
  "message": "Too many requests. Try again later.",
  "retryAfter": 1
}
```

Too many requests. Wait for `Retry-After`, then retry once.

### Does compare styles calculate tone or brand voice?

No. It returns 2 cached tweet sample sets. Your application performs any tone,
voice, vocabulary, or sentence-pattern analysis.

### Can I compare an X username with a custom style?

Yes. Send the analyzed username and the saved custom label as the 2 query
values. Both profiles must belong to the authenticated Xquik account.

### Can I compare Twitter analytics for another account?

Not with this endpoint. Compare Styles returns writing samples, not engagement
metrics. Analyze Performance retrieves current metrics for cached tweets.

### Why does compare styles return 404?

At least one lowercase key is missing from this account. List styles, verify
both keys, then analyze or save the missing profile.

<Note>
  **Related.** [Get Style](/api-reference/styles/get) isolates one profile.
  [Delete Style](/api-reference/styles/delete) removes a cached profile.
</Note>


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