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

# TypeScript Types for X API Requests

> Use TypeScript definitions for tweets, profiles, followers, monitors, webhooks, extractions, write actions, pagination, and API errors.

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

Copy-pasteable TypeScript helpers for common Xquik API objects. Use these for prototypes, docs examples, and lightweight clients. For complete generated coverage, use the [OpenAPI spec](https://docs.xquik.com/openapi.yaml) or an [official SDK](/sdks).

## Usage

3 ways to use these types in your project:

1. **Copy curated types** - copy the "Response types", "Request types", and "Shared types" tabs into a single `xquik-types.ts` file
2. **Copy individual interfaces** - grab only the types you need (e.g. `Tweet`, `EventList`)
3. **Generate full coverage from OpenAPI** - use the [OpenAPI spec](https://docs.xquik.com/openapi.yaml) with tools like `openapi-typescript` to auto-generate types:
   ```bash theme={null}
   npx openapi-typescript https://docs.xquik.com/openapi.yaml -o xquik-api.d.ts
   ```

<Tip>
  For production projects, option 3 or an official SDK is the safest source for complete coverage. For quick prototypes, copy only the interfaces you need.
</Tip>

<Tabs>
  <Tab title="Response types">
    Response objects returned by API endpoints.

    ```typescript theme={null}
    // ─── Account ─────────────────────────────────────────────

    interface Account {
      plan: "active" | "inactive";
      monitorsAllowed: number;
      monitorsUsed: number;
      creditInfo?: {
        balance: number;
        lifetimePurchased: number;
        lifetimeUsed: number;
        autoTopupEnabled: boolean;
      };
      xUsername?: string;
    }

    // ─── API Keys ────────────────────────────────────────────

    // Returned when creating a new key (includes full key)
    interface ApiKeyCreated {
      id: string;
      fullKey: string;
      prefix: string;
      name: string;
      createdAt: string;
    }

    // Returned when listing keys (full key is never exposed)
    interface ApiKey {
      id: string;
      name: string;
      prefix: string;
      isActive: boolean;
      createdAt: string;
      lastUsedAt?: string;
    }

    // ─── Monitors ────────────────────────────────────────────

    interface Monitor {
      id: string;
      username: string;
      xUserId: string;
      eventTypes: EventType[];
      isActive: boolean;
      createdAt: string;
      nextBillingAt: string;
    }

    interface KeywordMonitor {
      id: string;
      query: string;
      eventTypes: EventType[];
      isActive: boolean;
      createdAt: string;
      nextBillingAt: string;
    }

    // ─── Events ──────────────────────────────────────────────

    interface Event {
      id: string;
      type: EventType;
      monitorId: string;
      monitorType: "account" | "keyword";
      occurredAt: string;
      data: EventData;
      username?: string;
      query?: string;
      keywordMonitorId?: string;
      xEventId?: string;
    }

    interface EventList {
      events: Event[];
      hasMore: boolean;
      nextCursor?: string;
    }

    // ─── Webhooks ────────────────────────────────────────────

    // Returned when creating a webhook (includes signing secret)
    interface WebhookCreated {
      id: string;
      url: string;
      eventTypes: EventType[];
      secret: string;
      createdAt: string;
    }

    // Returned when listing webhooks (secret is never exposed)
    interface Webhook {
      id: string;
      url: string;
      eventTypes: EventType[];
      isActive: boolean;
      createdAt: string;
    }

    // ─── Deliveries ──────────────────────────────────────────

    interface Delivery {
      id: string;
      streamEventId: string;
      status: "pending" | "delivered" | "failed" | "exhausted";
      attempts: number;
      lastStatusCode?: number;
      lastError?: string;
      createdAt: string;
      deliveredAt?: string;
    }

    // ─── Webhook Payload ─────────────────────────────────────

    interface WebhookPayload {
      eventType: EventType;
      schemaVersion: 1;
      deliveryId: string;
      streamEventId: string;
      occurredAt: string;
      data: EventData;
      username?: string;
      query?: string;
    }

    interface WebhookTestPayload {
      eventType: "webhook.test";
      data: { message: string };
      timestamp: string;
    }

    // ─── Draws ──────────────────────────────────────────────

    interface Draw {
      id: string;
      tweetId: string;
      tweetUrl: string;
      tweetText: string;
      tweetAuthorUsername: string;
      tweetLikeCount: number;
      tweetRetweetCount: number;
      tweetReplyCount: number;
      tweetQuoteCount: number;
      status: "pending" | "running" | "completed" | "failed";
      totalEntries: number;
      validEntries: number;
      createdAt: string;
      drawnAt?: string;
    }

    interface DrawListItem {
      id: string;
      tweetUrl: string;
      status: "pending" | "running" | "completed" | "failed";
      totalEntries: number;
      validEntries: number;
      createdAt: string;
      drawnAt?: string;
    }

    interface DrawWinner {
      position: number;
      authorUsername: string;
      tweetId: string;
      isBackup: boolean;
    }

    interface DrawList {
      draws: DrawListItem[];
      hasMore: boolean;
      nextCursor?: string;
    }

    // ─── Extractions ────────────────────────────────────────

    interface ExtractionJob {
      id: string;
      toolType: ExtractionToolType;
      status: "pending" | "running" | "completed" | "failed";
      totalResults: number;
      targetTweetId?: string;
      targetUsername?: string;
      targetUserId?: string;
      targetCommunityId?: string;
      searchQuery?: string;
      errorMessage?: string;
      createdAt: string;
      completedAt?: string;
    }

    interface ExtractionResult {
      id: string;
      xUserId: string;
      xUsername?: string;
      xDisplayName?: string;
      xFollowersCount?: number;
      xVerified?: boolean;
      xProfileImageUrl?: string;
      tweetId?: string;
      tweetText?: string;
      tweetCreatedAt?: string;
      createdAt: string;
      enrichmentData?: Record<string, unknown>;
    }

    interface ExtractionList {
      extractions: ExtractionJob[];
      hasMore: boolean;
      nextCursor?: string;
    }

    interface ExtractionEstimate {
      allowed: boolean;
      source: "replyCount" | "retweetCount" | "quoteCount" | "followers" | "resultsLimit" | "unknown";
      estimatedResults: number;
      creditsRequired: string;
      creditsAvailable: string;
      resolvedXUserId?: string;
    }

    // ─── X API ──────────────────────────────────────────────

    interface Tweet {
      id: string;
      text: string;
      type?: string;
      createdAt?: string;
      retweetCount?: number;
      replyCount?: number;
      likeCount?: number;
      quoteCount?: number;
      viewCount?: number;
      bookmarkCount?: number;
      media?: TweetMediaItem[];
      url?: string;
      lang?: string;
      isReply?: boolean;
      inReplyToId?: string;
      inReplyToUserId?: string;
      inReplyToUsername?: string;
      conversationId?: string;
      source?: string;
      displayTextRange?: number[];
      isNoteTweet?: boolean;
      isQuoteStatus?: boolean;
      isLimitedReply?: boolean;
      entities?: Record<string, unknown>;
      author?: UserProfile;
      quoted_tweet?: Tweet;
      retweeted_tweet?: Tweet;
    }

    interface TweetAuthor {
      id: string;
      username: string;
      followers: number;
      verified: boolean;
      profilePicture?: string;
    }

    interface TweetSearchResult {
      id: string;
      text: string;
      createdAt: string;
      likeCount: number;
      retweetCount: number;
      replyCount: number;
      author: {
        id: string;
        username: string;
        name: string;
        verified: boolean;
      };
      media?: TweetMediaItem[];
    }

    interface UserProfile {
      id: string;
      username: string;
      name: string;
      description?: string;
      followers?: number;
      following?: number;
      verified?: boolean;
      profilePicture?: string;
      coverPicture?: string;
      location?: string;
      createdAt?: string;
      statusesCount?: number;
      mediaCount?: number;
      canDm?: boolean;
      url?: string;
      favouritesCount?: number;
      hasCustomTimelines?: boolean;
      isTranslator?: boolean;
      withheldInCountries?: string[];
      possiblySensitive?: boolean;
      pinnedTweetIds?: string[];
      isAutomated?: boolean;
      automatedBy?: string;
      unavailable?: boolean;
      unavailableReason?: string;
      verifiedType?: string;
      profile_bio?: Record<string, unknown>;
    }

    interface FollowerCheck {
      sourceUsername: string;
      targetUsername: string;
      isFollowing: boolean;
      isFollowedBy: boolean;
    }

    // ─── Trends ─────────────────────────────────────────────

    interface Trend {
      name: string;
      description?: string;
      rank?: number;
      query?: string;
    }

    interface TrendList {
      trends: Trend[];
      total: number;
      woeid: number;
    }

    // ─── Radar ──────────────────────────────────────────────

    interface RadarItem {
      id: string;
      title: string;
      description?: string;
      url?: string;
      imageUrl?: string;
      source: RadarSource;
      sourceId: string;
      category: RadarCategory;
      region: string;
      language: string;
      score: number;
      metadata: Record<string, unknown>;
      publishedAt: string;
      createdAt: string;
    }

    interface RadarList {
      items: RadarItem[];
      hasMore: boolean;
      nextCursor?: string;
    }

    // ─── Styles ─────────────────────────────────────────────

    interface StyleProfile {
      xUsername: string;
      isOwnAccount: boolean;
      tweetCount: number;
      fetchedAt: string;
      tweets: StyleTweet[];
    }

    interface StyleListItem {
      xUsername: string;
      isOwnAccount: boolean;
      tweetCount: number;
      fetchedAt: string;
    }

    interface StyleList {
      styles: StyleListItem[];
    }

    interface StyleComparison {
      style1: StyleProfile;
      style2: StyleProfile;
    }

    interface PerformanceAnalysis {
      xUsername: string;
      tweetCount: number;
      tweets: PerformanceTweet[];
    }

    // ─── Drafts ─────────────────────────────────────────────

    interface Draft {
      id: string;
      text: string;
      topic?: string;
      goal?: "engagement" | "followers" | "authority" | "conversation";
      createdAt: string;
      updatedAt: string;
    }

    interface DraftList {
      drafts: Draft[];
      hasMore: boolean;
      nextCursor?: string;
    }

    // ─── X Accounts ───────────────────────────────────────────

    interface XAccount {
      id: string;
      username: string;
      displayName: string;
      isActive: boolean;
      createdAt: string;
    }

    // ─── Compose ──────────────────────────────────────────────

    interface RadarRecommendation {
      endpoint: string;
      guidance: string;
      source: RadarSource;
      useFor: string;
    }

    // step="compose" response
    interface ComposeTweetResult {
      contentRules: { rule: string }[];
      engagementMultipliers: { action: string; multiplier: string }[];
      engagementVelocity: string;
      followUpQuestions: string[];
      intentUrl: string;
      nextStep: string;
      radarRecommendations: RadarRecommendation[];
      savedStyles?: { tweetCount: number; username: string }[];
      scorerWeights: { signal: string; weight: null; context: string }[];
      source: string;
      styleNote?: string;
      styleTweets?: string[];
      topPenalties: string[];
    }

    // step="refine" response
    interface RefineTweetResult {
      compositionGuidance: string[];
      examplePatterns: { description: string; pattern: string }[];
      intentUrl: string;
      nextStep: string;
    }

    // step="score" response
    interface ScoreTweetResult {
      passed: boolean;
      passedCount: number;
      totalChecks: number;
      topSuggestion: string;
      nextStep: string;
      checklist: { factor: string; passed: boolean; suggestion?: string }[];
      intentUrl?: string;
    }

    // ─── X Write ──────────────────────────────────────────────

    interface XWriteResponse {
      success: boolean;
      data?: Record<string, unknown>;
    }

    // ─── Support Tickets ──────────────────────────────────────

    interface SupportTicket {
      publicId: string;
      subject: string;
      status: "open" | "in_progress" | "resolved" | "closed";
      messageCount: number;
      createdAt: string;
      updatedAt: string;
    }

    interface SupportTicketDetail {
      publicId: string;
      subject: string;
      status: "open" | "in_progress" | "resolved" | "closed";
      createdAt: string;
      updatedAt: string;
      messages: SupportMessage[];
    }

    interface SupportMessage {
      body: string;
      sender: "user" | "support";
      createdAt: string;
    }

    // ─── Error Response ──────────────────────────────────────

    type ApiErrorType =
      | "api_error"
      | "authentication_error"
      | "billing_error"
      | "dependency_error"
      | "invalid_request_error"
      | "permission_error"
      | "rate_limit_error";

    interface StructuredApiError {
      message: string;
      type: ApiErrorType;
      code: string;
    }

    interface ApiError {
      error: string | StructuredApiError;
      message?: string;
      reason?: string;
      retryAfter?: number;
      retryAfterMs?: number;
    }
    ```
  </Tab>

  <Tab title="Request types">
    Request body types for POST/PATCH endpoints.

    ```typescript theme={null}
    interface CreateMonitorRequest {
      username: string;
      eventTypes: EventType[];
    }

    interface UpdateMonitorRequest {
      eventTypes?: EventType[];
      isActive?: boolean;
    }

    interface CreateWebhookRequest {
      url: string;
      eventTypes: EventType[];
    }

    interface UpdateWebhookRequest {
      url?: string;
      eventTypes?: EventType[];
      isActive?: boolean;
    }

    interface CreateApiKeyRequest {
      name?: string;
    }

    interface CreateDrawRequest {
      tweetUrl: string;
      winnerCount?: number;
      backupCount?: number;
      uniqueAuthorsOnly?: boolean;
      mustRetweet?: boolean;
      mustFollowUsername?: string;
      filterMinFollowers?: number;
      filterAccountAgeDays?: number;
      filterLanguage?: string;
      requiredKeywords?: string[];
      requiredHashtags?: string[];
      requiredMentions?: string[];
    }

    interface CreateExtractionRequest {
      toolType: ExtractionToolType;
      targetTweetId?: string;
      targetUsername?: string;
      targetCommunityId?: string;
      targetListId?: string;
      targetSpaceId?: string;
      searchQuery?: string;
      resultsLimit?: number;
    }

    interface CreateDraftRequest {
      text: string;
      topic?: string;
      goal?: "engagement" | "followers" | "authority" | "conversation";
    }

    interface ComposeRequest {
      step: "compose" | "refine" | "score";
      topic?: string;
      goal?: ComposeTweetGoal;
      styleUsername?: string;
      tone?: string;
      additionalContext?: string;
      callToAction?: string;
      hasLink?: boolean;
      /** @deprecated Accepted for compatibility. Text checks ignore it. */
      hasMedia?: boolean;
      mediaType?: MediaType;
      draft?: string;
    }
    ```
  </Tab>

  <Tab title="Shared types">
    Enums and shared types used across request and response objects.

    ```typescript theme={null}
    type EventType =
      | "tweet.new"
      | "tweet.quote"
      | "tweet.reply"
      | "tweet.retweet"
      | "tweet.media"
      | "tweet.link"
      | "tweet.poll"
      | "tweet.mention"
      | "tweet.hashtag"
      | "tweet.longform"
      | "profile.avatar.changed"
      | "profile.banner.changed"
      | "profile.name.changed"
      | "profile.username.changed"
      | "profile.bio.changed"
      | "profile.location.changed"
      | "profile.url.changed"
      | "profile.verified.changed"
      | "profile.protected.changed"
      | "profile.pinned_tweet.changed"
      | "profile.unavailable.changed";

    // The data field contains the tweet object stored with the monitor event.
    interface TweetEventData {
      id: string;
      text: string;
      author: {
        id: string;
        userName: string;
        name: string;
      };
      isRetweet: boolean;
      isReply: boolean;
      isQuote: boolean;
      createdAt: string;
      inReplyToId?: string;
      quoted_tweet?: {
        id: string;
        text: string;
        author: { userName: string };
      };
    }

    type EventData = TweetEventData;

    interface EventFilters {
      keywords?: { include?: string[]; exclude?: string[] };
      minLikes?: number;
      minRetweets?: number;
      verifiedOnly?: boolean;
    }

    type ExtractionToolType =
      | "article_extractor"
      | "community_extractor"
      | "community_moderator_explorer"
      | "community_post_extractor"
      | "community_search"
      | "favoriters"
      | "follower_explorer"
      | "following_explorer"
      | "list_follower_explorer"
      | "list_member_extractor"
      | "list_post_extractor"
      | "mention_extractor"
      | "people_search"
      | "post_extractor"
      | "quote_extractor"
      | "reply_extractor"
      | "repost_extractor"
      | "space_explorer"
      | "thread_extractor"
      | "tweet_search_extractor"
      | "user_likes"
      | "user_media"
      | "verified_follower_explorer";

    type ComposeTweetGoal = "authority" | "conversation" | "engagement" | "followers";
    type MediaType = "none" | "photo" | "video";

    type RadarSource = string;

    type RadarCategory =
      | "business"
      | "culture"
      | "dev"
      | "entertainment"
      | "general"
      | "politics"
      | "science"
      | "tech";

    interface TweetMediaItem {
      mediaUrl: string;
      type: string;
      url: string;
    }

    interface StyleTweet {
      id: string;
      authorUsername: string;
      text: string;
      createdAt: string;
      media?: TweetMediaItem[];
    }

    interface PerformanceTweet {
      id: string;
      text: string;
      likeCount: number;
      retweetCount: number;
      replyCount: number;
      quoteCount: number;
      viewCount: number;
      bookmarkCount: number;
    }
    ```
  </Tab>
</Tabs>

## REST API vs MCP Field Naming

<Info>
  REST examples show the default v1 response contract unless they send
  `xquik-api-contract: 2026-04-29`. API MCP v2.6.0 sends that contract
  automatically. MCP results use snake\_case, Unix timestamps, structured
  errors, `has_more`, and `next_cursor`. Pass `next_cursor` as `cursor` on
  tweet, profile, follower, reply, timeline, community, and list pages. Use
  `after` for draws, extractions, events, and Radar. Use `afterCursor` for
  drafts. A default `createdAt` field becomes `created`.
</Info>

## Type reference

### Account

Returned by `GET /api/v1/account`. The `creditInfo` field is omitted when no credit balance record exists yet. `creditInfo.balance` shows the current credit count available for metered API calls.

### API Keys

Two shapes exist: `ApiKeyCreated` is returned only from `POST /api/v1/api-keys` and includes the `fullKey` field. This is the only time the full key is exposed. `ApiKey` is returned by `GET /api/v1/api-keys` and shows only the `prefix` (first 8 characters) for identification.

### Monitors

Account monitor endpoints return `Monitor`. The `xUserId` is the X (Twitter) user ID resolved from the `username` at creation time. Keyword monitor endpoints return `KeywordMonitor` with the normalized X search `query`. Both monitor types include `eventTypes`, `isActive`, `createdAt`, and `nextBillingAt` for active monitor billing.

### Events

`Event` represents a single tracked action from an account or keyword monitor. `monitorType` is `account` or `keyword`; `monitorId` points to the source monitor. Account events include `username`; keyword events include `query` and `keywordMonitorId`. The `data` field contains tweet event data with `id`, `text`, `author`, `isRetweet`, `isReply`, `isQuote`, and `createdAt`. Replies include `inReplyToId`, quotes include a nested `quoted_tweet` object. Retweets are identified by `isRetweet: true`. See the `TweetEventData` interface in the Shared types tab for the full shape. `EventList` wraps paginated responses. Use `nextCursor` with the `after` query parameter to fetch subsequent pages.

### Webhooks

Similar to API keys, webhooks have two shapes. `WebhookCreated` includes the `secret` field used for HMAC signature verification. `Webhook` (from list) never exposes the secret. If you lose the secret, delete and recreate the webhook.

### Deliveries

Each `Delivery` represents one attempt to send an event to a webhook endpoint. Status progresses from `pending` to `delivered` (success) or through `failed` to `exhausted` (all retries failed). `lastStatusCode` and `lastError` help diagnose delivery failures.

### Webhook payload

The `WebhookPayload` type describes the JSON body your endpoint receives on each delivery. Normal monitor events include `schemaVersion`, `deliveryId`, `streamEventId`, `occurredAt`, `eventType`, and `data`. Account monitor events include `username`; keyword monitor events include `query`. Verify authenticity with the `X-Xquik-Signature` header and your webhook secret. See [Webhook Verification](/webhooks/verification) for implementation details.

<Note>
  `webhook.test` payloads include `timestamp` and omit monitor-only fields because they are not tied to a stored event. In normal event payloads, `timestamp` is omitted.
</Note>

### Draws

`Draw` is the full draw object returned by `GET /api/v1/draws/{id}` with tweet metadata and engagement counts. `DrawListItem` is the compact shape returned in list responses. `DrawWinner` contains the position, username, tweet ID, and backup flag for each winner. Filter fields on `CreateDrawRequest` control which entries qualify for the draw.

### Extractions

`ExtractionJob` represents a completed or failed extraction job. The target fields (`targetTweetId`, `targetUsername`, etc.) vary by `toolType`. `ExtractionResult` contains the core user and tweet data returned by the API. Results are paginated in the get endpoint with up to 1,000 results per page. Exports (CSV, XLSX, Markdown) include additional enrichment columns not present in the API response. See [Export Extraction](/api-reference/extractions/export) for the full column list. `ExtractionEstimate` previews the cost before running a job.

### X API

Tweet, profile, and relationship lookup types. `Tweet` and `TweetAuthor` come
from tweet lookup. `TweetSearchResult` includes an inline `author` object.
`UserProfile` contains the full profile. `FollowerCheck` returns the
bidirectional follow relationship between 2 users. `Tweet` and
`TweetSearchResult` include an optional `media` array when media exists. Media
types are `photo`, `video`, or `animated_gif`.

### Trends

`Trend` represents a single trending topic on X. The `description`, `rank`, and `query` fields are omitted when unavailable. `TrendList` wraps the `GET /api/v1/trends` response. `total` is the number of trends returned, `woeid` is the region ID.

### Radar

`RadarItem` represents a single trending topic or news item from Xquik's own
infrastructure. The `source` field identifies the Radar stream. Reddit metadata
can include post text, links, and media. It can also include public scores,
estimated vote counts, and comment counts. It never includes comment bodies.
Startup growth metadata can include reported growth and revenue. Company details
and a founder `xHandle` appear when available.
`RadarList` wraps paginated responses from `GET /api/v1/radar`. Use
`nextCursor` with the `after` query parameter to fetch subsequent pages.

### Styles

`StyleProfile` is returned by the analyze style (`POST /api/v1/styles`) and get style (`GET /api/v1/styles/{id}`) endpoints. It includes the cached tweets array with text, media, and timestamps. `StyleListItem` is the compact shape returned by `GET /api/v1/styles` (no tweets). `StyleComparison` wraps two full profiles for side-by-side comparison. `PerformanceAnalysis` adds engagement metrics (likes, retweets, replies, quotes, views, bookmarks) to each cached tweet. `isOwnAccount` is `true` when the analyzed username matches the authenticated user's linked X identity.

### Drafts

`Draft` represents a saved tweet draft. List, create, and get responses include `id`, `text`, `createdAt`, and `updatedAt`. Optional `topic` and `goal` fields are omitted (not null) when not set. `DraftList` wraps paginated responses. Use `nextCursor` with the `afterCursor` query parameter to fetch subsequent pages. Maximum 50 drafts per page.

### X Accounts

`XAccount` represents a linked X account. `displayName` is the user's display name on X. `isActive` indicates whether the account is currently connected and usable for API operations.

### Compose

`ComposeRequest` drives a 3-step writing flow. `compose` returns editorial rules
and follow-up questions. It also returns 7 `radarRecommendations`, published
signal names, and a topic `intentUrl`. Each recommendation identifies its
endpoint, source, use case, and drafting guidance. Production signal weights are
`null` because X does not publish them. `refine` returns writing guidance and 3
example patterns. `score` runs 9 deterministic text checks. These checks do not
predict reach. `styleUsername` selects a cached style.
Compose responses may include `savedStyles`, `styleTweets`, or
`styleNote`.

### X Write

`XWriteResponse` is returned by write operations (post, retweet, like, reply). `success` indicates whether the operation completed. The optional `data` field contains platform-specific response data when available.

### Support tickets

`SupportTicket` is the compact shape returned in list responses. `SupportTicketDetail` includes the full `messages` array. Each `SupportMessage` has a `sender` field indicating whether the message is from the user or support team. Status progresses from `open` through `in_progress` to `resolved` or `closed`.

### Request bodies

All request body types use optional fields for update operations (PATCH) and required fields for creation (POST). The API validates request bodies and returns `400 invalid_input` for missing or malformed fields.
