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

# Compose tweet

> Compose, refine, and score tweets using X algorithm data. 3-step workflow, free

<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** - does not consume credits
</Callout>

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://xquik.com/api/v1/compose \
    -H "x-api-key: xq_YOUR_KEY_HERE" \
    -H "Content-Type: application/json" \
    -d '{
      "step": "compose",
      "topic": "launching my new SaaS product",
      "goal": "engagement"
    }' | jq
  ```

  ```javascript Node.js theme={null}
  const response = await fetch("https://xquik.com/api/v1/compose", {
    method: "POST",
    headers: {
      "x-api-key": "xq_YOUR_KEY_HERE",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      step: "compose",
      topic: "launching my new SaaS product",
      goal: "engagement",
    }),
  });
  const data = await response.json();
  ```

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

  response = requests.post(
      "https://xquik.com/api/v1/compose",
      headers={"x-api-key": "xq_YOUR_KEY_HERE"},
      json={
          "step": "compose",
          "topic": "launching my new SaaS product",
          "goal": "engagement",
      },
  )
  data = response.json()
  ```

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

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

  func main() {
      body, _ := json.Marshal(map[string]interface{}{
          "step":  "compose",
          "topic": "launching my new SaaS product",
          "goal":  "engagement",
      })

      req, _ := http.NewRequest("POST", "https://xquik.com/api/v1/compose", bytes.NewReader(body))
      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()

      respBody, _ := io.ReadAll(resp.Body)
      fmt.Println(string(respBody))
  }
  ```
</CodeGroup>

## Headers

<ParamField header="x-api-key" type="string" required>
  Your API key. Session cookie authentication is also supported.
</ParamField>

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

## Body

<ParamField body="step" type="string" required>
  Workflow step. One of `compose`, `refine`, or `score`.
</ParamField>

<ParamField body="topic" type="string">
  Tweet topic. Used in `compose` and `refine` steps.
</ParamField>

<ParamField body="goal" type="string">
  Optimization goal: `engagement`, `followers`, `authority`, or `conversation`.
</ParamField>

<ParamField body="styleUsername" type="string">
  Cached style username for voice matching. Used in `compose` step.
</ParamField>

<ParamField body="tone" type="string">
  Desired tone for the tweet. Used in `refine` step.
</ParamField>

<ParamField body="additionalContext" type="string">
  Extra context or URLs. Used in `refine` step.
</ParamField>

<ParamField body="callToAction" type="string">
  Desired call to action. Used in `refine` step.
</ParamField>

<ParamField body="mediaType" type="string">
  Media type: `photo`, `video`, or `none`. Used in `refine` step.
</ParamField>

<ParamField body="draft" type="string">
  Tweet text to evaluate. Used in `score` step.
</ParamField>

<ParamField body="hasLink" type="boolean">
  Whether a link is attached. Used in `score` step.
</ParamField>

<ParamField body="hasMedia" type="boolean">
  Whether media is attached. Used in `score` step.
</ParamField>

## Workflow

The compose API follows a 3-step workflow:

1. **`compose`**: Returns algorithm weights, content rules, penalties, and follow-up questions
2. **`refine`**: Returns composition guidance, example patterns, media strategy, and CTA advice
3. **`score`**: Evaluates a draft against algorithm checks with pass/fail results

## Response

<Tabs>
  <Tab title="200 OK (compose)">
    <ResponseField name="contentRules" type="object[]">Algorithm content rules. Each item has a `rule` string.</ResponseField>
    <ResponseField name="scorerWeights" type="object[]">Algorithm scorer weights. Each item has `context`, `signal`, and `weight` fields.</ResponseField>
    <ResponseField name="followUpQuestions" type="string[]">Follow-up questions to refine the composition.</ResponseField>
    <ResponseField name="engagementMultipliers" type="object[]">Engagement multipliers. Each item has `action` and `multiplier` fields.</ResponseField>
    <ResponseField name="engagementVelocity" type="string">Engagement velocity description.</ResponseField>
    <ResponseField name="intentUrl" type="string">X intent URL for posting the tweet.</ResponseField>
    <ResponseField name="nextStep" type="string">Instructions for the next API call in the workflow.</ResponseField>
    <ResponseField name="savedStyles" type="object[]">Saved style profiles. Present when you omit `styleUsername` and cached styles exist.</ResponseField>
    <ResponseField name="savedStyles[].username" type="string">Cached style username.</ResponseField>
    <ResponseField name="savedStyles[].tweetCount" type="number">Number of cached tweets available for that style.</ResponseField>
    <ResponseField name="source" type="string">Algorithm source attribution.</ResponseField>
    <ResponseField name="styleNote" type="string">Style fallback note. Present when a requested style is not cached and the request can continue without refreshing it.</ResponseField>
    <ResponseField name="styleTweets" type="string[]">Cached example tweets used for voice matching. Present when `styleUsername` matches a cached style.</ResponseField>
    <ResponseField name="topPenalties" type="string[]">Top algorithm penalties to avoid.</ResponseField>

    ```json theme={null}
    {
      "contentRules": [{ "rule": "Keep under 280 characters" }, { "rule": "Front-load the hook" }],
      "scorerWeights": [{ "context": "tweet", "signal": "hook", "weight": 2 }],
      "engagementMultipliers": [{ "action": "reply", "multiplier": "1.5x" }],
      "engagementVelocity": "First 30 minutes are critical for algorithmic reach",
      "topPenalties": ["External links reduce reach by ~50%"],
      "followUpQuestions": [
        "What tone do you want? (casual, professional, bold)",
        "Will you attach media (photo, video, none)?",
        "What call-to-action do you prefer?"
      ],
      "intentUrl": "https://x.com/intent/tweet?text=...",
      "nextStep": "Call with step: refine, providing tone, goal, and topic",
      "source": "X algorithm analysis"
    }
    ```
  </Tab>

  <Tab title="200 OK (refine)">
    <ResponseField name="compositionGuidance" type="string[]">Composition guidance tips.</ResponseField>
    <ResponseField name="examplePatterns" type="object[]">Example tweet patterns. Each item has `pattern` and `description` fields.</ResponseField>
    <ResponseField name="intentUrl" type="string">X intent URL for posting the tweet.</ResponseField>
    <ResponseField name="nextStep" type="string">Instructions for the next API call in the workflow.</ResponseField>

    ```json theme={null}
    {
      "compositionGuidance": [
        "Lead with a personal story or metric.",
        "End with an open question."
      ],
      "examplePatterns": [
        { "pattern": "Hook -> Context -> CTA", "description": "Surprising metric, 1-2 sentences, open question" }
      ],
      "intentUrl": "https://x.com/intent/tweet?text=...",
      "nextStep": "Write your draft and call with step: score"
    }
    ```
  </Tab>

  <Tab title="200 OK (score)">
    <ResponseField name="totalChecks" type="number">Total number of algorithm checks evaluated.</ResponseField>
    <ResponseField name="passedCount" type="number">Number of checks that passed.</ResponseField>
    <ResponseField name="passed" type="boolean">Overall pass/fail result.</ResponseField>
    <ResponseField name="topSuggestion" type="string">Top improvement suggestion.</ResponseField>

    <ResponseField name="checklist" type="object[]">
      Individual check results.

      <Expandable title="check item">
        <ResponseField name="factor" type="string">Check factor name.</ResponseField>
        <ResponseField name="passed" type="boolean">Whether this check passed.</ResponseField>
        <ResponseField name="suggestion" type="string">Improvement suggestion. Omitted if passed.</ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="nextStep" type="string">Instructions for next steps.</ResponseField>
    <ResponseField name="intentUrl" type="string">X intent URL. Present only when all checks pass.</ResponseField>

    ```json theme={null}
    {
      "totalChecks": 11,
      "passedCount": 9,
      "passed": false,
      "topSuggestion": "Add a specific detail or metric to the first line.",
      "checklist": [
        { "factor": "No external links in body", "passed": true },
        { "factor": "No hashtags", "passed": true },
        { "factor": "No excessive capitalization", "passed": true },
        { "factor": "Conversation-driving CTA", "passed": true },
        { "factor": "Optimal length (50-280 characters)", "passed": true },
        { "factor": "Media attached", "passed": true },
        { "factor": "No excessive punctuation", "passed": true },
        { "factor": "No emojis", "passed": true },
        { "factor": "No em dashes or double dashes", "passed": true },
        { "factor": "Sufficient substance", "passed": false, "suggestion": "Add a specific detail or metric" },
        { "factor": "Link-in-reply strategy", "passed": false, "suggestion": "Move the link to a reply instead" }
      ],
      "nextStep": "Revise your draft and score again"
    }
    ```
  </Tab>

  <Tab title="400 Invalid Input">
    ```json theme={null}
    { "error": "invalid_input", "message": "step is required. Must be \"compose\", \"refine\", or \"score\"." }
    ```

    Invalid JSON returns `invalid_json`. Valid JSON with a missing or unsupported `step`, missing `topic` for `compose`, missing `goal`, `tone`, or `topic` for `refine`, or missing `draft` for `score` returns `invalid_input`.
  </Tab>

  <Tab title="401 Unauthenticated">
    ```json theme={null}
    { "error": "unauthenticated" }
    ```

    Missing or invalid API key.
  </Tab>

  <Tab title="429 Rate Limited">
    ```json theme={null}
    { "error": "rate_limit_exceeded", "message": "Too many requests. Try again later.", "retryAfter": 60 }
    ```

    Too many requests. Wait for the `Retry-After` header before retrying.
  </Tab>
</Tabs>

<Note>
  **Next steps:** [Save Draft](/api-reference/drafts/create) to save a composed tweet for later, or [Analyze Style](/api-reference/styles/analyze) to match another account's voice.
</Note>
