openapi: 3.1.0
info:
title: Xquik API
version: '1.0'
description: "Xquik is an independent third-party service. Not affiliated with X Corp. \"Twitter\" and \"X\" are trademarks\
\ of X Corp. Look up tweets, users, and X trends. Search tweets, check follow relationships, download media, and monitor\
\ accounts. 33 paid-read endpoints accept prepaid credits without a subscription. 7 fixed-price lookups also accept direct\
\ MPP payments. Write and automation endpoints require an API key or OAuth 2.1 bearer token.\n\n## Xquik SDKs\n\nStainless\
\ generates each SDK from this OpenAPI schema. Pick a language:\n\n- TypeScript / Node.js: `npm i x-twitter-scraper` -\n\
\ [Xquik-dev/x-twitter-scraper-typescript](https://github.com/Xquik-dev/x-twitter-scraper-typescript)\n\n- Python: `pip\
\ install x-twitter-scraper` -\n [Xquik-dev/x-twitter-scraper-python](https://github.com/Xquik-dev/x-twitter-scraper-python)\n\
\n- Go: `go get github.com/Xquik-dev/x-twitter-scraper-go` -\n [Xquik-dev/x-twitter-scraper-go](https://github.com/Xquik-dev/x-twitter-scraper-go)\n\
\n- Ruby: `gem install x-twitter-scraper` -\n [Xquik-dev/x-twitter-scraper-ruby](https://github.com/Xquik-dev/x-twitter-scraper-ruby)\n\
\n- Java (source build; Maven Central pending) -\n [Xquik-dev/x-twitter-scraper-java](https://github.com/Xquik-dev/x-twitter-scraper-java)\n\
\n- Kotlin (source build; Maven Central pending) -\n [Xquik-dev/x-twitter-scraper-kotlin](https://github.com/Xquik-dev/x-twitter-scraper-kotlin)\n\
\n- C# / .NET: `dotnet add package XTwitterScraper` -\n [Xquik-dev/x-twitter-scraper-csharp](https://github.com/Xquik-dev/x-twitter-scraper-csharp)\n\
\n- PHP: `composer require xquik/x-twitter-scraper` -\n [Xquik-dev/x-twitter-scraper-php](https://github.com/Xquik-dev/x-twitter-scraper-php)\n\
\n- CLI: `go install github.com/Xquik-dev/x-twitter-scraper-cli/cmd/x-twitter-scraper@latest` -\n [Xquik-dev/x-twitter-scraper-cli](https://github.com/Xquik-dev/x-twitter-scraper-cli)\n\
\n- Terraform Provider (Terraform Registry) -\n [Xquik-dev/terraform-provider-x-twitter-scraper](https://github.com/Xquik-dev/terraform-provider-x-twitter-scraper)\n\
\n\nOpenClaw plugin: [Xquik-dev/tweetclaw](https://github.com/Xquik-dev/tweetclaw) (`openclaw plugins install clawhub:@xquik/tweetclaw`)."
x-guidance: '## Common tasks
**Find a tweet** - GET /x/tweets/{id} with a numeric tweet ID. Returns full tweet data: text, author, metrics (likes,
retweets, replies, views), media URLs, and creation timestamp. Cost: $0.00015 per lookup.
**Search tweets** - GET /x/tweets/search?q={query}&limit={n}. Supports X search operators, structured filters like fromUser,
mediaType, minFaves, hashtags, and verifiedOnly, plus exact lookup for a pasted Tweet ID or X status URL. Plain from:user
date windows are optimized for timeline completeness. Returns up to 200 tweets per page with cursor-based pagination.
Cost: $0.00015 per tweet returned.
**Find a user** - GET /x/users/{id} where {id} is a numeric user ID or @username. Returns profile data: name, bio, follower/following
counts, verification status, join date. Cost: $0.00015 per lookup.
**Check if A follows B** - GET /x/followers/check?source={a}&target={b} where source and target are usernames, @usernames,
or X or Twitter profile URLs. Cost: $0.00075.
**Get trending topics** - GET /trends?woeid={region}&count={n}. WOEID 1 = worldwide, 23424977 = US, 23424975 = UK, 23424969
= Turkey. Cost: $0.00045.
**Download media** - POST /x/media/download with {"tweetIds": ["123", "456"]} body. Returns download URLs for images and
videos. Cost: 1 credit per fresh tweet processed with media; cached repeat downloads are free.
**Read an article** - GET /x/articles/{tweetId} for long-form X Articles. Returns full article HTML, cover image, and
metadata. Cost: $0.00075.
## Pagination
Default v1 responses keep their existing pagination fields for compatibility. Platform list endpoints return `hasMore`
and `nextCursor`; X data endpoints return `has_next_page` and `next_cursor`. Send `xquik-api-contract: 2026-04-29` to
receive the unified best-practice fields `has_more` and `next_cursor`. Pass the cursor back as `?cursor={cursor}`; legacy
`?after={cursor}` still works. Dynamic-priced endpoints charge per item returned, not per request.
## Authentication
Eligible paid read endpoints accept accountless prepaid credit wallets. Fixed-price lookups also accept direct MPP payments.
Media downloads, write endpoints, and automation features require authentication. Send an Xquik API key through `x-api-key`,
`Xquik-Api-Key`, or `Authorization: Bearer xq_...`. Send an OAuth 2.1 access token through `Authorization: Bearer`.
## Best-Practice Response Contract
v1 keeps its original response contract by default so existing integrations do not break. Send `xquik-api-contract: 2026-04-29`
to opt in to the best-practice contract: snake_case response fields, Unix timestamps in seconds, structured error objects,
`has_more` and `next_cursor` pagination fields, `object` resource identifiers, and prefixed IDs where available. Dependency
failures that returned 502 in default v1 return 424 in the opt-in contract. Future major API versions should make this
contract the default.'
contact:
name: Xquik
url: https://xquik.com
email: support@xquik.com
servers:
- url: https://xquik.com
x-service-info:
categories:
- data
docs:
homepage: https://xquik.com
apiReference: https://docs.xquik.com
llms: https://docs.xquik.com/llms.txt
x-discovery:
ownershipProofs:
- dns:xquik.com
security:
- apiKey: []
- oauthBearer: []
tags:
- name: API Keys
description: API key management (session auth only)
- name: Account
description: Account info and settings
- name: Articles
description: Long-form X Article extraction
- name: Communities
description: X Community info, members, and tweets
- name: Composition
description: AI tweet composition, drafts, writing styles, and radar
- name: Draws
description: Giveaway draws from tweet replies
- name: Events
description: Activity events from monitored accounts
- name: Extractions
description: Bulk data extraction (23 tool types)
- name: Guest Wallets
description: Accountless prepaid access for paid read endpoints
- name: Lists
description: X List followers, members, and tweets
- name: Media
description: Media upload and download
- name: Monitors
description: X account monitoring with 1-second checks
- name: Subscribe
description: Subscription, billing, and credits
- name: Support
description: Support ticket management
- name: Trends
description: Trending topics and hashtags by region
- name: Tweets
description: Look up, search, and analyze individual tweets
- name: Users
description: Look up, search, and explore user profiles and relationships
- name: Webhooks
description: Webhook endpoint management and delivery
- name: X Accounts
description: Connected X account management
- name: X Write
description: X write actions (tweets, likes, follows, DMs)
paths:
/api/v1/account:
get:
operationId: getAccount
summary: Get account info
tags:
- Account
security:
- apiKey: []
- oauthBearer: []
responses:
'200':
description: Account info
content:
application/json:
schema:
type: object
required:
- plan
- monitorsUsed
- monitorsAllowed
- monitorBilling
properties:
plan:
type: string
enum:
- active
- inactive
example: active
monitorsUsed:
type: integer
example: 3
monitorsAllowed:
type: integer
deprecated: true
x-stainless-deprecation-message: Monitor slots are unlimited. Use monitorBilling.unlimitedSlots instead.
description: Deprecated. Monitor slots are unlimited, so this is always Number.MAX_SAFE_INTEGER.
example: 9007199254740991
monitorBilling:
type: object
required:
- activeDailyEstimate
- activeHourlyBurn
- creditsPerActiveMonitorDay
- creditsPerActiveMonitorHour
- eventsIncluded
- instantCheckIntervalSeconds
- unlimitedSlots
properties:
activeDailyEstimate:
type: string
description: Estimated daily credits for currently active monitors.
example: '1500'
activeHourlyBurn:
type: string
description: Credits charged each hour for currently active monitors.
example: '63'
creditsPerActiveMonitorDay:
type: string
description: Rounded daily estimate for 1 active monitor.
example: '500'
creditsPerActiveMonitorHour:
type: string
description: Hourly credits charged for 1 active monitor.
example: '21'
eventsIncluded:
type: boolean
description: Webhook and event deliveries are included in monitor billing.
example: true
instantCheckIntervalSeconds:
type: integer
description: Active monitors check every 1 second.
example: 1
unlimitedSlots:
type: boolean
description: Monitor slot count is unlimited.
example: true
creditInfo:
type: object
required:
- balance
- lifetimePurchased
- lifetimeUsed
- autoTopupEnabled
- autoTopupAmountDollars
- autoTopupThreshold
properties:
balance:
type: string
description: Bigint string to preserve precision above Number.MAX_SAFE_INTEGER.
example: '50000'
lifetimePurchased:
type: string
description: Total purchased credits as a bigint string.
example: '140000'
lifetimeUsed:
type: string
description: Total consumed credits as a bigint string.
example: '90000'
autoTopupEnabled:
type: boolean
example: false
autoTopupAmountDollars:
type: number
description: Dollar amount charged when automatic top-up runs.
example: 10
autoTopupThreshold:
type: string
description: Bigint string threshold that triggers automatic top-up when enabled.
example: '50000'
example:
balance: '50000'
lifetimePurchased: '140000'
lifetimeUsed: '90000'
autoTopupEnabled: false
autoTopupAmountDollars: 10
autoTopupThreshold: '50000'
xUsername:
type: string
description: Linked X username, omitted when no X account is connected.
example: elonmusk
example:
plan: active
monitorsUsed: 3
monitorsAllowed: 9007199254740991
monitorBilling:
activeDailyEstimate: '1500'
activeHourlyBurn: '63'
creditsPerActiveMonitorDay: '500'
creditsPerActiveMonitorHour: '21'
eventsIncluded: true
instantCheckIntervalSeconds: 1
unlimitedSlots: true
creditInfo:
balance: '50000'
lifetimePurchased: '140000'
lifetimeUsed: '90000'
autoTopupEnabled: false
autoTopupAmountDollars: 10
autoTopupThreshold: '50000'
xUsername: elonmusk
'401':
$ref: '#/components/responses/Unauthenticated'
'429':
$ref: '#/components/responses/RateLimitExceeded'
default:
content:
application/json:
example:
error: internal_error
message: Unexpected error. Try again.
schema:
$ref: '#/components/schemas/Error'
description: Unexpected error.
description: Get account info.
patch:
operationId: updateAccount
summary: Update account locale
tags:
- Account
security:
- apiKey: []
- oauthBearer: []
requestBody:
required: true
description: Locale preference for the account.
content:
application/json:
schema:
type: object
required:
- locale
properties:
locale:
type: string
enum:
- en
- tr
- es
example: en
example:
locale: en
responses:
'200':
$ref: '#/components/responses/Success'
'400':
$ref: '#/components/responses/InvalidInput'
'401':
$ref: '#/components/responses/Unauthenticated'
'429':
$ref: '#/components/responses/RateLimitExceeded'
default:
content:
application/json:
example:
error: internal_error
message: Unexpected error. Try again.
schema:
$ref: '#/components/schemas/Error'
description: Unexpected error.
description: Update account locale.
/api/v1/account/x-identity:
put:
operationId: setXIdentity
summary: Set linked X username
tags:
- Account
security:
- apiKey: []
- oauthBearer: []
requestBody:
required: true
description: X username to link to this account.
content:
application/json:
schema:
type: object
required:
- username
properties:
username:
type: string
description: X username without @
example: elonmusk
example:
username: elonmusk
responses:
'200':
description: X identity linked
content:
application/json:
schema:
type: object
required:
- success
- xUsername
properties:
success:
type: boolean
const: true
xUsername:
type: string
example: elonmusk
example:
success: true
xUsername: elonmusk
'400':
$ref: '#/components/responses/InvalidInput'
'401':
$ref: '#/components/responses/Unauthenticated'
'429':
$ref: '#/components/responses/RateLimitExceeded'
default:
content:
application/json:
example:
error: internal_error
message: Unexpected error. Try again.
schema:
$ref: '#/components/schemas/Error'
description: Unexpected error.
description: Set linked X username.
/api/v1/api-keys:
get:
operationId: listApiKeys
summary: List API keys
tags:
- API Keys
security:
- cookieSession: []
responses:
'200':
description: API key list
content:
application/json:
schema:
type: object
required:
- keys
properties:
keys:
type: array
items:
$ref: '#/components/schemas/ApiKey'
example: []
example:
keys: []
'401':
$ref: '#/components/responses/Unauthenticated'
'429':
$ref: '#/components/responses/RateLimitExceeded'
default:
content:
application/json:
example:
error: internal_error
message: Unexpected error. Try again.
schema:
$ref: '#/components/schemas/Error'
description: Unexpected error.
description: List API keys.
post:
operationId: createApiKey
summary: Create API key
tags:
- API Keys
security:
- cookieSession: []
requestBody:
required: true
description: Optional display name for the new API key.
content:
application/json:
schema:
type: object
properties:
name:
type: string
example: My API Key
example:
name: My API Key
responses:
'201':
description: API key created
content:
application/json:
schema:
type: object
required:
- id
- fullKey
- name
- prefix
- createdAt
properties:
id:
type: string
example: '42'
fullKey:
type: string
example: xq_live_abc123def456
name:
type: string
example: My API Key
prefix:
type: string
example: xq_live_abc1
createdAt:
type: string
format: date-time
example: '2025-01-15T12:00:00Z'
example:
id: '42'
fullKey: xq_live_abc123def456
name: My API Key
prefix: xq_live_abc1
createdAt: '2025-01-15T12:00:00Z'
'401':
$ref: '#/components/responses/Unauthenticated'
'403':
description: API key limit reached
content:
application/json:
schema:
type: object
required:
- error
- limit
- message
properties:
error:
type: string
const: api_key_limit_reached
example: api_key_limit_reached
limit:
type: integer
example: 100
message:
type: string
example: API key limit reached. Delete an existing key first.
example:
error: api_key_limit_reached
limit: 100
message: API key limit reached. Delete an existing key first.
'429':
$ref: '#/components/responses/RateLimitExceeded'
default:
content:
application/json:
example:
error: internal_error
message: Unexpected error. Try again.
schema:
$ref: '#/components/schemas/Error'
description: Unexpected error.
description: Create API key.
/api/v1/api-keys/{id}:
delete:
operationId: revokeApiKey
summary: Revoke API key
tags:
- API Keys
security:
- cookieSession: []
parameters:
- $ref: '#/components/parameters/ResourceId'
responses:
'200':
$ref: '#/components/responses/Success'
'400':
$ref: '#/components/responses/InvalidInput'
'401':
$ref: '#/components/responses/Unauthenticated'
'404':
$ref: '#/components/responses/NotFound'
'429':
$ref: '#/components/responses/RateLimitExceeded'
default:
content:
application/json:
example:
error: internal_error
message: Unexpected error. Try again.
schema:
$ref: '#/components/schemas/Error'
description: Unexpected error.
description: Revoke API key.
/api/v1/subscribe:
post:
operationId: subscribe
summary: Create subscription checkout
description: 'Create a subscription checkout or billing-management URL only after the user confirms. The request never
completes payment by itself.
'
tags:
- Subscribe
security:
- apiKey: []
- oauthBearer: []
requestBody:
required: false
description: Optional subscription tier to pre-select at checkout.
content:
application/json:
schema:
type: object
properties:
tier:
type: string
enum:
- starter
- pro
- business
description: Subscription tier to pre-select.
example: pro
example:
tier: pro
responses:
'200':
description: Billing URL
content:
application/json:
schema:
type: object
required:
- url
- status
- message
properties:
url:
type: string
format: uri
example: https://xquik.com/billing/session
status:
type: string
enum:
- checkout_created
- already_subscribed
- payment_issue
example: checkout_created
message:
type: string
example: Billing session created
example:
url: https://xquik.com/billing/session
status: checkout_created
message: Billing session created
'401':
$ref: '#/components/responses/Unauthenticated'
'429':
$ref: '#/components/responses/RateLimitExceeded'
default:
content:
application/json:
example:
error: internal_error
message: Unexpected error. Try again.
schema:
$ref: '#/components/schemas/Error'
description: Unexpected error.
/api/v1/compose:
post:
operationId: compose
summary: Build, refine, or check a post draft
description: 'Run one step of Xquik''s three-step writing workflow. Compose returns questions, editorial rules, and
source-specific Radar recommendations. Refine returns goal-specific guidance. Score applies deterministic text checks.
It does not predict reach or expose X ranking weights.
'
tags:
- Composition
security:
- apiKey: []
- oauthBearer: []
requestBody:
required: true
description: Send exactly one workflow step and its required fields.
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/ComposePrepareRequest'
- $ref: '#/components/schemas/ComposeRefineRequest'
- $ref: '#/components/schemas/ComposeScoreRequest'
example:
step: compose
topic: PostgreSQL query planning
goal: engagement
responses:
'200':
description: Result for the requested workflow step
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/ComposePrepareResult'
- $ref: '#/components/schemas/ComposeRefineResult'
- $ref: '#/components/schemas/ComposeScoreResult'
example:
checklist:
- factor: No external links in body
passed: true
- factor: No hashtags
passed: true
- factor: No excessive capitalization
passed: true
- factor: Length between 50 and 280 characters
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: true
- factor: Link-in-reply strategy
passed: true
nextStep: 'All 9 checks passed. Get an account from GET /api/v1/x/accounts. Then send the draft to POST /api/v1/x/tweets.
The intentUrl also supports one-click posting.
'
passed: true
passedCount: 9
topSuggestion: All Xquik editorial checks passed.
totalChecks: 9
intentUrl: https://x.com/intent/tweet?text=PostgreSQL%2018%20reduced%20query%20latency
'400':
$ref: '#/components/responses/InvalidInput'
'401':
$ref: '#/components/responses/Unauthenticated'
'429':
$ref: '#/components/responses/RateLimitExceeded'
default:
content:
application/json:
example:
error: internal_error
message: Unexpected error. Try again.
schema:
$ref: '#/components/schemas/Error'
description: Unexpected error.
/api/v1/drafts:
get:
operationId: listDrafts
summary: List saved drafts
tags:
- Composition
security:
- apiKey: []
- oauthBearer: []
parameters:
- $ref: '#/components/parameters/Limit'
- name: afterCursor
in: query
schema:
type: string
description: Cursor for pagination
responses:
'200':
description: Draft list
content:
application/json:
schema:
type: object
required:
- drafts
- hasMore
properties:
drafts:
type: array
items:
$ref: '#/components/schemas/Draft'
example: []
hasMore:
type: boolean
example: false
nextCursor:
type: string
example: abc123
example:
drafts: []
hasMore: false
'401':
$ref: '#/components/responses/Unauthenticated'
'429':
$ref: '#/components/responses/RateLimitExceeded'
default:
content:
application/json:
example:
error: internal_error
message: Unexpected error. Try again.
schema:
$ref: '#/components/schemas/Error'
description: Unexpected error.
description: List saved drafts.
post:
operationId: createDraft
summary: Save a tweet draft
tags:
- Composition
security:
- apiKey: []
- oauthBearer: []
requestBody:
required: true
description: Draft text with optional topic and optimization goal.
content:
application/json:
schema:
type: object
required:
- text
properties:
text:
type: string
example: AI is the future of productivity
topic:
type: string
example: AI trends
goal:
type: string
enum:
- engagement
- followers
- authority
- conversation
example: engagement
example:
text: AI is the future of productivity
topic: AI trends
goal: engagement
responses:
'201':
description: Draft created
content:
application/json:
schema:
$ref: '#/components/schemas/DraftDetail'
example:
id: '42'
text: AI is the future of productivity
topic: AI trends
goal: engagement
createdAt: '2025-01-15T12:00:00Z'
updatedAt: '2025-01-16T09:30:00Z'
'400':
$ref: '#/components/responses/InvalidInput'
'401':
$ref: '#/components/responses/Unauthenticated'
'429':
$ref: '#/components/responses/RateLimitExceeded'
default:
content:
application/json:
example:
error: internal_error
message: Unexpected error. Try again.
schema:
$ref: '#/components/schemas/Error'
description: Unexpected error.
description: Save a tweet draft.
/api/v1/drafts/{id}:
get:
operationId: getDraft
summary: Get draft by ID
tags:
- Composition
security:
- apiKey: []
- oauthBearer: []
parameters:
- $ref: '#/components/parameters/ResourceId'
responses:
'200':
description: Draft details
content:
application/json:
schema:
$ref: '#/components/schemas/DraftDetail'
example:
id: '42'
text: AI is the future of productivity
topic: AI trends
goal: engagement
createdAt: '2025-01-15T12:00:00Z'
updatedAt: '2025-01-16T09:30:00Z'
'400':
$ref: '#/components/responses/InvalidInput'
'401':
$ref: '#/components/responses/Unauthenticated'
'404':
$ref: '#/components/responses/NotFound'
'429':
$ref: '#/components/responses/RateLimitExceeded'
default:
content:
application/json:
example:
error: internal_error
message: Unexpected error. Try again.
schema:
$ref: '#/components/schemas/Error'
description: Unexpected error.
description: Get draft by ID.
delete:
operationId: deleteDraft
summary: Delete a draft
tags:
- Composition
security:
- apiKey: []
- oauthBearer: []
parameters:
- $ref: '#/components/parameters/ResourceId'
responses:
'204':
$ref: '#/components/responses/NoContent'
'400':
$ref: '#/components/responses/InvalidInput'
'401':
$ref: '#/components/responses/Unauthenticated'
'404':
$ref: '#/components/responses/NotFound'
'429':
$ref: '#/components/responses/RateLimitExceeded'
default:
content:
application/json:
# --- truncated at 32 KB (472 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/xquik-api/refs/heads/main/openapi/xquik-rest-api-openapi.yml