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

# Tweet writing style API for cached X profile samples

> Cache recent tweet writing samples for one X username. Reuse fresh profiles, refresh stale samples, and read authors, timestamps, and exact Tweet IDs.

<Panel>
  <Tabs defaultTabIndex={0} sync={false}>
    <Tab title="200" id="response-styles-analyze-200">
      ```json theme={null}
      {
        "xUsername": "elonmusk",
        "tweetCount": 50,
        "isOwnAccount": true,
        "fetchedAt": "2025-01-15T12:00:00Z",
        "tweets": [
          {
            "id": "1234567890",
            "text": "Just launched our new feature!"
          }
        ]
      }
      ```
    </Tab>

    <Tab title="201" id="response-styles-analyze-201">
      ```json theme={null}
      {
        "xUsername": "elonmusk",
        "tweetCount": 50,
        "isOwnAccount": true,
        "fetchedAt": "2025-01-15T12:00:00Z",
        "tweets": [
          {
            "id": "1234567890",
            "text": "Just launched our new feature!"
          }
        ]
      }
      ```
    </Tab>

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

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

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

    <Tab title="429" id="response-styles-analyze-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="coins" color="#5c3327">
  **Free from cache.** A refresh costs 1 credit per tweet returned.
</Callout>

## Build a reusable tweet writing profile

Send one X username to cache recent tweet writing samples. Xquik searches posts
from that username and stores each returned Tweet ID, text, author, and time.

This route manages cache creation and refreshes. It does not generate a tone
label, vocabulary summary, sentence score, or engagement analysis.

Use the returned samples for your approved writing review. Use
[Analyze Performance](/api-reference/styles/performance) for current likes,
replies, reposts, quotes, bookmarks, and views.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://xquik.com/api/v1/styles \
    -H "x-api-key: xq_YOUR_KEY_HERE" \
    -H "Content-Type: application/json" \
    -d '{
      "username": "xquik"
    }' | jq
  ```

  ```javascript Node.js theme={null}
  const response = await fetch("https://xquik.com/api/v1/styles", {
    method: "POST",
    headers: {
      "x-api-key": "xq_YOUR_KEY_HERE",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ username: "xquik" }),
  });

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

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

  response = requests.post(
      "https://xquik.com/api/v1/styles",
      headers={"x-api-key": "xq_YOUR_KEY_HERE"},
      json={"username": "xquik"},
      timeout=30,
  )
  response.raise_for_status()
  result = response.json()
  cache_was_refreshed = response.status_code == 201
  ```

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

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

  func main() {
      body, err := json.Marshal(map[string]string{"username": "xquik"})
      if err != nil {
          panic(err)
      }

      req, err := http.NewRequest(
          http.MethodPost,
          "https://xquik.com/api/v1/styles",
          bytes.NewReader(body),
      )
      if err != nil {
          panic(err)
      }
      req.Header.Set("x-api-key", "xq_YOUR_KEY_HERE")
      req.Header.Set("Content-Type", "application/json")

      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 && resp.StatusCode != http.StatusCreated {
          panic(fmt.Sprintf("style request failed: %v", result))
      }
      cacheWasRefreshed := resp.StatusCode == http.StatusCreated
      fmt.Println(cacheWasRefreshed)
  }
  ```
</CodeGroup>

## Understand cached and refreshed responses

The HTTP status explains the cache action. Always inspect `fetchedAt` too.

| Status | Cache condition | X request | Credit result |
| - | - | - | - |
| `200` | Profile is under 7 days old | No | Free cached response |
| `200` | Profile is older, and credits cannot cover a refresh | No | Existing stale cache returned |
| `201` | Profile is missing or older, and credits cover a refresh | Yes | 1 credit per returned Tweet |
| `402` | No cache exists, and credits cannot cover a refresh | No | `no_cached_style` returned |

A `200` response does not guarantee a recent refresh. Compare `fetchedAt` with
your freshness policy before using the samples.

