x-developer 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1607 @@
1
+ # Xquik REST API Endpoints
2
+
3
+ Base URL: `https://xquik.com/api/v1`
4
+
5
+ All requests require the `x-api-key` header. All responses are JSON. HTTPS only.
6
+
7
+ ## Table of Contents
8
+
9
+ - [Account](#account)
10
+ - [API Keys](#api-keys)
11
+ - [Monitors](#monitors)
12
+ - [Events](#events)
13
+ - [Webhooks](#webhooks)
14
+ - [Draws](#draws)
15
+ - [Extractions](#extractions)
16
+ - [X API (Direct Lookups)](#x-api-direct-lookups)
17
+ - [X Media (Download)](#x-media-download)
18
+ - [Trends](#trends)
19
+ - [Radar](#radar)
20
+ - [Compose](#compose)
21
+ - [Drafts](#drafts)
22
+ - [Tweet Style Cache](#tweet-style-cache)
23
+ - [Account Identity](#account-identity)
24
+ - [Subscribe](#subscribe)
25
+ - [X Accounts (Connected)](#x-accounts-connected)
26
+ - [X Write](#x-write)
27
+ - [Integrations](#integrations)
28
+ - [Automations](#automations)
29
+ - [Credits](#credits)
30
+ - [Support](#support)
31
+
32
+ ---
33
+
34
+ ## Account
35
+
36
+ ### Get Account
37
+
38
+ ```
39
+ GET /account
40
+ ```
41
+
42
+ Returns subscription status, monitor allocation, and current period usage.
43
+
44
+ **Response:**
45
+ ```json
46
+ {
47
+ "plan": "active",
48
+ "monitorsAllowed": 1,
49
+ "monitorsUsed": 0,
50
+ "currentPeriod": {
51
+ "start": "2026-02-01T00:00:00.000Z",
52
+ "end": "2026-03-01T00:00:00.000Z",
53
+ "usagePercent": 45
54
+ }
55
+ }
56
+ ```
57
+
58
+ ### Update Account
59
+
60
+ ```
61
+ PATCH /account
62
+ ```
63
+
64
+ Update account locale. Session auth only (not API key).
65
+
66
+ **Body:** `{ "locale": "en" | "tr" | "es" }`
67
+
68
+ ---
69
+
70
+ ## API Keys
71
+
72
+ Session auth only. These endpoints do not accept API key auth.
73
+
74
+ ### Create API Key
75
+
76
+ ```
77
+ POST /api-keys
78
+ ```
79
+
80
+ **Body:** `{ "name": "My Key" }` (optional)
81
+
82
+ **Response:** Returns `fullKey` (shown only once), `prefix`, `name`, `id`, `createdAt`.
83
+
84
+ ### List API Keys
85
+
86
+ ```
87
+ GET /api-keys
88
+ ```
89
+
90
+ Returns all keys with `id`, `name`, `prefix`, `isActive`, `createdAt`, `lastUsedAt`. Full key is never exposed.
91
+
92
+ ### Revoke API Key
93
+
94
+ ```
95
+ DELETE /api-keys/{id}
96
+ ```
97
+
98
+ Permanent and irreversible. The key stops working immediately.
99
+
100
+ ---
101
+
102
+ ## Monitors
103
+
104
+ ### Create Monitor
105
+
106
+ ```
107
+ POST /monitors
108
+ ```
109
+
110
+ **Body:**
111
+ ```json
112
+ {
113
+ "username": "elonmusk",
114
+ "eventTypes": ["tweet.new", "tweet.reply", "tweet.quote"]
115
+ }
116
+ ```
117
+
118
+ **Response:**
119
+ ```json
120
+ {
121
+ "id": "7",
122
+ "username": "elonmusk",
123
+ "xUserId": "44196397",
124
+ "eventTypes": ["tweet.new", "tweet.reply", "tweet.quote"],
125
+ "createdAt": "2026-02-24T10:30:00.000Z"
126
+ }
127
+ ```
128
+
129
+ Event types: `tweet.new`, `tweet.quote`, `tweet.reply`, `tweet.retweet`, `follower.gained`, `follower.lost`.
130
+
131
+ Returns `409 monitor_already_exists` if the username is already monitored.
132
+
133
+ ### List Monitors
134
+
135
+ ```
136
+ GET /monitors
137
+ ```
138
+
139
+ Returns all monitors (up to 200, no pagination). Response includes `monitors` array and `total` count.
140
+
141
+ ### Get Monitor
142
+
143
+ ```
144
+ GET /monitors/{id}
145
+ ```
146
+
147
+ ### Update Monitor
148
+
149
+ ```
150
+ PATCH /monitors/{id}
151
+ ```
152
+
153
+ **Body:** `{ "eventTypes": [...], "isActive": true|false }` (both optional)
154
+
155
+ ### Delete Monitor
156
+
157
+ ```
158
+ DELETE /monitors/{id}
159
+ ```
160
+
161
+ Stops tracking and deletes all associated data.
162
+
163
+ ---
164
+
165
+ ## Events
166
+
167
+ ### List Events
168
+
169
+ ```
170
+ GET /events
171
+ ```
172
+
173
+ **Query parameters:**
174
+
175
+ | Param | Type | Description |
176
+ |-------|------|-------------|
177
+ | `monitorId` | string | Filter by monitor ID |
178
+ | `eventType` | string | Filter by event type |
179
+ | `limit` | number | Results per page (1-100, default 50) |
180
+ | `after` | string | Cursor for next page |
181
+
182
+ **Response:**
183
+ ```json
184
+ {
185
+ "events": [
186
+ {
187
+ "id": "9010",
188
+ "type": "tweet.new",
189
+ "monitorId": "7",
190
+ "username": "elonmusk",
191
+ "occurredAt": "2026-02-24T16:45:00.000Z",
192
+ "data": {
193
+ "tweetId": "1893556789012345678",
194
+ "text": "Hello world",
195
+ "metrics": { "likes": 3200, "retweets": 890, "replies": 245 }
196
+ }
197
+ }
198
+ ],
199
+ "hasMore": true,
200
+ "nextCursor": "MjAyNi0wMi0yNFQxNjozMDowMC4wMDBa..."
201
+ }
202
+ ```
203
+
204
+ ### Get Event
205
+
206
+ ```
207
+ GET /events/{id}
208
+ ```
209
+
210
+ Returns a single event with full details.
211
+
212
+ ---
213
+
214
+ ## Webhooks
215
+
216
+ ### Create Webhook
217
+
218
+ ```
219
+ POST /webhooks
220
+ ```
221
+
222
+ **Body:**
223
+ ```json
224
+ {
225
+ "url": "https://your-server.com/webhook",
226
+ "eventTypes": ["tweet.new", "tweet.reply"]
227
+ }
228
+ ```
229
+
230
+ **Response** includes a `secret` field (shown only once). Store it for signature verification.
231
+
232
+ ### List Webhooks
233
+
234
+ ```
235
+ GET /webhooks
236
+ ```
237
+
238
+ Returns all webhooks (up to 200). Secret is never exposed in list responses.
239
+
240
+ ### Update Webhook
241
+
242
+ ```
243
+ PATCH /webhooks/{id}
244
+ ```
245
+
246
+ **Body:** `{ "url": "...", "eventTypes": [...], "isActive": true|false }` (all optional)
247
+
248
+ ### Delete Webhook
249
+
250
+ ```
251
+ DELETE /webhooks/{id}
252
+ ```
253
+
254
+ Permanently removes the webhook. All future deliveries are stopped.
255
+
256
+ ### Test Webhook
257
+
258
+ ```
259
+ POST /webhooks/{id}/test
260
+ ```
261
+
262
+ Sends a `webhook.test` event to the webhook endpoint, HMAC-signed with the webhook's secret. Returns success or failure status with HTTP response details.
263
+
264
+ **Payload delivered to your endpoint:**
265
+ ```json
266
+ {
267
+ "eventType": "webhook.test",
268
+ "data": {
269
+ "message": "Test delivery from Xquik"
270
+ },
271
+ "timestamp": "2026-02-27T12:00:00.000Z"
272
+ }
273
+ ```
274
+
275
+ The delivery includes the `X-Xquik-Signature` header, identical to production deliveries.
276
+
277
+ Returns `400 webhook_inactive` if the webhook is disabled. Reactivate via `PATCH /webhooks/{id}` before testing.
278
+
279
+ ### List Deliveries
280
+
281
+ ```
282
+ GET /webhooks/{id}/deliveries
283
+ ```
284
+
285
+ View delivery attempts and statuses for a webhook. Statuses: `pending`, `delivered`, `failed`, `exhausted`.
286
+
287
+ ---
288
+
289
+ ## Draws
290
+
291
+ ### Create Draw
292
+
293
+ ```
294
+ POST /draws
295
+ ```
296
+
297
+ Run a giveaway draw from a tweet. Picks random winners from replies.
298
+
299
+ **Body:**
300
+ ```json
301
+ {
302
+ "tweetUrl": "https://x.com/user/status/1893456789012345678",
303
+ "winnerCount": 3,
304
+ "backupCount": 2,
305
+ "uniqueAuthorsOnly": true,
306
+ "mustRetweet": true,
307
+ "mustFollowUsername": "burakbayir",
308
+ "filterMinFollowers": 100,
309
+ "filterAccountAgeDays": 30,
310
+ "filterLanguage": "en",
311
+ "requiredKeywords": ["giveaway"],
312
+ "requiredHashtags": ["#contest"],
313
+ "requiredMentions": ["@xquik"]
314
+ }
315
+ ```
316
+
317
+ All filter fields are optional. Only `tweetUrl` is required.
318
+
319
+ **Response:**
320
+ ```json
321
+ {
322
+ "id": "42",
323
+ "tweetId": "1893456789012345678",
324
+ "tweetUrl": "https://x.com/user/status/1893456789012345678",
325
+ "tweetText": "Like & RT to enter! Picking 3 winners tomorrow.",
326
+ "tweetAuthorUsername": "xquik",
327
+ "tweetLikeCount": 4200,
328
+ "tweetRetweetCount": 1800,
329
+ "tweetReplyCount": 1500,
330
+ "tweetQuoteCount": 120,
331
+ "status": "completed",
332
+ "totalEntries": 1500,
333
+ "validEntries": 890,
334
+ "createdAt": "2026-02-24T10:00:00.000Z",
335
+ "drawnAt": "2026-02-24T10:01:00.000Z"
336
+ }
337
+ ```
338
+
339
+ ### List Draws
340
+
341
+ ```
342
+ GET /draws
343
+ ```
344
+
345
+ Cursor-paginated. Returns compact draw objects.
346
+
347
+ ### Get Draw
348
+
349
+ ```
350
+ GET /draws/{id}
351
+ ```
352
+
353
+ Returns full draw details including winners.
354
+
355
+ ### Export Draw
356
+
357
+ ```
358
+ GET /draws/{id}/export?format=csv&type=winners
359
+ ```
360
+
361
+ Formats: `csv`, `xlsx`, `md`. Types: `winners` (default), `entries`. Entry exports capped at 50,000 rows.
362
+
363
+ ---
364
+
365
+ ## Extractions
366
+
367
+ ### Create Extraction
368
+
369
+ ```
370
+ POST /extractions
371
+ ```
372
+
373
+ Run a bulk data extraction job. See `references/extractions.md` for all 23 tool types.
374
+
375
+ **Body:**
376
+ ```json
377
+ {
378
+ "toolType": "reply_extractor",
379
+ "targetTweetId": "1893704267862470862",
380
+ "resultsLimit": 500
381
+ }
382
+ ```
383
+
384
+ `resultsLimit` (optional): Maximum results to extract. Stops early instead of fetching all data. Useful for controlling costs.
385
+
386
+ **Tweet Search Filters** (`tweet_search_extractor` only):
387
+
388
+ | Field | Type | Description |
389
+ |-------|------|-------------|
390
+ | `fromUser` | string | Author username |
391
+ | `toUser` | string | Directed to user |
392
+ | `mentioning` | string | Mentions user |
393
+ | `language` | string | Language code (e.g., `en`) |
394
+ | `sinceDate` | string | Start date (YYYY-MM-DD) |
395
+ | `untilDate` | string | End date (YYYY-MM-DD) |
396
+ | `mediaType` | string | `images`, `videos`, `gifs`, or `media` |
397
+ | `minFaves` | number | Minimum likes |
398
+ | `minRetweets` | number | Minimum retweets |
399
+ | `minReplies` | number | Minimum replies |
400
+ | `verifiedOnly` | boolean | Verified authors only |
401
+ | `replies` | string | `include`, `exclude`, or `only` |
402
+ | `retweets` | string | `include`, `exclude`, or `only` |
403
+ | `exactPhrase` | string | Exact match text |
404
+ | `excludeWords` | string | Comma-separated words to exclude |
405
+ | `advancedQuery` | string | Raw X search operators appended to query |
406
+
407
+ These filters are converted to X search operators and combined with `searchQuery`.
408
+
409
+ **Response:**
410
+ ```json
411
+ {
412
+ "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
413
+ "toolType": "reply_extractor",
414
+ "status": "running"
415
+ }
416
+ ```
417
+
418
+ ### Estimate Extraction
419
+
420
+ ```
421
+ POST /extractions/estimate
422
+ ```
423
+
424
+ Preview the cost before running. Same body as create.
425
+
426
+ **Response:**
427
+ ```json
428
+ {
429
+ "allowed": true,
430
+ "source": "replyCount",
431
+ "estimatedResults": 150,
432
+ "usagePercent": 45,
433
+ "projectedPercent": 48
434
+ }
435
+ ```
436
+
437
+ ### List Extractions
438
+
439
+ ```
440
+ GET /extractions
441
+ ```
442
+
443
+ Cursor-paginated. Filter by `status` and `toolType`.
444
+
445
+ ### Get Extraction
446
+
447
+ ```
448
+ GET /extractions/{id}
449
+ ```
450
+
451
+ Returns job details with paginated results (up to 1,000 per page).
452
+
453
+ ### Export Extraction
454
+
455
+ ```
456
+ GET /extractions/{id}/export?format=csv
457
+ ```
458
+
459
+ Formats: `csv`, `xlsx`, `md`. 50,000 row limit. Exports include enrichment columns not in the API response.
460
+
461
+ ---
462
+
463
+ ## X API (Direct Lookups)
464
+
465
+ Metered operations that count toward the monthly quota.
466
+
467
+ ### Get Tweet
468
+
469
+ ```
470
+ GET /x/tweets/{id}
471
+ ```
472
+
473
+ Returns full tweet with engagement metrics (likes, retweets, replies, quotes, views, bookmarks), author info (username, followers, verified status, profile picture), and optional attached media (photos/videos with URLs).
474
+
475
+ ### Get Article
476
+
477
+ ```
478
+ GET /x/articles/{id}
479
+ ```
480
+
481
+ Retrieve the full content of an X Article (long-form post) by tweet ID. Returns title, body text with block-level formatting, cover image, inline images, and engagement metrics. Metered.
482
+
483
+ **Response:**
484
+ ```json
485
+ {
486
+ "title": "Why AI Will Transform Everything",
487
+ "coverImage": "https://pbs.twimg.com/...",
488
+ "bodyHtml": "<p>The future of AI...</p>",
489
+ "likeCount": 5200,
490
+ "retweetCount": 890,
491
+ "replyCount": 245,
492
+ "viewCount": 150000,
493
+ "bookmarkCount": 1200,
494
+ "author": {
495
+ "id": "44196397",
496
+ "username": "elonmusk",
497
+ "name": "Elon Musk"
498
+ }
499
+ }
500
+ ```
501
+
502
+ ### Search Tweets
503
+
504
+ ```
505
+ GET /x/tweets/search?q={query}
506
+ ```
507
+
508
+ Search using X syntax: keywords, `#hashtags`, `from:user`, `to:user`, `"exact phrases"`, `OR`, `-exclude`.
509
+
510
+ Returns tweet info with optional engagement metrics (likeCount, retweetCount, replyCount) and optional attached media. Some fields may be omitted if unavailable.
511
+
512
+ ### Get User
513
+
514
+ ```
515
+ GET /x/users/{username}
516
+ ```
517
+
518
+ Returns profile info. Fields `id`, `username`, `name` are always present. All other fields (`description`, `followers`, `following`, `verified`, `profilePicture`, `location`, `createdAt`, `statusesCount`) are optional and omitted when unavailable.
519
+
520
+ ### Check Follower
521
+
522
+ ```
523
+ GET /x/followers/check?source={username}&target={username}
524
+ ```
525
+
526
+ Returns `isFollowing` and `isFollowedBy` for both directions.
527
+
528
+ ### Get User Tweets
529
+
530
+ ```
531
+ GET /x/users/{id}/tweets
532
+ ```
533
+
534
+ Get a user's recent tweets by user ID. Metered (1 credit/tweet).
535
+
536
+ ### Get User Likes
537
+
538
+ ```
539
+ GET /x/users/{id}/likes
540
+ ```
541
+
542
+ Get tweets liked by a user. Metered (1 credit/result).
543
+
544
+ ### Get User Media
545
+
546
+ ```
547
+ GET /x/users/{id}/media
548
+ ```
549
+
550
+ Get a user's media tweets (tweets containing photos/videos). Metered (1 credit/result).
551
+
552
+ ### Get Tweet Favoriters
553
+
554
+ ```
555
+ GET /x/tweets/{id}/favoriters
556
+ ```
557
+
558
+ Get users who liked a tweet. Metered (1 credit/result).
559
+
560
+ ### Get Mutual Followers
561
+
562
+ ```
563
+ GET /x/users/{id}/followers-you-know
564
+ ```
565
+
566
+ Get mutual followers (followers you know). Metered (1 credit/result).
567
+
568
+ ### Get Bookmarks
569
+
570
+ ```
571
+ GET /x/bookmarks
572
+ ```
573
+
574
+ Get bookmarked tweets. Requires a connected X account. Metered (1 credit/result).
575
+
576
+ **Sensitive:** Returns private data. Confirm with user before calling.
577
+
578
+ ### Get Bookmark Folders
579
+
580
+ ```
581
+ GET /x/bookmarks/folders
582
+ ```
583
+
584
+ Get bookmark folders. Requires a connected X account. Metered (1 credit).
585
+
586
+ ### Get Notifications
587
+
588
+ ```
589
+ GET /x/notifications
590
+ ```
591
+
592
+ Get notifications with type filter. Requires a connected X account. Metered (1 credit/result).
593
+
594
+ **Sensitive:** Returns private data. Confirm with user before calling.
595
+
596
+ ### Get Home Timeline
597
+
598
+ ```
599
+ GET /x/timeline
600
+ ```
601
+
602
+ Get home timeline. Requires a connected X account. Metered (1 credit/result).
603
+
604
+ **Sensitive:** Returns private data. Confirm with user before calling.
605
+
606
+ ---
607
+
608
+ ## X Media (Download)
609
+
610
+ ### Download Media
611
+
612
+ ```
613
+ POST /x/media/download
614
+ ```
615
+
616
+ Download images, videos, and GIFs from tweets. Single or bulk (up to 50). Returns a shareable gallery URL.
617
+
618
+ **Body:** Provide either `tweetInput` (single tweet) or `tweetIds` (bulk). Exactly 1 is required.
619
+
620
+ | Field | Type | Description |
621
+ |-------|------|-------------|
622
+ | `tweetInput` | string | Tweet URL or numeric tweet ID for a single download. Accepts `x.com` and `twitter.com` URL formats |
623
+ | `tweetIds` | string[] | Array of tweet URLs or IDs for bulk download. Maximum 50 items. Returns a single combined gallery |
624
+
625
+ **Response (single):**
626
+ ```json
627
+ {
628
+ "tweetId": "1893456789012345678",
629
+ "galleryUrl": "https://xquik.com/gallery/abc123",
630
+ "cacheHit": false
631
+ }
632
+ ```
633
+
634
+ **Response (bulk):**
635
+ ```json
636
+ {
637
+ "galleryUrl": "https://xquik.com/gallery/def456",
638
+ "totalTweets": 3,
639
+ "totalMedia": 7
640
+ }
641
+ ```
642
+
643
+ First download is metered (counts toward monthly quota). Subsequent requests for the same tweet return cached URLs at no cost (`cacheHit: true`). All downloads are saved to the gallery at `https://xquik.com/gallery`.
644
+
645
+ Returns `400 no_media` if the tweet has no downloadable media. Returns `400 too_many_tweets` if bulk array exceeds 50 items.
646
+
647
+ ---
648
+
649
+ ## Trends
650
+
651
+ ### List Trends
652
+
653
+ ```
654
+ GET /trends?woeid=1&count=30
655
+ ```
656
+
657
+ Metered. Subscription required. Cached, refreshes every 15 minutes.
658
+
659
+ **WOEIDs:** 1 (Worldwide), 23424977 (US), 23424975 (UK), 23424969 (Turkey), 23424950 (Spain), 23424829 (Germany), 23424819 (France), 23424856 (Japan), 23424848 (India), 23424768 (Brazil), 23424775 (Canada), 23424900 (Mexico).
660
+
661
+ **Response:**
662
+ ```json
663
+ {
664
+ "trends": [
665
+ { "name": "#AI", "description": "...", "rank": 1, "query": "#AI" }
666
+ ],
667
+ "total": 30,
668
+ "woeid": 1
669
+ }
670
+ ```
671
+
672
+ ---
673
+
674
+ ## Radar
675
+
676
+ ### List Radar Items
677
+
678
+ ```
679
+ GET /radar
680
+ ```
681
+
682
+ Get trending topics and news from 7 sources: Google Trends, Hacker News, Polymarket, TrustMRR, Wikipedia, GitHub Trending, Reddit. Free.
683
+
684
+ **Query parameters:**
685
+
686
+ | Param | Type | Description |
687
+ |-------|------|-------------|
688
+ | `source` | string | Filter by source: `google_trends`, `hacker_news`, `polymarket`, `trustmrr`, `wikipedia`, `github`, `reddit` |
689
+ | `category` | string | Filter by category: `general`, `tech`, `dev`, `science`, `culture`, `politics`, `business`, `entertainment` |
690
+ | `limit` | number | Items per page (1-100, default 50) |
691
+ | `hours` | number | Look-back window in hours (1-72, default 6) |
692
+ | `region` | string | Region code: `US`, `GB`, `TR`, `ES`, `DE`, `FR`, `JP`, `IN`, `BR`, `CA`, `MX`, `global` (default) |
693
+
694
+ **Response:**
695
+ ```json
696
+ {
697
+ "items": [
698
+ {
699
+ "id": "12345",
700
+ "title": "Claude 4.6 Released",
701
+ "description": "Anthropic releases Claude 4.6...",
702
+ "url": "https://example.com/article",
703
+ "imageUrl": "https://example.com/image.png",
704
+ "source": "hacker_news",
705
+ "sourceId": "hn_12345",
706
+ "category": "tech",
707
+ "region": "global",
708
+ "language": "en",
709
+ "score": 450,
710
+ "metadata": { "points": 450, "numberComments": 132, "author": "pgdev" },
711
+ "publishedAt": "2026-03-05T10:00:00.000Z",
712
+ "createdAt": "2026-03-05T10:05:00.000Z"
713
+ }
714
+ ],
715
+ "hasMore": true,
716
+ "nextCursor": "NDUwfDIwMjYtMDMtMDRUMDg6MzA6MDAuMDAwWnwxMjM0NQ=="
717
+ }
718
+ ```
719
+
720
+ Fields: `id`, `title`, `description?`, `url?`, `imageUrl?`, `source`, `sourceId`, `category`, `region`, `language`, `score`, `metadata`, `publishedAt`, `createdAt`. Response includes `hasMore` and `nextCursor` for pagination.
721
+
722
+ ---
723
+
724
+ ## Compose
725
+
726
+ ### Compose Tweet
727
+
728
+ ```
729
+ POST /compose
730
+ ```
731
+
732
+ Compose, refine, and score tweets using X algorithm data. Free, 3-step workflow.
733
+
734
+ **Body:**
735
+
736
+ | Field | Type | Required | Description |
737
+ |-------|------|----------|-------------|
738
+ | `step` | string | Yes | `compose`, `refine`, or `score` |
739
+ | `topic` | string | No | Tweet topic (compose, refine) |
740
+ | `goal` | string | No | `engagement`, `followers`, `authority`, `conversation` |
741
+ | `styleUsername` | string | No | Cached style username for voice matching (compose) |
742
+ | `tone` | string | No | Desired tone (refine) |
743
+ | `additionalContext` | string | No | Extra context or URLs (refine) |
744
+ | `callToAction` | string | No | Desired CTA (refine) |
745
+ | `mediaType` | string | No | `photo`, `video`, `none` (refine) |
746
+ | `draft` | string | No | Tweet text to evaluate (score) |
747
+ | `hasLink` | boolean | No | Link attached (score) |
748
+ | `hasMedia` | boolean | No | Media attached (score) |
749
+
750
+ **Response (step=compose):** Returns `contentRules`, `scorerWeights`, `followUpQuestions`, `algorithmInsights`, `engagementMultipliers`, `topPenalties`.
751
+
752
+ **Response (step=refine):** Returns `compositionGuidance`, `examplePatterns`.
753
+
754
+ **Response (step=score):** Returns `totalChecks`, `passedCount`, `topSuggestion`, `checklist[]` with `factor`, `passed`, `suggestion`.
755
+
756
+ ---
757
+
758
+ ## Drafts
759
+
760
+ ### Create Draft
761
+
762
+ `POST /drafts`
763
+
764
+ Save a tweet draft for later.
765
+
766
+ **Request body:**
767
+
768
+ | Field | Type | Required | Description |
769
+ |-------|------|----------|-------------|
770
+ | `text` | string | Yes | The draft tweet text |
771
+ | `topic` | string | No | Topic the tweet is about |
772
+ | `goal` | string | No | Optimization goal: `engagement`, `followers`, `authority`, `conversation` |
773
+
774
+ **Response (201):**
775
+
776
+ ```json
777
+ {
778
+ "id": "123",
779
+ "text": "draft text",
780
+ "topic": "product launch",
781
+ "goal": "engagement",
782
+ "createdAt": "2026-02-24T10:30:00.000Z",
783
+ "updatedAt": "2026-02-24T10:30:00.000Z"
784
+ }
785
+ ```
786
+
787
+ ---
788
+
789
+ ### List Drafts
790
+
791
+ `GET /drafts`
792
+
793
+ List saved tweet drafts with cursor pagination.
794
+
795
+ **Query parameters:**
796
+
797
+ | Parameter | Type | Required | Default | Description |
798
+ |-----------|------|----------|---------|-------------|
799
+ | `limit` | number | No | 50 | Results per page (max 50) |
800
+ | `afterCursor` | string | No | - | Pagination cursor from previous response |
801
+
802
+ **Response (200):**
803
+
804
+ ```json
805
+ {
806
+ "drafts": [
807
+ {
808
+ "id": "123",
809
+ "text": "draft text",
810
+ "topic": "product launch",
811
+ "goal": "engagement",
812
+ "createdAt": "2026-02-24T10:30:00.000Z",
813
+ "updatedAt": "2026-02-24T10:30:00.000Z"
814
+ }
815
+ ],
816
+ "afterCursor": "cursor_string",
817
+ "hasMore": true
818
+ }
819
+ ```
820
+
821
+ ---
822
+
823
+ ### Get Draft
824
+
825
+ `GET /drafts/{id}`
826
+
827
+ Get a specific draft by ID.
828
+
829
+ **Response (200):** Single draft object.
830
+
831
+ **Errors:** `400 invalid_id`, `404 draft_not_found`
832
+
833
+ ---
834
+
835
+ ### Delete Draft
836
+
837
+ `DELETE /drafts/{id}`
838
+
839
+ Delete a draft. Returns `204 No Content`.
840
+
841
+ **Errors:** `400 invalid_id`, `404 draft_not_found`
842
+
843
+ ---
844
+
845
+ ## Tweet Style Cache
846
+
847
+ ### Analyze & Cache Style
848
+
849
+ `POST /styles`
850
+
851
+ Fetch recent tweets from an X account and cache them for style analysis. **Consumes API usage credits.**
852
+
853
+ **Request body:**
854
+
855
+ | Field | Type | Required | Description |
856
+ |-------|------|----------|-------------|
857
+ | `username` | string | Yes | X username to analyze (without @) |
858
+
859
+ **Response (201):**
860
+
861
+ ```json
862
+ {
863
+ "xUsername": "elonmusk",
864
+ "tweetCount": 20,
865
+ "isOwnAccount": false,
866
+ "fetchedAt": "2026-02-24T10:30:00.000Z",
867
+ "tweets": [
868
+ {
869
+ "id": "1893456789012345678",
870
+ "text": "The future is now.",
871
+ "authorUsername": "elonmusk",
872
+ "createdAt": "2026-02-24T14:22:00.000Z"
873
+ }
874
+ ]
875
+ }
876
+ ```
877
+
878
+ ---
879
+
880
+ ### List Cached Styles
881
+
882
+ `GET /styles`
883
+
884
+ List all cached tweet style profiles. Max 200 results, ordered by fetch date.
885
+
886
+ **Response (200):**
887
+
888
+ ```json
889
+ {
890
+ "styles": [
891
+ {
892
+ "xUsername": "elonmusk",
893
+ "tweetCount": 20,
894
+ "isOwnAccount": false,
895
+ "fetchedAt": "2026-02-24T10:30:00.000Z"
896
+ }
897
+ ]
898
+ }
899
+ ```
900
+
901
+ ---
902
+
903
+ ### Save Custom Style
904
+
905
+ `PUT /styles/{username}`
906
+
907
+ Save a custom style profile from tweet texts. Free, no usage cost. Replaces existing style if one exists with the same label.
908
+
909
+ **Body:**
910
+
911
+ | Field | Type | Required | Description |
912
+ |-------|------|----------|-------------|
913
+ | `label` | string | Yes | Style label name (1-30 characters) |
914
+ | `tweets` | object[] | Yes | Array of tweet objects (1-100). Each must have a `text` field |
915
+
916
+ **Response (200):** Style object with label, `tweetCount`, `isOwnAccount: false`, `fetchedAt`, and `tweets` array.
917
+
918
+ **Errors:** `400 invalid_input`
919
+
920
+ ---
921
+
922
+ ### Get Cached Style
923
+
924
+ `GET /styles/{username}`
925
+
926
+ Get a cached style profile with full tweet data.
927
+
928
+ **Response (200):** Full style object with `tweets` array.
929
+
930
+ **Errors:** `404 style_not_found`
931
+
932
+ ---
933
+
934
+ ### Delete Cached Style
935
+
936
+ `DELETE /styles/{username}`
937
+
938
+ Delete a cached style. Returns `204 No Content`.
939
+
940
+ **Errors:** `404 style_not_found`
941
+
942
+ ---
943
+
944
+ ### Compare Styles
945
+
946
+ `GET /styles/compare?username1=A&username2=B`
947
+
948
+ Compare two cached tweet style profiles side by side.
949
+
950
+ **Query parameters:**
951
+
952
+ | Parameter | Type | Required | Description |
953
+ |-----------|------|----------|-------------|
954
+ | `username1` | string | Yes | First X username |
955
+ | `username2` | string | Yes | Second X username |
956
+
957
+ **Response (200):**
958
+
959
+ ```json
960
+ {
961
+ "style1": { "xUsername": "user1", "tweetCount": 20, "isOwnAccount": true, "fetchedAt": "...", "tweets": [...] },
962
+ "style2": { "xUsername": "user2", "tweetCount": 15, "isOwnAccount": false, "fetchedAt": "...", "tweets": [...] }
963
+ }
964
+ ```
965
+
966
+ **Errors:** `400 missing_params`, `404 style_not_found`
967
+
968
+ ---
969
+
970
+ ### Analyze Performance
971
+
972
+ `GET /styles/{username}/performance`
973
+
974
+ Get live engagement metrics for cached tweets. **Consumes API usage credits.**
975
+
976
+ **Response (200):**
977
+
978
+ ```json
979
+ {
980
+ "xUsername": "elonmusk",
981
+ "tweetCount": 20,
982
+ "tweets": [
983
+ {
984
+ "id": "1893456789012345678",
985
+ "text": "The future is now.",
986
+ "likeCount": 42000,
987
+ "retweetCount": 8500,
988
+ "replyCount": 3200,
989
+ "quoteCount": 1100,
990
+ "viewCount": 5000000,
991
+ "bookmarkCount": 2400
992
+ }
993
+ ]
994
+ }
995
+ ```
996
+
997
+ **Errors:** `404 style_not_found`
998
+
999
+ ---
1000
+
1001
+ ## Account Identity
1002
+
1003
+ ### Set X Identity
1004
+
1005
+ `PUT /account/x-identity`
1006
+
1007
+ Link your X username to your Xquik account. Required for own-account detection in style analysis.
1008
+
1009
+ **Request body:**
1010
+
1011
+ | Field | Type | Required | Description |
1012
+ |-------|------|----------|-------------|
1013
+ | `username` | string | Yes | Your X username (without @) |
1014
+
1015
+ **Response (200):**
1016
+
1017
+ ```json
1018
+ {
1019
+ "success": true,
1020
+ "xUsername": "elonmusk"
1021
+ }
1022
+ ```
1023
+
1024
+ **Errors:** `400 invalid_input`
1025
+
1026
+ ---
1027
+
1028
+ ## Subscribe
1029
+
1030
+ ### Get Subscription Link
1031
+
1032
+ ```
1033
+ POST /subscribe
1034
+ ```
1035
+
1036
+ Returns a checkout URL for subscribing or managing the subscription. If already subscribed, returns the billing portal URL.
1037
+
1038
+ **Response:**
1039
+ ```json
1040
+ {
1041
+ "url": "https://checkout.xquik.com/..."
1042
+ }
1043
+ ```
1044
+
1045
+ ---
1046
+
1047
+ ## X Accounts (Connected)
1048
+
1049
+ Manage connected X accounts for write actions. All endpoints are free (no usage cost).
1050
+
1051
+ ### List X Accounts
1052
+
1053
+ ```
1054
+ GET /x/accounts
1055
+ ```
1056
+
1057
+ Returns all connected X accounts. Response: `{ accounts: [{ id, username, displayName, isActive, createdAt }] }`.
1058
+
1059
+ ### Connect X Account
1060
+
1061
+ ```
1062
+ POST /x/accounts
1063
+ ```
1064
+
1065
+ **Body:**
1066
+
1067
+ | Field | Type | Required | Description |
1068
+ |-------|------|----------|-------------|
1069
+ | `username` | string | Yes | X username (`@` auto-stripped) |
1070
+ | `email` | string | Yes | Email associated with the X account |
1071
+ | `password` | string | Yes | Account password (encrypted at rest) |
1072
+ | `totp_secret` | string | No | TOTP base32 secret for 2FA accounts |
1073
+ | `proxy_country` | string | No | Preferred proxy region (e.g. `"US"`, `"TR"`) |
1074
+
1075
+ **Response (201):** `{ id, username, isActive, createdAt }`
1076
+
1077
+ **Errors:** `409 account_already_connected`, `422 login_failed`
1078
+
1079
+ **Security:** This is a credential proxy endpoint. The agent transmits the user's X credentials to Xquik over HTTPS for session establishment. Credentials are encrypted at rest and never returned in responses. Before calling: (1) confirm with the user that they want to connect this account, (2) show which fields will be sent, (3) never log or retain credentials after the call.
1080
+
1081
+ ### Get X Account
1082
+
1083
+ ```
1084
+ GET /x/accounts/{id}
1085
+ ```
1086
+
1087
+ Returns `{ id, username, displayName, isActive, createdAt }`.
1088
+
1089
+ ### Disconnect X Account
1090
+
1091
+ ```
1092
+ DELETE /x/accounts/{id}
1093
+ ```
1094
+
1095
+ Permanently removes the account and deletes stored credentials. Returns `{ success: true }`.
1096
+
1097
+ ### Re-authenticate X Account
1098
+
1099
+ ```
1100
+ POST /x/accounts/{id}/reauth
1101
+ ```
1102
+
1103
+ Use when a session expires or X requires re-verification.
1104
+
1105
+ **Body:** `{ "password": "...", "totp_secret": "..." }` (password required, totp_secret optional)
1106
+
1107
+ **Response:** `{ success: true }`
1108
+
1109
+ **Errors:** `422 reauth_failed`
1110
+
1111
+ **Security:** Same credential proxy rules as POST /x/accounts — confirm with user, never log or retain credentials.
1112
+
1113
+ ---
1114
+
1115
+ ## X Write
1116
+
1117
+ Write actions performed through connected X accounts. All endpoints are metered. Every request requires an `account` field (username or account ID) identifying which connected account to use.
1118
+
1119
+ ### Create Tweet
1120
+
1121
+ ```
1122
+ POST /x/tweets
1123
+ ```
1124
+
1125
+ **Body:**
1126
+
1127
+ | Field | Type | Required | Description |
1128
+ |-------|------|----------|-------------|
1129
+ | `account` | string | Yes | Connected X username or account ID |
1130
+ | `text` | string | Yes | Tweet text (280 chars, or 25,000 if `is_note_tweet` is true) |
1131
+ | `reply_to_tweet_id` | string | No | Tweet ID to reply to |
1132
+ | `attachment_url` | string | No | URL to attach as a card |
1133
+ | `community_id` | string | No | Community ID to post into |
1134
+ | `is_note_tweet` | boolean | No | Long-form note tweet (up to 25,000 chars) |
1135
+ | `media_ids` | string[] | No | Media IDs from `POST /x/media` (max 4 images or 1 video) |
1136
+
1137
+ **Response:** `{ tweetId, success: true }`
1138
+
1139
+ **Errors:** `502 x_write_failed`
1140
+
1141
+ ### Delete Tweet
1142
+
1143
+ ```
1144
+ DELETE /x/tweets/{id}
1145
+ ```
1146
+
1147
+ **Body:** `{ "account": "username" }`
1148
+
1149
+ **Response:** `{ success: true }`
1150
+
1151
+ ### Like Tweet
1152
+
1153
+ ```
1154
+ POST /x/tweets/{id}/like
1155
+ ```
1156
+
1157
+ **Body:** `{ "account": "username" }`
1158
+
1159
+ ### Unlike Tweet
1160
+
1161
+ ```
1162
+ DELETE /x/tweets/{id}/like
1163
+ ```
1164
+
1165
+ **Body:** `{ "account": "username" }`
1166
+
1167
+ ### Retweet
1168
+
1169
+ ```
1170
+ POST /x/tweets/{id}/retweet
1171
+ ```
1172
+
1173
+ **Body:** `{ "account": "username" }`
1174
+
1175
+ ### Follow User
1176
+
1177
+ ```
1178
+ POST /x/users/{id}/follow
1179
+ ```
1180
+
1181
+ **Body:** `{ "account": "username" }`
1182
+
1183
+ **Errors:** `502 x_write_failed`
1184
+
1185
+ ### Unfollow User
1186
+
1187
+ ```
1188
+ DELETE /x/users/{id}/follow
1189
+ ```
1190
+
1191
+ **Body:** `{ "account": "username" }`
1192
+
1193
+ ### Send DM
1194
+
1195
+ ```
1196
+ POST /x/dm/{userId}
1197
+ ```
1198
+
1199
+ **Body:**
1200
+
1201
+ | Field | Type | Required | Description |
1202
+ |-------|------|----------|-------------|
1203
+ | `account` | string | Yes | Connected X username or account ID |
1204
+ | `text` | string | Yes | Message text |
1205
+ | `media_ids` | string[] | No | Media IDs to attach |
1206
+ | `reply_to_message_id` | string | No | Message ID to reply to |
1207
+
1208
+ ### Get DM History
1209
+
1210
+ ```
1211
+ GET /x/dm/{userId}/history
1212
+ ```
1213
+
1214
+ Get DM conversation history with a user. Requires a connected X account. Metered (1 credit/result).
1215
+
1216
+ **Sensitive:** Returns private DM conversations. Confirm with user before calling. Do not forward to other tools without consent.
1217
+
1218
+ ### Update Profile
1219
+
1220
+ ```
1221
+ PATCH /x/profile
1222
+ ```
1223
+
1224
+ **Body:** `{ "account": "username", "name": "...", "description": "...", "location": "...", "url": "..." }` (account required, others optional)
1225
+
1226
+ ### Update Avatar
1227
+
1228
+ ```
1229
+ PATCH /x/profile/avatar
1230
+ ```
1231
+
1232
+ Update profile avatar. Max 700 KB, GIF/JPEG/PNG. Metered (10 credits).
1233
+
1234
+ **Body:** FormData with `account` (required) and `file` (required, max 700 KB).
1235
+
1236
+ ### Update Banner
1237
+
1238
+ ```
1239
+ PATCH /x/profile/banner
1240
+ ```
1241
+
1242
+ Update profile banner. Max 2 MB, GIF/JPEG/PNG. Metered (10 credits).
1243
+
1244
+ **Body:** FormData with `account` (required) and `file` (required, max 2 MB).
1245
+
1246
+ ### Upload Media
1247
+
1248
+ ```
1249
+ POST /x/media
1250
+ ```
1251
+
1252
+ **Body:** FormData with `account` (required), `file` (required), and `is_long_video` (optional boolean). Alternatively, JSON body with `account` (required) and `url` (required, direct media URL) for URL-based upload.
1253
+
1254
+ **Response:** Returns a media ID to pass in `media_ids` when creating a tweet.
1255
+
1256
+ ### Create Community
1257
+
1258
+ ```
1259
+ POST /x/communities
1260
+ ```
1261
+
1262
+ **Body:** `{ "account": "username", "name": "...", "description": "..." }` (all required)
1263
+
1264
+ ### Delete Community
1265
+
1266
+ ```
1267
+ DELETE /x/communities/{id}
1268
+ ```
1269
+
1270
+ **Body:** `{ "account": "username", "community_name": "..." }` (name required for confirmation)
1271
+
1272
+ ### Join Community
1273
+
1274
+ ```
1275
+ POST /x/communities/{id}/join
1276
+ ```
1277
+
1278
+ **Body:** `{ "account": "username" }`
1279
+
1280
+ **Errors:** `409 already_member`
1281
+
1282
+ ### Leave Community
1283
+
1284
+ ```
1285
+ DELETE /x/communities/{id}/join
1286
+ ```
1287
+
1288
+ **Body:** `{ "account": "username" }`
1289
+
1290
+ ---
1291
+
1292
+ ## Integrations
1293
+
1294
+ Manage third-party integrations (currently Telegram) that receive monitor event notifications. All endpoints are free (no usage cost).
1295
+
1296
+ ### Create Integration
1297
+
1298
+ ```
1299
+ POST /integrations
1300
+ ```
1301
+
1302
+ **Body:**
1303
+
1304
+ | Field | Type | Required | Description |
1305
+ |-------|------|----------|-------------|
1306
+ | `type` | string | Yes | Integration type: `"telegram"` |
1307
+ | `name` | string | Yes | Human-readable name |
1308
+ | `config` | object | Yes | Type-specific config. Telegram: `{ chatId: "-1001234567890" }` |
1309
+ | `eventTypes` | string[] | Yes | Event types: `tweet.new`, `tweet.quote`, `tweet.reply`, `tweet.retweet`, `draw.completed`, `extraction.completed`, `extraction.failed` |
1310
+
1311
+ **Response (201):** `{ id, type, name, config, eventTypes, isActive, createdAt }`
1312
+
1313
+ ### List Integrations
1314
+
1315
+ ```
1316
+ GET /integrations
1317
+ ```
1318
+
1319
+ Returns all integrations. Response: `{ integrations: [...] }`.
1320
+
1321
+ ### Get Integration
1322
+
1323
+ ```
1324
+ GET /integrations/{id}
1325
+ ```
1326
+
1327
+ Returns a single integration with full details.
1328
+
1329
+ ### Update Integration
1330
+
1331
+ ```
1332
+ PATCH /integrations/{id}
1333
+ ```
1334
+
1335
+ **Body:** `{ "name": "...", "eventTypes": [...], "isActive": true|false, "silentPush": false, "scopeAllMonitors": true, "filters": {}, "messageTemplate": {} }` (all optional, at least 1 required)
1336
+
1337
+ ### Delete Integration
1338
+
1339
+ ```
1340
+ DELETE /integrations/{id}
1341
+ ```
1342
+
1343
+ Permanently removes the integration. Returns `204 No Content`.
1344
+
1345
+ ### Test Integration
1346
+
1347
+ ```
1348
+ POST /integrations/{id}/test
1349
+ ```
1350
+
1351
+ Sends a test notification. Returns success or failure status.
1352
+
1353
+ **Errors:** `502 delivery_failed`
1354
+
1355
+ ### List Deliveries
1356
+
1357
+ ```
1358
+ GET /integrations/{id}/deliveries
1359
+ ```
1360
+
1361
+ View delivery attempts and statuses. Statuses: `pending`, `delivered`, `failed`, `exhausted`.
1362
+
1363
+ **Query:** `limit` (default 50).
1364
+
1365
+ ---
1366
+
1367
+ ## Automations
1368
+
1369
+ Trigger-driven workflow automation. Create flows with triggers (monitor events, schedules, search, inbound webhooks) and action steps.
1370
+
1371
+ ### List Automations
1372
+
1373
+ ```
1374
+ GET /automations
1375
+ ```
1376
+
1377
+ Returns all flows. Response: `{ items: [{ id, name, slug, triggerType, triggerConfig, isActive, runCount, lastRunAt, minIntervalSeconds, pausedReason, templateSlug, xAccountId, createdAt, updatedAt }] }`.
1378
+
1379
+ ### Create Automation
1380
+
1381
+ ```
1382
+ POST /automations
1383
+ ```
1384
+
1385
+ **Body:**
1386
+ ```json
1387
+ {
1388
+ "name": "New Follower Welcome",
1389
+ "triggerType": "monitor_event",
1390
+ "triggerConfig": { "eventType": "follower.gained" },
1391
+ "templateSlug": "welcome-dm"
1392
+ }
1393
+ ```
1394
+
1395
+ Trigger types: `monitor_event`, `schedule`, `search`, `webhook_inbound`.
1396
+
1397
+ **Response (201):** Flow object with `id`, `slug`, `isActive: false`.
1398
+
1399
+ Flows are created inactive. Add steps, then activate via `PATCH /automations/{slug}`.
1400
+
1401
+ Free: 2 flows. Subscribers: 10 flows.
1402
+
1403
+ ### Get Automation
1404
+
1405
+ ```
1406
+ GET /automations/{slug}
1407
+ ```
1408
+
1409
+ Returns flow with steps and 20 most recent runs.
1410
+
1411
+ ### Update Automation
1412
+
1413
+ ```
1414
+ PATCH /automations/{slug}
1415
+ ```
1416
+
1417
+ **Body:** `{ "expectedUpdatedAt": "...", "name": "...", "triggerType": "...", "triggerConfig": {...}, "isActive": true|false }`. `expectedUpdatedAt` required (optimistic concurrency). Returns `409 conflict` if stale.
1418
+
1419
+ Activation requires an active subscription and at least 1 action step.
1420
+
1421
+ ### Delete Automation
1422
+
1423
+ ```
1424
+ DELETE /automations/{slug}
1425
+ ```
1426
+
1427
+ Deletes the flow and all its steps. Returns `{ success: true }`.
1428
+
1429
+ ### Add Step
1430
+
1431
+ ```
1432
+ POST /automations/{slug}/steps
1433
+ ```
1434
+
1435
+ **Body:**
1436
+ ```json
1437
+ {
1438
+ "stepType": "action",
1439
+ "actionType": "send_dm",
1440
+ "branch": "main",
1441
+ "config": { "message": "Welcome!" },
1442
+ "position": 0
1443
+ }
1444
+ ```
1445
+
1446
+ Step types: `action`, `condition`, `extraction`. Max 10 steps per flow.
1447
+
1448
+ Action types: `create_tweet`, `follow`, `like`, `reply_tweet`, `retweet`, `send_dm`, `send_email`, `send_telegram`, `unfollow`.
1449
+
1450
+ Extraction types: all 23 extraction tool types (kebab-case, e.g. `reply-extractor`). Requires `outputName` for variable reference in later steps.
1451
+
1452
+ ### Update Step
1453
+
1454
+ ```
1455
+ PATCH /automations/{slug}/steps
1456
+ ```
1457
+
1458
+ **Body:** `{ "stepId": "101", "config": {...}, "positionX": 250, "positionY": 100 }`. `stepId` required.
1459
+
1460
+ ### Delete Step
1461
+
1462
+ ```
1463
+ DELETE /automations/{slug}/steps
1464
+ ```
1465
+
1466
+ **Body:** `{ "stepId": "101" }`.
1467
+
1468
+ ### Update Step Positions
1469
+
1470
+ ```
1471
+ PATCH /automations/{slug}/steps/positions
1472
+ ```
1473
+
1474
+ Batch update canvas positions: `{ "positions": [{ "stepId": "101", "positionX": 250, "positionY": 100 }] }`.
1475
+
1476
+ ### Test Automation
1477
+
1478
+ ```
1479
+ POST /automations/{slug}/test
1480
+ ```
1481
+
1482
+ Not yet implemented. Returns `{ status: "not_implemented" }`.
1483
+
1484
+ ### Inbound Webhook Trigger
1485
+
1486
+ ```
1487
+ POST /webhooks/inbound/{token}
1488
+ ```
1489
+
1490
+ No auth header required. The URL token identifies the flow. Accepts any JSON body as trigger payload. Rate limited per flow (60/hour) and per user (300/hour).
1491
+
1492
+ ---
1493
+
1494
+ ## Credits
1495
+
1496
+ ### Get Credit Balance
1497
+
1498
+ ```
1499
+ GET /credits
1500
+ ```
1501
+
1502
+ Get credit balance, lifetime purchased/used, and auto top-up status. Free.
1503
+
1504
+ ### Top Up Credits
1505
+
1506
+ ```
1507
+ POST /credits/topup
1508
+ ```
1509
+
1510
+ Get a checkout URL to purchase credits ($10 minimum). Free.
1511
+
1512
+ ---
1513
+
1514
+ ## Support
1515
+
1516
+ ### Create Ticket
1517
+
1518
+ ```
1519
+ POST /support/tickets
1520
+ ```
1521
+
1522
+ **Body:** `{ "subject": "...", "body": "..." }`
1523
+
1524
+ **Response (201):** `{ id, subject, status, createdAt }`
1525
+
1526
+ ### List Tickets
1527
+
1528
+ ```
1529
+ GET /support/tickets
1530
+ ```
1531
+
1532
+ Returns all tickets for the authenticated user.
1533
+
1534
+ ### Get Ticket
1535
+
1536
+ ```
1537
+ GET /support/tickets/{id}
1538
+ ```
1539
+
1540
+ Returns ticket with messages.
1541
+
1542
+ ### Update Ticket
1543
+
1544
+ ```
1545
+ PATCH /support/tickets/{id}
1546
+ ```
1547
+
1548
+ Update ticket status.
1549
+
1550
+ ### Reply to Ticket
1551
+
1552
+ ```
1553
+ POST /support/tickets/{id}/messages
1554
+ ```
1555
+
1556
+ **Body:** `{ "body": "..." }`
1557
+
1558
+ Add a message to an existing ticket.
1559
+
1560
+ ---
1561
+
1562
+ ## Error Codes
1563
+
1564
+ | Status | Code | Meaning |
1565
+ |--------|------|---------|
1566
+ | 400 | `invalid_input` | Request body failed validation |
1567
+ | 400 | `invalid_id` | Path parameter is not a valid ID |
1568
+ | 400 | `invalid_json` | Invalid JSON in request body |
1569
+ | 400 | `invalid_tweet_url` | Tweet URL format is invalid |
1570
+ | 400 | `invalid_tweet_id` | Tweet ID is empty or invalid |
1571
+ | 400 | `invalid_username` | X username is empty or invalid |
1572
+ | 400 | `invalid_tool_type` | Extraction tool type not recognized |
1573
+ | 400 | `invalid_format` | Export format not `csv`, `xlsx`, or `md` |
1574
+ | 400 | `invalid_params` | Export query parameters are missing or invalid |
1575
+ | 400 | `missing_query` | Required query parameter is missing |
1576
+ | 400 | `missing_params` | Required query parameters are missing |
1577
+ | 400 | `no_media` | Tweet has no downloadable media |
1578
+ | 400 | `webhook_inactive` | Webhook is disabled (test-webhook only) |
1579
+ | 401 | `unauthenticated` | Missing or invalid API key |
1580
+ | 403 | `account_needs_reauth` | X account session expired, re-authenticate |
1581
+ | 402 | `no_subscription` | No active subscription |
1582
+ | 402 | `subscription_inactive` | Subscription is not active |
1583
+ | 402 | `usage_limit_reached` | Monthly usage cap exceeded |
1584
+ | 402 | `extra_usage_disabled` | Extra usage not enabled |
1585
+ | 402 | `extra_usage_requires_v2` | Extra usage requires the new pricing plan |
1586
+ | 402 | `frozen` | Extra usage paused, outstanding payment required |
1587
+ | 402 | `overage_limit_reached` | Overage spending limit reached |
1588
+ | 402 | `no_addon` | No monitor addon on subscription |
1589
+ | 403 | `monitor_limit_reached` | Plan monitor limit exceeded |
1590
+ | 403 | `api_key_limit_reached` | API key limit reached (100 max) |
1591
+ | 403 | `flow_limit_reached` | Flow limit reached (free: 2, subscriber: 10) |
1592
+ | 403 | `step_limit_reached` | Step limit reached (10 per flow) |
1593
+ | 404 | `not_found` | Resource does not exist |
1594
+ | 404 | `user_not_found` | X user not found |
1595
+ | 404 | `tweet_not_found` | Tweet not found |
1596
+ | 404 | `style_not_found` | No cached style found |
1597
+ | 404 | `draft_not_found` | Draft not found |
1598
+ | 409 | `monitor_already_exists` | Duplicate monitor for same username |
1599
+ | 409 | `conflict` | Concurrent edit conflict (automation updates) |
1600
+ | 422 | `login_failed` | X credential verification failed |
1601
+ | 429 | - | Rate limited. Retry with backoff |
1602
+ | 429 | `x_api_rate_limited` | X data source rate limited. Retry |
1603
+ | 500 | `internal_error` | Server error |
1604
+ | 502 | `stream_registration_failed` | Stream registration failed. Retry |
1605
+ | 502 | `x_api_unavailable` | X data source temporarily unavailable |
1606
+ | 502 | `x_api_unauthorized` | X data source authentication failed. Retry |
1607
+ | 502 | `delivery_failed` | Integration test delivery failed |