@@ -9,14 +9,17 @@ import { RequestOptions } from '../internal/request-options';
99 */
1010export class Compose extends APIResource {
1111 /**
12- * Compose, refine, or score a tweet
12+ * Run one step of Xquik's three-step writing workflow. Compose returns questions
13+ * and editorial rules. Refine returns goal-specific guidance. Score applies
14+ * deterministic text checks. It does not predict reach or expose X ranking
15+ * weights.
1316 *
1417 * @example
1518 * ```ts
1619 * const compose = await client.compose.create({
1720 * step: 'compose',
21+ * topic: 'PostgreSQL query planning',
1822 * goal: 'engagement',
19- * topic: 'AI trends in 2025',
2023 * });
2124 * ```
2225 */
@@ -25,85 +28,249 @@ export class Compose extends APIResource {
2528 }
2629}
2730
28- export interface ComposeCreateResponse {
29- /**
30- * AI feedback on the draft
31- */
32- feedback ?: string ;
31+ export type ComposeCreateResponse =
32+ | ComposeCreateResponse . ComposePrepareResult
33+ | ComposeCreateResponse . ComposeRefineResult
34+ | ComposeCreateResponse . ComposeScoreResult ;
3335
34- /**
35- * Engagement score (0-100)
36- */
37- score ?: number ;
36+ export namespace ComposeCreateResponse {
37+ export interface ComposePrepareResult {
38+ /**
39+ * Xquik editorial heuristics, ordered for the goal.
40+ */
41+ contentRules : Array < ComposePrepareResult . ContentRule > ;
3842
39- /**
40- * Improvement suggestions
41- */
42- suggestions ? : Array < string > ;
43+ /**
44+ * Published engagement signal names. Production multipliers are not published.
45+ */
46+ engagementMultipliers : Array < ComposePrepareResult . EngagementMultiplier > ;
4347
44- /**
45- * Generated or refined tweet text
46- */
47- text ?: string ;
48+ /**
49+ * Publication limit for timing and decay claims.
50+ */
51+ engagementVelocity : string ;
52+
53+ followUpQuestions : Array < string > ;
54+
55+ /**
56+ * X post intent seeded with the topic.
57+ */
58+ intentUrl : string ;
59+
60+ nextStep : string ;
61+
62+ /**
63+ * Published signal names with unpublished weights as null.
64+ */
65+ scorerWeights : Array < ComposePrepareResult . ScorerWeight > ;
66+
67+ /**
68+ * Signal source and evidence limits.
69+ */
70+ source : string ;
71+
72+ /**
73+ * Negative engagement predictions in the public model.
74+ */
75+ topPenalties : Array < string > ;
76+
77+ /**
78+ * Style analyses saved to the account.
79+ */
80+ savedStyles ?: Array < ComposePrepareResult . SavedStyle > ;
81+
82+ /**
83+ * Next action when no cached style is available.
84+ */
85+ styleNote ?: string ;
86+
87+ /**
88+ * Cached examples for the requested style username.
89+ */
90+ styleTweets ?: Array < string > ;
91+ }
92+
93+ export namespace ComposePrepareResult {
94+ export interface ContentRule {
95+ rule : string ;
96+ }
97+
98+ export interface EngagementMultiplier {
99+ /**
100+ * Human-readable published signal name.
101+ */
102+ action : string ;
103+
104+ multiplier : 'Production weight not published by X' ;
105+ }
106+
107+ export interface ScorerWeight {
108+ /**
109+ * Signal direction and publication limit.
110+ */
111+ context : string ;
112+
113+ /**
114+ * Signal name from X's public ranking repository.
115+ */
116+ signal : string ;
117+
118+ /**
119+ * X does not publish the production weight.
120+ */
121+ weight : null ;
122+ }
123+
124+ export interface SavedStyle {
125+ tweetCount : number ;
126+
127+ username : string ;
128+ }
129+ }
130+
131+ export interface ComposeRefineResult {
132+ /**
133+ * Goal, tone, media, and editorial guidance.
134+ */
135+ compositionGuidance : Array < string > ;
136+
137+ examplePatterns : Array < ComposeRefineResult . ExamplePattern > ;
138+
139+ /**
140+ * X post intent seeded with the topic.
141+ */
142+ intentUrl : string ;
143+
144+ nextStep : string ;
145+ }
146+
147+ export namespace ComposeRefineResult {
148+ export interface ExamplePattern {
149+ description : string ;
150+
151+ pattern : string ;
152+ }
153+ }
154+
155+ export interface ComposeScoreResult {
156+ /**
157+ * Deterministic editorial checks. Not a reach prediction.
158+ */
159+ checklist : Array < ComposeScoreResult . Checklist > ;
160+
161+ nextStep : string ;
162+
163+ passed : boolean ;
164+
165+ passedCount : number ;
166+
167+ topSuggestion : string ;
48168
49- [ k : string ] : unknown ;
169+ totalChecks : 9 ;
170+
171+ /**
172+ * Present only when every check passes.
173+ */
174+ intentUrl ?: string ;
175+ }
176+
177+ export namespace ComposeScoreResult {
178+ export interface Checklist {
179+ factor : string ;
180+
181+ passed : boolean ;
182+
183+ /**
184+ * Present only when the check fails.
185+ */
186+ suggestion ?: string ;
187+ }
188+ }
50189}
51190
52- export interface ComposeCreateParams {
53- /**
54- * Workflow step
55- */
56- step : 'compose' | 'refine' | 'score' ;
191+ export type ComposeCreateParams =
192+ | ComposeCreateParams . ComposePrepareRequest
193+ | ComposeCreateParams . ComposeRefineRequest
194+ | ComposeCreateParams . ComposeScoreRequest ;
57195
58- /**
59- * Extra context or URLs (refine)
60- */
61- additionalContext ?: string ;
196+ export declare namespace ComposeCreateParams {
197+ export interface ComposePrepareRequest {
198+ step : 'compose' ;
62199
63- /**
64- * Desired call to action (refine)
65- */
66- callToAction ? : string ;
200+ /**
201+ * Subject for the post.
202+ */
203+ topic : string ;
67204
68- /**
69- * Tweet draft text to evaluate (score)
70- */
71- draft ?: string ;
205+ /**
206+ * Editorial goal used to order the rules and questions.
207+ */
208+ goal ?: 'engagement' | 'followers' | 'authority' | 'conversation' ;
72209
73- /**
74- * Optimization goal
75- */
76- goal ?: 'engagement' | 'followers' | 'authority' | 'conversation' ;
210+ /**
211+ * Username from a style analysis saved to this account.
212+ */
213+ styleUsername ?: string ;
77214
78- /**
79- * Whether a link is attached (score)
80- */
81- hasLink ?: boolean ;
215+ [ k : string ] : unknown ;
216+ }
82217
83- /**
84- * Whether media is attached (score)
85- */
86- hasMedia ?: boolean ;
218+ export interface ComposeRefineRequest {
219+ /**
220+ * Editorial goal for the guidance.
221+ */
222+ goal : 'engagement' | 'followers' | 'authority' | 'conversation' ;
87223
88- /**
89- * Media type (refine)
90- */
91- mediaType ?: 'photo' | 'video' | 'none' ;
224+ step : 'refine' ;
92225
93- /**
94- * Cached style username for voice matching (compose)
95- */
96- styleUsername ? : string ;
226+ /**
227+ * Requested writing tone.
228+ */
229+ tone : string ;
97230
98- /**
99- * Desired tone (refine)
100- */
101- tone ? : string ;
231+ /**
232+ * Subject for the post.
233+ */
234+ topic : string ;
102235
103- /**
104- * Tweet topic (compose, refine)
105- */
106- topic ?: string ;
236+ /**
237+ * Audience, constraints, sources, or other writing context.
238+ */
239+ additionalContext ?: string ;
240+
241+ /**
242+ * Specific action the draft should request.
243+ */
244+ callToAction ?: string ;
245+
246+ /**
247+ * Planned media type.
248+ */
249+ mediaType ?: 'photo' | 'video' | 'none' ;
250+
251+ [ k : string ] : unknown ;
252+ }
253+
254+ export interface ComposeScoreRequest {
255+ /**
256+ * Full post text for deterministic editorial checks.
257+ */
258+ draft : string ;
259+
260+ step : 'score' ;
261+
262+ /**
263+ * True when a separate link card is attached.
264+ */
265+ hasLink ?: boolean ;
266+
267+ /**
268+ * @deprecated Accepted for backward compatibility. Text checks ignore this field.
269+ */
270+ hasMedia ?: boolean ;
271+
272+ [ k : string ] : unknown ;
273+ }
107274}
108275
109276export declare namespace Compose {
0 commit comments