The route has no `force` parameter. Repeating POST while the profile is fresh
returns the same cache without another X request.

## Send a normalized X username

Send a non-empty X username without `@`, spaces, or a profile URL. Xquik
lowercases the value before lookup and storage.

```json theme={null}
{
  "username": "xquik"
}
```

The request body accepts one field only:

| Field | Type | Required | Rule |
| - | - | - | - |
| `username` | string | Yes | Send the X handle without `@`. |

Missing, empty, or non-string values return `400 invalid_input`. Keep the
returned `xUsername` value for Get, Compare, Delete, and Performance requests.

## Read the cached tweet writing samples

The profile response contains exact cached examples. It does not contain
derived writing conclusions.

| Profile field | Meaning | Integration use |
| - | - | - |
| `xUsername` | Lowercase analyzed X username | Use as the profile key. |
| `tweetCount` | Number of cached Tweet samples | Record the sample size and refresh cost. |
| `isOwnAccount` | Ownership classification stored during refresh | Separate owned and external profiles. |
| `fetchedAt` | ISO 8601 fetch time | Apply your cache freshness policy. |
| `tweets` | Cached tweet writing samples | Review the source text directly. |

`isOwnAccount` compares the username with the saved
[X identity](/api-reference/account/x-identity) during a refresh. A cached
`200` response does not recompute that flag.

## Parse every cached tweet

Each public `tweets[]` entry contains these fields:

| Tweet field | Required | Meaning |
| - | - | - |
| `id` | Yes | Exact Tweet ID as a string |
| `text` | Yes | Cached tweet text |
| `authorUsername` | No | Tweet author's X username |
| `createdAt` | No | ISO 8601 publication time |

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

The public Style Profile contract does not include cached media objects. Use a
Tweet or media endpoint when your workflow requires images, videos, or GIFs.

```json theme={null}
{
  "xUsername": "xquik",
  "tweetCount": 2,
  "isOwnAccount": true,
  "fetchedAt": "2026-08-02T12:00:00.000Z",
  "tweets": [
    {
      "id": "1950882898740914261",
      "text": "Export tweet replies to JSON or CSV.",
      "authorUsername": "xquik",
      "createdAt": "2026-08-02T11:30:00.000Z"
    }
  ]
}
```

## Review observable tweet writing features

The response provides source text for your analysis. Start with observable
features before assigning subjective voice or tone labels.

| Writing feature | Sample calculation | Review question |
| - | - | - |
| Post length | Median `text.length` | Does the profile prefer short tweets? |
| Questions | Samples containing `?` | How often does the profile invite replies? |
| Links | Samples containing an HTTP URL | How often does it cite another page? |
| Hashtags | Count `#` tokens | Does it label topics with hashtags? |
| Openings | Compare first sentences | Which hooks recur? |
| Vocabulary | Count repeated meaningful words | Which specific terms define the sample? |
| Cadence | Compare available `createdAt` values | How closely were samples published? |

Do not infer future engagement from writing samples. Refresh public metrics
through Analyze Performance when outcome comparisons are required.

## Build a Twitter brand voice workflow

1. Set the [X identity](/api-reference/account/x-identity) before refreshing.
2. Send one public X username to this endpoint.
3. Branch on HTTP `200` or `201`.
4. Store `xUsername`, `fetchedAt`, and `tweetCount`.
5. Store every Tweet ID and text value.
6. Review observable patterns with a human editor.
7. Keep current product claims out of copied historical tweets.

Use cached examples as references. Never copy another person's distinctive
phrasing without authorization.

## Analyze another public X account

You can cache recent public tweets from another username. The resulting
profile belongs only to the authenticated Xquik account.

This route does not expose drafts, private posts, private analytics, followers,
following, profile visits, or direct messages.

## Budget a style refresh

Cached `200` responses are free. A `201` refresh costs 1 credit per Tweet
returned and stored.

