openapi: 3.2.0 info: title: Xquik Webhooks 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 security: - apiKey: [] - oauthBearer: [] tags: - name: Webhooks description: Webhook endpoint management and delivery paths: /api/v1/webhooks: get: operationId: listWebhooks summary: List webhooks tags: - Webhooks security: - apiKey: [] - oauthBearer: [] responses: '200': description: Webhook list content: application/json: schema: type: object required: - webhooks properties: webhooks: type: array items: $ref: '#/components/schemas/Webhook' example: [] example: webhooks: [] '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 webhooks. post: operationId: createWebhook summary: Create webhook tags: - Webhooks security: - apiKey: [] - oauthBearer: [] requestBody: required: true description: HTTPS callback URL and event types to subscribe to. content: application/json: schema: type: object required: - url - eventTypes properties: url: type: string format: uri description: HTTPS URL example: https://example.com/webhook eventTypes: $ref: '#/components/schemas/EventTypeArray' example: - tweet.new - tweet.reply example: url: https://example.com/webhook eventTypes: - tweet.new - tweet.reply responses: '201': description: Webhook created content: application/json: schema: type: object required: - id - url - secret - eventTypes - createdAt properties: id: type: string example: '42' url: type: string format: uri example: https://example.com/webhook secret: type: string description: Plaintext HMAC signing secret returned only at creation. example: a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2 eventTypes: $ref: '#/components/schemas/EventTypeArray' example: - tweet.new - tweet.reply createdAt: type: string format: date-time example: '2025-01-15T12:00:00Z' example: id: '42' url: https://example.com/webhook secret: a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2 eventTypes: - tweet.new - tweet.reply createdAt: '2025-01-15T12:00: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: Create webhook. /api/v1/webhooks/{id}: patch: operationId: updateWebhook summary: Update webhook tags: - Webhooks security: - apiKey: [] - oauthBearer: [] parameters: - $ref: '#/components/parameters/ResourceId' requestBody: required: true description: Updated URL, event types, or active status. content: application/json: schema: type: object properties: url: type: string format: uri example: https://example.com/webhook eventTypes: $ref: '#/components/schemas/EventTypeArray' example: - tweet.new isActive: type: boolean example: true example: url: https://example.com/webhook isActive: true responses: '200': description: Webhook updated content: application/json: schema: $ref: '#/components/schemas/Webhook' example: id: '42' url: https://example.com/webhook eventTypes: - tweet.new isActive: true consecutiveFailures: 0 deliveryStatus: active failureHardCap: 200 createdAt: '2025-01-15T12:00: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: Update webhook. delete: operationId: deleteWebhook summary: Deactivate webhook tags: - Webhooks security: - apiKey: [] - oauthBearer: [] 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: Deactivate webhook. /api/v1/webhooks/{id}/deliveries: get: operationId: listWebhookDeliveries summary: List webhook deliveries tags: - Webhooks security: - apiKey: [] - oauthBearer: [] parameters: - $ref: '#/components/parameters/ResourceId' responses: '200': description: Delivery list content: application/json: schema: type: object required: - deliveries properties: deliveries: type: array items: $ref: '#/components/schemas/Delivery' example: [] example: deliveries: [] '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: List webhook deliveries. /api/v1/webhooks/{id}/test: post: operationId: testWebhook summary: Test webhook endpoint tags: - Webhooks security: - apiKey: [] - oauthBearer: [] parameters: - $ref: '#/components/parameters/ResourceId' responses: '200': description: Test result content: application/json: schema: type: object required: - success - statusCode properties: success: type: boolean example: true statusCode: type: integer example: 200 error: type: string example: '' example: success: true statusCode: 200 '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: Test webhook endpoint. /api/v1/webhooks/{id}/resume: post: operationId: resumeWebhook summary: Test and resume webhook endpoint tags: - Webhooks security: - apiKey: [] - oauthBearer: [] parameters: - $ref: '#/components/parameters/ResourceId' responses: '200': description: Webhook resumed after a successful test delivery content: application/json: schema: type: object required: - success - statusCode - webhook properties: success: type: boolean example: true statusCode: type: integer example: 200 webhook: $ref: '#/components/schemas/Webhook' example: success: true statusCode: 200 webhook: id: '42' url: https://example.com/webhook eventTypes: - tweet.new isActive: true consecutiveFailures: 0 deliveryStatus: active failureHardCap: 200 createdAt: '2025-01-15T12:00:00Z' '400': description: Webhook test failed content: application/json: schema: type: object additionalProperties: false required: - error - statusCode - success properties: error: type: string description: Delivery failure returned by the webhook sender. example: Connection timed out statusCode: type: integer description: Webhook response status, or 0 before a response. example: 0 success: type: boolean const: false example: error: Connection timed out statusCode: 0 success: false '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: Test and resume webhook endpoint. webhooks: monitorEvent: post: description: Receive one signed Xquik monitor event. operationId: receiveMonitorEvent requestBody: content: application/json: example: data: id: '1893456789012345678' text: Example post. eventType: tweet.new username: example schema: properties: data: additionalProperties: true type: object eventType: $ref: '#/components/schemas/EventType' username: type: string required: - eventType - data type: object required: true responses: '200': description: Event accepted. security: [] summary: Receive monitor event tags: - Webhooks components: schemas: EventTypeArray: description: Array of event types to subscribe to. type: array items: $ref: '#/components/schemas/EventType' minItems: 1 example: - tweet.new - tweet.reply Delivery: description: Webhook delivery attempt record with status and retry count. type: object required: - id - streamEventId - status - attempts - createdAt properties: id: type: string streamEventId: type: string status: type: string attempts: type: integer createdAt: type: string format: date-time deliveredAt: type: string format: date-time lastStatusCode: type: integer lastError: type: string Error: description: 'Error response. Default v1 returns a legacy string error code. Send `xquik-api-contract: 2026-04-29` to receive the structured best-practice error object. ' type: object required: - error properties: error: x-stainless-naming: python: type_name: ErrorValue java: type_name: ErrorValue example: invalid_input oneOf: - type: string title: LegacyErrorCode enum: - internal_error - account_already_connected - account_needs_reauth - account_not_found - account_required - account_restricted - api_key_limit_reached - article_not_found - dm_not_permitted - invalid_format - invalid_id - invalid_input - invalid_params - invalid_tool_type - invalid_tweet_id - invalid_tweet_url - invalid_user_id - invalid_user_ids - invalid_username - invalid_json - insufficient_credits - login_cooldown - login_failed - media_download_failed - missing_params - missing_query - monitor_already_exists - no_media - no_credits - no_subscription - not_found - payment_failed - rate_limit_exceeded - service_unavailable - style_not_found - subscription_inactive - tweet_not_found - unauthenticated - unsupported_field - user_not_found - body_too_large - checkout_unavailable - connection_challenge_expired - connection_challenge_inactive - draft_not_found - favoriters_unavailable - forbidden - guest_wallet_unavailable - guest_wallets_disabled - guest_wallets_unavailable - idempotency_conflict - idempotency_key_conflict - invalid_community_id - invalid_idempotency_key - invalid_list_id - invalid_payment_amount - invalid_range - login_rate_limited - missing_idempotency_key - missing_ids - no_cached_style - passkey_required - rate_limited - read_request_timeout - replies_incomplete - support_media_rate_limit - support_request_rate_limit - too_many_ids - unknown_field - unsupported_media_type - webhook_inactive - write_tracking_unavailable - x_write_unconfirmed - x_account_feature_required - x_account_protected - x_account_suspended - x_api_rate_limited - x_api_unavailable - x_api_unauthorized - x_auth_failure - x_content_too_long - x_daily_limit - x_dm_not_allowed - x_duplicate_action - x_login_auth_failed - x_login_challenge - x_login_denied - x_login_failed - x_login_proxy_error - x_login_rate_limited - x_login_service_unavailable - x_login_suspended - x_rate_limited - x_rejected - x_target_not_found - x_transient_error - x_user_lookup_failed - x_write_ambiguous - x_write_failed example: invalid_input - type: object title: StructuredError required: - message - type - code properties: message: type: string example: Invalid input. Check the request body. type: type: string enum: - api_error - authentication_error - billing_error - dependency_error - invalid_request_error - permission_error - rate_limit_error example: invalid_request_error code: type: string title: ErrorCode enum: - internal_error - account_already_connected - account_needs_reauth - account_not_found - account_required - account_restricted - api_key_limit_reached - article_not_found - dm_not_permitted - invalid_format - invalid_id - invalid_input - invalid_params - invalid_tool_type - invalid_tweet_id - invalid_tweet_url - invalid_user_id - invalid_user_ids - invalid_username - invalid_json - insufficient_credits - login_cooldown - login_failed - media_download_failed - missing_params - missing_query - monitor_already_exists - no_media - no_credits - no_subscription - not_found - payment_failed - rate_limit_exceeded - service_unavailable - style_not_found - subscription_inactive - tweet_not_found - unauthenticated - unsupported_field - user_not_found - body_too_large - checkout_unavailable - connection_challenge_expired - connection_challenge_inactive - draft_not_found - favoriters_unavailable - forbidden - guest_wallet_unavailable - guest_wallets_disabled - guest_wallets_unavailable - idempotency_conflict - idempotency_key_conflict - invalid_community_id - invalid_idempotency_key - invalid_list_id - invalid_payment_amount - invalid_range - login_rate_limited - missing_idempotency_key - missing_ids - no_cached_style - passkey_required - rate_limited - read_request_timeout - replies_incomplete - support_media_rate_limit - support_request_rate_limit - too_many_ids - unknown_field - unsupported_media_type - webhook_inactive - write_tracking_unavailable - x_write_unconfirmed - x_account_feature_required - x_account_protected - x_account_suspended - x_api_rate_limited - x_api_unavailable - x_api_unauthorized - x_auth_failure - x_content_too_long - x_daily_limit - x_dm_not_allowed - x_duplicate_action - x_login_auth_failed - x_login_challenge - x_login_denied - x_login_failed - x_login_proxy_error - x_login_rate_limited - x_login_service_unavailable - x_login_suspended - x_rate_limited - x_rejected - x_target_not_found - x_transient_error - x_user_lookup_failed - x_write_ambiguous - x_write_failed example: invalid_input message: type: string description: Human-readable error guidance. example: Invalid input. Check the request body. reason: type: string description: Machine-readable reason for a login cooldown. example: temporary_issue retryAfter: type: integer minimum: 1 description: Seconds until the next permitted request. example: 60 retryAfterMs: type: integer minimum: 1 description: Required wait in milliseconds. example: 60000 Webhook: description: Webhook endpoint registered to receive event deliveries. type: object required: - id - url - eventTypes - isActive - consecutiveFailures - deliveryStatus - failureHardCap - createdAt properties: id: type: string example: '42' url: type: string format: uri example: https://example.com/webhooks/xquik eventTypes: $ref: '#/components/schemas/EventTypeArray' example: - tweet.new - tweet.reply isActive: type: boolean example: true consecutiveFailures: type: integer description: Consecutive failed delivery attempts since the last success. example: 0 deliveryStatus: type: string enum: - active - paused - needs_attention description: Endpoint delivery state. needs_attention means delivery stopped after repeated failures. example: active failureHardCap: type: integer description: Consecutive delivery failures that pause the endpoint. example: 200 createdAt: type: string format: date-time example: '2025-01-15T12:00:00Z' EventType: description: Type of monitor event fired when account activity occurs. type: string enum: - tweet.new - tweet.reply - tweet.retweet - tweet.quote - 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 example: tweet.new responses: NotFound: description: Not found content: application/json: schema: $ref: '#/components/schemas/Error' example: error: not_found message: Resource not found. InvalidInput: description: Invalid input content: application/json: schema: $ref: '#/components/schemas/Error' example: error: invalid_input message: Invalid input. Check the request body. Success: description: Success content: application/json: schema: type: object required: - success properties: success: type: boolean const: true example: true example: success: true Unauthenticated: description: Unauthenticated headers: Cache-Control: description: Prevents storage of authentication responses. schema: type: string const: no-store WWW-Authenticate: description: Bearer authentication challenge. schema: type: string const: Bearer realm="xquik" content: application/json: schema: $ref: '#/components/schemas/Error' example: error: unauthenticated message: Authentication required. Provide a valid API key or bearer token. RateLimitExceeded: description: 'Xquik tier rate limit exceeded. The response includes a `Retry-After` header with the number of seconds to wait before retrying. ' content: application/json: schema: allOf: - $ref: '#/components/schemas/Error' - type: object properties: retryAfter: type: integer example: 60 example: error: rate_limit_exceeded message: Too many requests. Try again later. retryAfter: 60 headers: Retry-After: description: Seconds until the next permitted request. schema: example: 60 minimum: 1 type: integer parameters: ResourceId: name: id in: path required: true schema: type: string description: Resource ID returned by the matching create or list endpoint. securitySchemes: apiKey: type: apiKey in: header name: x-api-key description: 'Xquik API key passed through the x-api-key header. Xquik-Api-Key is a vendor-prefixed alias. API keys beginning with xq_ can also use Authorization: Bearer.' oauthBearer: type: http scheme: bearer description: 'OAuth 2.1 access token passed through Authorization: Bearer. Values beginning with xq_ remain Xquik API-key credentials, not OAuth tokens.' cookieSession: type: apiKey in: cookie name: __Host-xquik_session description: Secure Xquik browser session cookie. 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