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

# Write post drafts in your voice

> Writes post drafts from a brief, in the account's own voice. Nothing
is scheduled and nothing is stored: the response is text for you to
review and edit, then send to `POST /v1/scheduled-posts` to save a
draft or schedule it.

Every draft copies the SHAPE of a proven post, never its content.
Pass one in `mirror` (the text of a post from `GET /v1/inspiration`
works well), or leave `mirror` out and a proven shape is picked for
you, optionally biased toward a `collection`.

Voice: `mine` (default) writes as the account in `account_id`, from
that account's own posts, style guide and rules (your main account
when `account_id` is omitted), `creator` writes in a creator's style,
and `hybrid` keeps the account's substance with the creator's flavor.
The creator's style guide is prepared in the
background the first time you name them; that first call returns
`409 creator_style_pending` and the retry a minute later succeeds.

Costs AI credits per draft (drafts that fail are refunded), and a
call takes roughly 20 to 40 seconds. `Idempotency-Key` is NOT
supported: generation is not idempotent, and a replay would produce
different text anyway.




## OpenAPI

````yaml /api-reference/openapi.yaml post /v1/posts/draft
openapi: 3.1.0
info:
  title: SuperX API
  version: 1.0.0
  description: >
    The SuperX public API: your Twitter/X content, analytics, audience and

    scheduling data over REST.


    All endpoints require an API key (`Authorization: Bearer sxk_...`) except

    `GET /v1/docs`. Keys are created in the SuperX app under Account > API / MCP
    / CLI

    and are server-side secrets.


    Timestamps are UTC ISO-8601 in both directions; inputs must carry an
    explicit

    `Z` or numeric offset. Every authenticated response carries

    `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`
    headers.
  contact:
    name: SuperX
    url: https://superx.so
servers:
  - url: https://api.superx.so
security:
  - apiKey: []
tags:
  - name: Identity
  - name: Content
  - name: Analytics
  - name: Inspiration
  - name: Audience
  - name: Contact Lists
  - name: Signals
  - name: Datasets
    description: |
      The audience collections Ask SuperX builds in the app: the repliers,
      quoters or reposters of a post, the members of an X list, your own
      posts or replies, or a research brief.

      Collect a new one with `POST /v1/datasets` (a big collection answers
      202 and finishes in the background), read it, export it, or copy the
      people in it into a contact list you created. Datasets are kept for 30
      days, and the ones Ask SuperX builds in the app show up here too.
  - name: Engage
    description: |
      The account's saved Engage feeds and the candidate posts in them, for
      an agent to score and a person to act on.

      Read-only by design. These endpoints return feed candidates for a
      person to review; replies are written and sent by a person in the
      SuperX app, which is why there is no reply endpoint here. Sending
      spammy, automated, or AI-generated replies that read as inauthentic
      may get your X account suspended under X's inauthentic-behavior
      rules and your SuperX account terminated. AI suggestions must be
      reviewed and meaningfully edited before they are sent, and you are
      solely responsible for what you post. Reply activity is logged and
      may be audited.
  - name: X Lookups
    description: |
      Read any public post, its top replies, any public profile, or an
      account's latest posts LIVE from X, rather than from SuperX's stored
      data.

      These are owner-scoped, so none of them take an `account_id`: nothing
      about a public lookup is per-X-account. They cost the tighter
      live-enrichment allowance and share a daily allowance of 300 live
      lookups with Ask SuperX inside the app, so use them for what you
      actually need rather than to sweep. Repeat lookups within 15 minutes
      may be served from a short-lived server-side cache.
  - name: Tools
    description: |
      The composer helpers from the SuperX app, over the API: rewrite a post,
      edit one selected piece of it, apply one preset rewrite, check a claim,
      or compare two versions.

      Every one of them returns TEXT and writes nothing. Nothing here is
      posted, scheduled or sent; save what you keep with
      `POST /v1/posts/draft` or `POST /v1/scheduled-posts`. They cost AI
      credits, measured from the models' real cost, and spend no live-data
      allowance.
  - name: Media
  - name: Workers
    description: |
      The posts the account's Workers have written, and the three things a
      person does with one: save it as a draft, schedule it, or dismiss it.

      A Worker is a scheduled AI writer set up in the SuperX app. Creating,
      editing and running one stays in the app, so there is no create or run
      endpoint here. What a run produces lands in the app's "To review" queue
      and is read with `GET /v1/workers/suggestions`.

      NOTHING HERE POSTS TO X. Drafting or scheduling a suggestion writes a
      post the user can see in the app and on `GET /v1/scheduled-posts`,
      exactly like the app's own buttons. AI output must be reviewed and
      meaningfully edited by a person before it goes out, so show the text to
      the user and confirm the time before you schedule anything.
  - name: Scheduling
  - name: Tags
  - name: Context
  - name: Queue
  - name: DMs
    description: |
      Queue direct messages into the account's own DM pipeline, and read or
      cancel what is waiting.

      NOTHING HERE SENDS A MESSAGE. `POST /v1/dm/campaigns` enqueues; the
      SuperX app's scheduler is what sends, within the account's daily and
      monthly DM limits, so the create response is counts, not deliveries.
      Unsent messages can be cancelled until the scheduler picks them up.

      You are responsible for the messages you queue. Unsolicited or
      automated bulk DMs may get an X account suspended under X's rules and
      a SuperX account terminated, so confirm the recipient list and the
      exact wording with the person on whose behalf you are queueing.
  - name: Articles
  - name: Meta