Use `tweetCount` to reconcile the refresh. The endpoint does not accept a limit
parameter, date range, pagination cursor, or requested sample count.

When a stale cache exists without enough available credits, Xquik returns that
cache with `200`. It does not delete the existing writing samples.

## Handle style cache errors

| Status | Error | Meaning | Recovery |
| - | - | - | - |
| `200` | None | Cached profile returned | Inspect `fetchedAt` before use. |
| `201` | None | Profile fetched and stored | Record `tweetCount` for billing. |
| `400` | `invalid_input` | Username is missing, empty, or not a string | Send one username string. |
| `401` | `unauthenticated` | Credential is missing or invalid | Replace the API key or bearer token. |
| `402` | `no_cached_style` | No cache exists, and credits cannot cover a refresh | Top up or save approved examples. |
| `429` | `rate_limit_exceeded` | Request exceeded the rate limit | Wait for `Retry-After`, then retry once. |

The response widget lists every status in the OpenAPI contract.

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

<ParamField header="Content-Type" type="string" required>
  Must be `application/json`.
</ParamField>

## Body

<ParamField body="username" type="string" required>
  Non-empty X username without `@`. Xquik lowercases the value.
</ParamField>

## Response

### 200 OK

Returns a cached profile. It can be fresh, or stale when credits cannot cover a refresh.

### 201 Created

Returns a newly fetched and stored profile.

<ResponseField name="xUsername" type="string">Lowercase analyzed X username.</ResponseField>
<ResponseField name="tweetCount" type="number">Number of cached Tweet samples.</ResponseField>
<ResponseField name="isOwnAccount" type="boolean">Stored ownership classification.</ResponseField>
<ResponseField name="fetchedAt" type="string">ISO 8601 cache fetch timestamp.</ResponseField>

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

  <Expandable title="Tweet sample fields">
    <ResponseField name="id" type="string">Exact Tweet ID.</ResponseField>
    <ResponseField name="text" type="string">Cached tweet text.</ResponseField>
    <ResponseField name="authorUsername" type="string">Optional author username.</ResponseField>
    <ResponseField name="createdAt" type="string">Optional ISO 8601 publication time.</ResponseField>
  </Expandable>
</ResponseField>

### 400 Invalid input

```json theme={null}
{ "error": "invalid_input", "message": "Invalid input. Check the request body." }
```

Username is missing, empty, or not a string. Send one username string.

### 401 Unauthenticated

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

Authentication failed. Replace the missing or invalid credential.

### 402 No cached style

```json theme={null}
{
  "error": "no_cached_style",
  "message": "No cached style for @username. Share 5-10 example tweet texts, then save via PUT /api/v1/styles/username."
}
```

No cache exists, and credits cannot cover a refresh. Top up through the
[billing page](https://dashboard.xquik.com/en/account?tab=subscription), or
save approved tweet examples with [Save Custom Style](/api-reference/styles/save).

### 429 Rate limited

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

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

### How do I analyze a Twitter writing style?

Cache one public username, then review the returned tweet text. This endpoint
supplies writing samples. Your application performs any voice or tone analysis.

### Does analyze style return tone or vocabulary scores?

No. It returns Tweet IDs, text, authors, timestamps, and cache metadata. It
does not return generated style labels or scores.

### Why did analyze style return 200 instead of 201?

The route reused an existing cache. Check `fetchedAt`. A `200` can also return
a stale cache when credits cannot cover a refresh.

### Can I force a Twitter style refresh?

No force parameter exists. Fresh profiles return from cache. To refresh early, delete the
profile and create it again. Deletion is permanent.

### Can I analyze another Twitter account?

Yes, for recent public tweets. Only your
authenticated Xquik account can read the cached profile.

<Note>
  **Next.** [Get Style](/api-reference/styles/get) reads samples without a
  refresh. [Compare Styles](/api-reference/styles/compare) retrieves 2 profiles.
</Note>


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