paths:
  /v1/posts/draft:
    post:
      tags:
        - Scheduling
      summary: Write post drafts in your voice
      description: |
        Writes post drafts from a brief, in the account's own voice. Nothing
        is scheduled and nothing is stored: the response is text for you to
        review and edit, then send to `POST /v1/scheduled-posts` to save a
        draft or schedule it.

        Every draft copies the SHAPE of a proven post, never its content.
        Pass one in `mirror` (the text of a post from `GET /v1/inspiration`
        works well), or leave `mirror` out and a proven shape is picked for
        you, optionally biased toward a `collection`.

        Voice: `mine` (default) writes as the account in `account_id`, from
        that account's own posts, style guide and rules (your main account
        when `account_id` is omitted), `creator` writes in a creator's style,
        and `hybrid` keeps the account's substance with the creator's flavor.
        The creator's style guide is prepared in the
        background the first time you name them; that first call returns
        `409 creator_style_pending` and the retry a minute later succeeds.

        Costs AI credits per draft (drafts that fail are refunded), and a
        call takes roughly 20 to 40 seconds. `Idempotency-Key` is NOT
        supported: generation is not idempotent, and a replay would produce
        different text anyway.
      operationId: draftPost
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - brief
              properties:
                brief:
                  type: string
                  minLength: 1
                  maxLength: 2000
                  description: >-
                    What the post should say: the data, angle, or notes to write
                    from.
                count:
                  type: integer
                  minimum: 1
                  maximum: 3
                  default: 1
                  description: How many drafts to write. Each one costs credits.
                voice:
                  type: string
                  enum:
                    - mine
                    - creator
                    - hybrid
                  default: mine
                  description: >-
                    Whose voice to write in. `mine` is the voice of the account
                    in `account_id`: its own posts, style guide and rules. Omit
                    `account_id` and that is your main account.
                creator:
                  type: string
                  description: >-
                    X handle to borrow style from, for example `@naval`.
                    Required when `voice` is `creator` or `hybrid`, rejected
                    when `voice` is `mine`.
                mirror:
                  type: string
                  minLength: 50
                  maxLength: 1500
                  description: >-
                    Plain text of a proven post whose shape to copy. Only the
                    form is reused, never the content. Pick a mirror with room
                    for your data: a two-line aphorism squeezes the facts out.
                    Omit to have a shape picked for you.
                collection:
                  type: string
                  description: >-
                    Format collection id to bias the picked shape toward, for
                    example `numbered_list` or `contrarian_take`. Used only when
                    `mirror` is omitted; an id that is unknown or not usable as
                    a mirror fails with `400 invalid_collection`, which lists
                    the ids that do work.
                instructions:
                  type: string
                  maxLength: 500
                  description: Extra style instructions for this batch.
                account_id:
                  type: string
                  description: >-
                    Any account you own, meaning your main account (the default
                    when omitted) or one linked to it. With `voice: mine` the
                    drafts use this account's own posts and style guide. An
                    account shared with you returns `403
                    writes_main_account_only`.
            examples:
              simple:
                summary: One draft in your own voice
                value:
                  brief: >-
                    We cut churn from 6.2% to 3.8% by replacing the onboarding
                    video with a 3-step checklist.
              mirrored:
                summary: Three drafts copying a proven post's shape
                value:
                  brief: >-
                    We shipped a public API. 40 developers signed up in 48
                    hours.
                  count: 3
                  mirror: >-
                    Most people think they need more discipline.


                    They do not.


                    They need a smaller first step. Discipline is what you build
                    after the habit already exists, not before.
              creator_voice:
                summary: Your substance, a creator's flavor
                value:
                  brief: Removing our free plan tripled conversion.
                  voice: hybrid
                  creator: '@naval'
      responses:
        '201':
          description: The generated drafts. Nothing was scheduled or stored.
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-Credits-Charged:
              $ref: '#/components/headers/X-Credits-Charged'
            X-Credits-Remaining:
              $ref: '#/components/headers/X-Credits-Remaining'
            X-Credits-Reset:
              $ref: '#/components/headers/X-Credits-Reset'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      drafts:
                        type: array
                        items:
                          type: object
                          properties:
                            text:
                              type: string
                              description: >-
                                The draft post text. Send it to `POST
                                /v1/scheduled-posts` when the user is happy with
                                it.
                            mirrored:
                              type: object
                              nullable: true
                              description: >-
                                Which proven shape this draft copied, or `null`
                                when the draft copied no shape (no usable one
                                was found and it was written from the brief
                                alone).
                              properties:
                                source:
                                  type: string
                                  enum:
                                    - you
                                    - collection
                                  description: >-
                                    `you` when you passed `mirror`, `collection`
                                    when a shape was picked for you.
                                collection:
                                  type: string
                                  description: >-
                                    Format collection the shape came from.
                                    Absent when `source` is `you`.
                                reference_id:
                                  type: string
                                  description: >-
                                    Id of the post whose shape was copied.
                                    Absent when `source` is `you`.
                      credits_charged:
                        type: integer
                        description: >-
                          AI credits kept for this call. Drafts that failed are
                          refunded and are not counted here.
              example:
                data:
                  drafts:
                    - text: >-
                        Most founders think they need better retention
                        strategies.


                        They do not.


                        They need simpler onboarding.
                      mirrored:
                        source: you
                  credits_charged: 3
        '400':
          description: >-
            Invalid or missing field (`invalid_parameter`), a `mirror` that
            cannot be used as a shape (`mirror_rejected`, with the reason), an
            unknown or unusable `collection` (`invalid_collection`), a `creator`
            SuperX has no posts for (`unknown_creator`), or a creator whose
            style guide could not be built at all (`creator_style_unavailable`,
            terminal: do not retry).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              example:
                error:
                  code: mirror_rejected
                  message: >-
                    That post cannot be used as a mirror (url). Pass the plain
                    text of a substantial post with no links and no engagement
                    bait.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: >-
            Read-only key (`insufficient_scope`), an account shared with you
            (`writes_main_account_only`), or a lapsed subscription (legacy
            string envelope).
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ErrorEnvelope'
                  - $ref: '#/components/schemas/LegacyErrorEnvelope'
              example:
                error:
                  code: writes_main_account_only
                  message: >-
                    Accounts shared with you are read-only through the API.
                    Drafting works on your own main and linked accounts.
        '404':
          $ref: '#/components/responses/AccountNotFound'
        '409':
          description: >-
            The creator's style guide is being prepared
            (`creator_style_pending`). It is ready in about a minute; retry the
            same request.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              example:
                error:
                  code: creator_style_pending
                  message: >-
                    Style guide for @naval is being prepared, retry in about a
                    minute.
        '429':
          description: >-
            Rate limited (`rate_limited`, honor `Retry-After`), the AI credit
            pool is used up (`ai_credits_exhausted`, with the credit counters),
            or the plan's daily cap on drafting runs is spent
            (`ai_action_limited`, honor `Retry-After`). No plan caps drafting
            today; the shape is documented so a future cap cannot surprise a
            client.
          headers:
            Retry-After:
              description: >-
                Seconds to wait before retrying. Sent on every flavour of this
                429.
              schema:
                type: integer
            X-Credits-Remaining:
              description: >-
                Credits left in the pool. Sent only on `ai_credits_exhausted`,
                never on `rate_limited` or `ai_action_limited`, which do not
                consult the pool.
              schema:
                type: integer
            X-Credits-Reset:
              description: >-
                Unix timestamp (seconds) when the pool refills. Sent only on
                `ai_credits_exhausted`, on the same terms as
                `X-Credits-Remaining`.
              schema:
                type: integer
          content:
            application/json:
              schema:
                anyOf:
                  - $ref: '#/components/schemas/CreditExhaustedError'
                  - $ref: '#/components/schemas/ActionLimitedError'
                  - $ref: '#/components/schemas/ErrorEnvelope'
              example:
                error:
                  code: ai_credits_exhausted
                  message: Not enough AI credits. Resets in 5 hours.
                  credits_required: 9
                  credits_remaining: 2
                  reset_at: 1790812800
        '500':
          $ref: '#/components/responses/InternalError'
        '502':
          description: >-
            Every draft failed to generate (`generation_failed`). All credits
            for the call were refunded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              example:
                error:
                  code: generation_failed
                  message: >-
                    Drafting failed and no credits were spent. Try again
                    shortly.
components:
  headers:
    X-RateLimit-Limit:
      description: The limit of the rate window closest to exhaustion.
      schema:
        type: integer
    X-RateLimit-Remaining:
      description: Requests remaining in that window.
      schema:
        type: integer
    X-RateLimit-Reset:
      description: Unix timestamp (seconds) when that window resets.
      schema:
        type: integer
    X-Credits-Charged:
      description: >-
        AI credits kept for this call. Sent on every endpoint that settles its
        charge before answering, which is all of them except the ones that
        answer 202 and finish in the background.
      schema:
        type: integer
    X-Credits-Remaining:
      description: AI credits left in the account's pool, bonus credits included.
      schema:
        type: integer
    X-Credits-Reset:
      description: Unix timestamp (seconds) when the AI credit pool refills.
      schema:
        type: integer
  schemas:
    ErrorEnvelope:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              description: Stable machine-readable error code.
            message:
              type: string
            retry_after:
              type: integer
              description: Seconds to wait before retrying (rate-limit errors only).
    LegacyErrorEnvelope:
      type: object
      required:
        - error
      description: |
        Legacy shape used ONLY by the shared subscription middleware: a plain
        string `error` field. Seen on `403` when the subscription has lapsed
        (string starts with "subscription_required:") and on `500` when
        subscription verification fails (string starts with "internal_error:").
      properties:
        error:
          type: string
          example: >-
            subscription_required: The SuperX API requires an active
            subscription
    CreditExhaustedError:
      type: object
      required:
        - error
      description: |
        The `429 ai_credits_exhausted` body: the standard envelope plus the
        credit counters. Sent with a `Retry-After` header and the
        `X-Credits-Remaining` / `X-Credits-Reset` headers. `code` is stable;
        the counters are additive fields, safe to ignore.
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              enum:
                - ai_credits_exhausted
            message:
              type: string
            credits_required:
              type: integer
              description: Credits the call needed.
            credits_remaining:
              type: integer
              nullable: true
              description: Credits available when it was refused.
            reset_at:
              type: integer
              nullable: true
              description: Unix timestamp (seconds) when the pool refills.
    ActionLimitedError:
      type: object
      required:
        - error
      description: |
        The `429 ai_action_limited` body: a per-day cap on how many times an
        expensive action can run, counted separately from the credit pool and
        from the request rate limits. Sent with a `Retry-After` header. Caps
        reset at midnight UTC.

        Read `scope` before telling a user anything: `account` means the
        plan's own daily cap for that action, `platform` means the
        platform-wide fair-use ceiling on live-data actions, which is shared
        with every SuperX account. A `platform` refusal is not about this
        account's quota, so wait and retry rather than reporting the account
        as out.
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              enum:
                - ai_action_limited
            message:
              type: string
            scope:
              type: string
              enum:
                - account
                - platform
              description: |
                Whose ceiling refused the call: this account's own per-day cap
                for the action, or the platform-wide fair-use ceiling on
                live-data actions.
            retry_after:
              type: integer
              description: Seconds to wait before the cap resets.
            reset_at:
              type: integer
              description: Unix seconds when the cap resets (the next UTC midnight).
  responses:
    Unauthorized:
      description: >-
        Missing/malformed Authorization header (`unauthorized`) or an
        unknown/revoked key (`invalid_api_key`).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            error:
              code: invalid_api_key
              message: Unknown or revoked API key
    AccountNotFound:
      description: account_id is not one of your accounts.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            error:
              code: account_not_found
              message: No account with that id belongs to this key
    InternalError:
      description: >-
        Unexpected server error. May also use the legacy string envelope when
        subscription verification fails.
      content:
        application/json:
          schema:
            oneOf:
              - $ref: '#/components/schemas/ErrorEnvelope'
              - $ref: '#/components/schemas/LegacyErrorEnvelope'
          example:
            error:
              code: internal_error
              message: Failed to fetch posts
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      description: >-
        A SuperX API key ("sxk_..."), created in the SuperX app under Account >
        API / MCP / CLI. Keys are server-side secrets.

````