postpeer 0.1.0__py3-none-any.whl

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,2061 @@
1
+ # This file is auto-generated by @hey-api/openapi-python
2
+
3
+ from datetime import date, datetime
4
+ from enum import Enum
5
+ from typing import Annotated, Any, Optional, Union
6
+
7
+ from pydantic import AnyUrl, BaseModel, ConfigDict, EmailStr, Field, RootModel
8
+
9
+
10
+ class Platform(str, Enum):
11
+ TWITTER = "twitter"
12
+ INSTAGRAM = "instagram"
13
+ YOUTUBE = "youtube"
14
+ TIKTOK = "tiktok"
15
+ PINTEREST = "pinterest"
16
+ LINKEDIN = "linkedin"
17
+ BLUESKY = "bluesky"
18
+ FACEBOOK = "facebook"
19
+ THREADS = "threads"
20
+ GOOGLEBUSINESS = "googlebusiness"
21
+
22
+
23
+ class Status(str, Enum):
24
+ DRAFT = "draft"
25
+ PENDING = "pending"
26
+ SCHEDULED = "scheduled"
27
+ PUBLISHING = "publishing"
28
+ PUBLISHED = "published"
29
+ FAILED = "failed"
30
+ PARTIAL = "partial"
31
+
32
+
33
+ class SortOrder(str, Enum):
34
+ ASC = "asc"
35
+ DESC = "desc"
36
+
37
+
38
+ class ErrorResponse(BaseModel):
39
+ success: bool
40
+ message: str
41
+
42
+
43
+ class TwitterConfigurationsReplySettings(str, Enum):
44
+ FOLLOWING = "following"
45
+ MENTIONED_USERS = "mentionedUsers"
46
+ SUBSCRIBERS = "subscribers"
47
+ VERIFIED = "verified"
48
+
49
+
50
+ class TwitterConfigurationsThreadItemsMediaItemsType(str, Enum):
51
+ IMAGE = "image"
52
+ VIDEO = "video"
53
+ GIF = "gif"
54
+ DOCUMENT = "document"
55
+
56
+
57
+ class TwitterConfigurationsThreadItemsMediaItems(BaseModel):
58
+ model_config = ConfigDict(extra="forbid")
59
+ type: TwitterConfigurationsThreadItemsMediaItemsType
60
+ url: AnyUrl
61
+ thumbnail: Optional[AnyUrl] = Field(default=None, description="Thumbnail image URL for video items. Supported on YouTube regular videos (not Shorts). JPEG, PNG, or GIF, max 2 MB, min 640 px wide.")
62
+
63
+
64
+ class TwitterConfigurationsThreadItems(BaseModel):
65
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
66
+ content: str = Field(..., description="Text of this thread tweet (max 280 chars)")
67
+ media_items: Optional[list[TwitterConfigurationsThreadItemsMediaItems]] = Field(default=None, alias="mediaItems")
68
+
69
+
70
+ class TwitterConfigurationsPoll(BaseModel):
71
+ """Cannot be combined with media or threadItems."""
72
+
73
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
74
+ options: Annotated[list[str], Field(min_length=2, max_length=4)] = Field(..., description="2–4 poll options.")
75
+ duration_minutes: Annotated[float, Field(ge=5, le=10080)] = Field(..., alias="durationMinutes", description="Poll duration in minutes (5 min – 7 days).")
76
+
77
+
78
+ class TwitterConfigurations(BaseModel):
79
+ """Pass this object in platformSpecificData when posting to Twitter/X, including Community post options."""
80
+
81
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
82
+ community_id: Optional[str] = Field(default=None, alias="communityId", description="Community ID to publish this post into.")
83
+ share_with_followers: Optional[bool] = Field(default=None, alias="shareWithFollowers", description="When posting to a Community, also share the post with followers.")
84
+ reply_to_tweet_id: Optional[str] = Field(default=None, alias="replyToTweetId", description="Tweet ID to reply to.")
85
+ reply_settings: Optional[TwitterConfigurationsReplySettings] = Field(default=None, alias="replySettings")
86
+ thread_items: Optional[list[TwitterConfigurationsThreadItems]] = Field(default=None, alias="threadItems", description="Additional tweets to chain as a thread. The root tweet uses post.content.")
87
+ poll: Optional[TwitterConfigurationsPoll] = Field(default=None, description="Cannot be combined with media or threadItems.")
88
+
89
+
90
+ class YouTubeConfigurationsVisibility(str, Enum):
91
+ """Who can see the video. Defaults to "public". Scheduled posts upload as private and flip to this value at publish time."""
92
+
93
+ PUBLIC = "public"
94
+ PRIVATE = "private"
95
+ UNLISTED = "unlisted"
96
+
97
+
98
+ class YouTubeConfigurations(BaseModel):
99
+ """Pass this object in platformSpecificData when posting to YouTube."""
100
+
101
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
102
+ title: Optional[Annotated[str, Field(max_length=100)]] = Field(default=None, description='Video title (max 100 chars, no < or >). Defaults to first 100 chars of content, or "Untitled Video".')
103
+ tags: Optional[list[str]] = Field(default=None, description="Video tags. Total characters across all tags must be ≤500.")
104
+ visibility: Optional[YouTubeConfigurationsVisibility] = Field(default=None, description='Who can see the video. Defaults to "public". Scheduled posts upload as private and flip to this value at publish time.')
105
+ made_for_kids: Optional[bool] = Field(default=None, alias="madeForKids", description="COPPA compliance flag. Setting to true permanently disables comments, notification bell, personalized ads, end screens, and cards on the video. Defaults to false.")
106
+ contains_synthetic_media: Optional[bool] = Field(default=None, alias="containsSyntheticMedia", description="AI-generated content disclosure. YouTube is increasingly enforcing this requirement. Defaults to false.")
107
+ category_id: Optional[str] = Field(default=None, alias="categoryId", description='YouTube category ID. Defaults to "22" (People & Blogs). Common values: "1" Film & Animation, "10" Music, "20" Gaming, "22" People & Blogs, "27" Education, "28" Science & Technology.')
108
+ first_comment: Optional[Annotated[str, Field(max_length=10000)]] = Field(default=None, alias="firstComment", description="Auto-posted comment after the video goes live. Max 10,000 characters. For publishNow posts: posted immediately after upload. For scheduled posts: posted when the video becomes public.")
109
+
110
+
111
+ class TikTokConfigurationsPrivacyLevel(str, Enum):
112
+ """Who can see this post. Defaults to "PUBLIC_TO_EVERYONE"."""
113
+
114
+ PUBLIC_TO_EVERYONE = "PUBLIC_TO_EVERYONE"
115
+ MUTUAL_FOLLOW_FRIENDS = "MUTUAL_FOLLOW_FRIENDS"
116
+ FOLLOWER_OF_CREATOR = "FOLLOWER_OF_CREATOR"
117
+ SELF_ONLY = "SELF_ONLY"
118
+
119
+
120
+ class TikTokConfigurations(BaseModel):
121
+ """Pass this object in platformSpecificData when posting to TikTok."""
122
+
123
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
124
+ privacy_level: Optional[TikTokConfigurationsPrivacyLevel] = Field(default=None, alias="privacyLevel", description='Who can see this post. Defaults to "PUBLIC_TO_EVERYONE".')
125
+ disable_comment: Optional[bool] = Field(default=None, alias="disableComment", description="Disable comments on this post. Defaults to false.")
126
+ disable_duet: Optional[bool] = Field(default=None, alias="disableDuet", description="Disable duet for this video. Videos only. Defaults to false.")
127
+ disable_stitch: Optional[bool] = Field(default=None, alias="disableStitch", description="Disable stitch for this video. Videos only. Defaults to false.")
128
+ brand_content_toggle: Optional[bool] = Field(default=None, alias="brandContentToggle", description="Mark as branded content (paid partnership). Defaults to false.")
129
+ brand_organic_toggle: Optional[bool] = Field(default=None, alias="brandOrganicToggle", description="Mark as organic brand promotion. Defaults to false.")
130
+ is_aigc: Optional[bool] = Field(default=None, alias="isAigc", description="AI-generated content disclosure. Videos only. Defaults to false.")
131
+ video_cover_timestamp_ms: Optional[Annotated[float, Field(ge=0)]] = Field(default=None, alias="videoCoverTimestampMs", description="Timestamp in milliseconds to use as the video cover frame. Videos only.")
132
+ auto_add_music: Optional[bool] = Field(default=None, alias="autoAddMusic", description="Automatically add background music to photo carousels. Photo posts only. Defaults to true.")
133
+ photo_cover_index: Optional[Annotated[float, Field(ge=0)]] = Field(default=None, alias="photoCoverIndex", description="0-indexed position of the cover image in a photo carousel. Photo posts only. Defaults to 0.")
134
+ description: Optional[Annotated[str, Field(max_length=4000)]] = Field(default=None, description="Separate description for a TikTok photo or carousel post. Max 4,000 characters. When omitted, the post content is also used as the description. Photo posts only.")
135
+ draft: Optional[bool] = Field(default=None, description="When true, sends content to the creator's TikTok inbox as a draft. Defaults to false (publishes immediately via DIRECT_POST).")
136
+
137
+
138
+ class PinterestConfigurations(BaseModel):
139
+ """Pass this object in platformSpecificData when posting to Pinterest."""
140
+
141
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
142
+ board_id: str = Field(..., alias="boardId", description="Target board ID. Retrieve available boards via GET /v1/pinterest/boards.")
143
+ title: Optional[Annotated[str, Field(max_length=100)]] = Field(default=None, description="Pin title. Max 100 characters. Defaults to first line of content.")
144
+ link: Optional[AnyUrl] = Field(default=None, description="HTTPS destination URL when the pin is clicked. Important for driving traffic.")
145
+ alt_text: Optional[Annotated[str, Field(max_length=500)]] = Field(default=None, alias="altText", description="Accessible image description. Max 500 characters.")
146
+ dominant_color: Optional[str] = Field(default=None, alias="dominantColor", description='Hex color for the loading placeholder (e.g. "#6E7874").')
147
+ cover_image_url: Optional[AnyUrl] = Field(default=None, alias="coverImageUrl", description="Custom cover image URL for video pins.")
148
+
149
+
150
+ class LinkedInConfigurationsVisibility(str, Enum):
151
+ """Post visibility. "PUBLIC" = visible to everyone, "CONNECTIONS" = visible to connections only. Defaults to "PUBLIC"."""
152
+
153
+ PUBLIC = "PUBLIC"
154
+ CONNECTIONS = "CONNECTIONS"
155
+
156
+
157
+ class LinkedInConfigurations(BaseModel):
158
+ """Pass this object in platformSpecificData when posting to LinkedIn."""
159
+
160
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
161
+ visibility: Optional[LinkedInConfigurationsVisibility] = Field(default=None, description='Post visibility. "PUBLIC" = visible to everyone, "CONNECTIONS" = visible to connections only. Defaults to "PUBLIC".')
162
+ article_url: Optional[AnyUrl] = Field(default=None, alias="articleUrl", description="URL for an article/link post. When provided, the post becomes a link share with a preview card.")
163
+ article_title: Optional[Annotated[str, Field(max_length=400)]] = Field(default=None, alias="articleTitle", description="Title for the article preview card. Max 400 characters.")
164
+ article_description: Optional[Annotated[str, Field(max_length=400)]] = Field(default=None, alias="articleDescription", description="Description for the article preview card. Max 400 characters.")
165
+ document_title: Optional[Annotated[str, Field(max_length=200)]] = Field(default=None, alias="documentTitle", description="Title shown on the document card when posting a PDF. Required by LinkedIn when a document media item is included.")
166
+
167
+
168
+ class BlueskyConfigurations(BaseModel):
169
+ """Pass this object in platformSpecificData when posting to Bluesky."""
170
+
171
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
172
+ langs: Optional[list[str]] = Field(default=None, description='BCP-47 language tags for the post (e.g. ["en"], ["en-US", "es"]). Defaults to ["en"].')
173
+ alt_text: Optional[list[str]] = Field(default=None, alias="altText", description="Alt text for each image, in the same order as mediaItems. Strongly encouraged for accessibility.")
174
+
175
+
176
+ class FacebookConfigurations(BaseModel):
177
+ """Pass this object in platformSpecificData when posting to Facebook Pages."""
178
+
179
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
180
+ link: Optional[AnyUrl] = Field(default=None, description="When provided on a text-only post, Facebook renders a link preview card from this URL's Open Graph tags. Ignored when mediaItems are attached.")
181
+ published: Optional[bool] = Field(default=None, description="When false, the post is created on the Page in unpublished/draft state — useful for staging or scheduling via Facebook's own composer. Defaults to true.")
182
+ video_thumbnail_url: Optional[AnyUrl] = Field(default=None, alias="videoThumbnailUrl", description="Video posts only. Public URL of an image Facebook will use as the video's cover/thumbnail. Applied as a follow-up call after publish — if the upload fails, the post still succeeds (Facebook just auto-picks a frame). Ignored when no video is attached.")
183
+
184
+
185
+ class InstagramConfigurations(BaseModel):
186
+ """Pass this object in platformSpecificData when posting to Instagram Business accounts. All fields are optional and apply to Reels/video posts; image posts ignore them."""
187
+
188
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
189
+ share_to_feed: Optional[bool] = Field(default=None, alias="shareToFeed", description="Reels-only. When true (default), the Reel also appears in the account's main feed grid. Set false to publish to Reels only.")
190
+ cover_url: Optional[AnyUrl] = Field(default=None, alias="coverUrl", description="Video-only. Public URL of an image Instagram will use as the cover frame for the Reel/video post. Ignored for image posts.")
191
+ thumb_offset: Optional[Annotated[int, Field(ge=0)]] = Field(default=None, alias="thumbOffset", description="Video-only. Timestamp in milliseconds Instagram extracts as the cover frame. Ignored when coverUrl is set or for image posts.")
192
+
193
+
194
+ class ThreadsConfigurationsReplyControl(str, Enum):
195
+ """Who can reply to this thread. Defaults to "everyone" when omitted."""
196
+
197
+ EVERYONE = "everyone"
198
+ ACCOUNTS_YOU_FOLLOW = "accounts_you_follow"
199
+ MENTIONED_ONLY = "mentioned_only"
200
+
201
+
202
+ class ThreadsConfigurations(BaseModel):
203
+ """Pass this object in platformSpecificData when posting to Threads."""
204
+
205
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
206
+ reply_control: Optional[ThreadsConfigurationsReplyControl] = Field(default=None, alias="replyControl", description='Who can reply to this thread. Defaults to "everyone" when omitted.')
207
+ alt_text: Optional[list[str]] = Field(default=None, alias="altText", description="Alt text for each image, in the same order as mediaItems. Strongly encouraged for accessibility.")
208
+
209
+
210
+ class GoogleBusinessConfigurationsTopicType(str, Enum):
211
+ """Post type. Defaults to STANDARD. Use EVENT for event posts, OFFER for promotional offer posts."""
212
+
213
+ STANDARD = "STANDARD"
214
+ EVENT = "EVENT"
215
+ OFFER = "OFFER"
216
+
217
+
218
+ class GoogleBusinessConfigurationsCallToActionType(str, Enum):
219
+ """Call-to-action button shown on the post."""
220
+
221
+ BOOK = "BOOK"
222
+ ORDER = "ORDER"
223
+ SHOP = "SHOP"
224
+ LEARN_MORE = "LEARN_MORE"
225
+ SIGN_UP = "SIGN_UP"
226
+ CALL = "CALL"
227
+ GET_OFFER = "GET_OFFER"
228
+
229
+
230
+ class GoogleBusinessConfigurations(BaseModel):
231
+ """Pass this object in platformSpecificData when posting to Google Business Profile. Posts appear on Google Search and Maps."""
232
+
233
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
234
+ topic_type: Optional[GoogleBusinessConfigurationsTopicType] = Field(default=None, alias="topicType", description="Post type. Defaults to STANDARD. Use EVENT for event posts, OFFER for promotional offer posts.")
235
+ call_to_action_type: Optional[GoogleBusinessConfigurationsCallToActionType] = Field(default=None, alias="callToActionType", description="Call-to-action button shown on the post.")
236
+ call_to_action_url: Optional[AnyUrl] = Field(default=None, alias="callToActionUrl", description="URL for the call-to-action. Required for all CTA types except CALL.")
237
+ event_title: Optional[str] = Field(default=None, alias="eventTitle", description="Event title. Required when topicType is EVENT.")
238
+ event_start_date: Optional[str] = Field(default=None, alias="eventStartDate", description="Event start date in YYYY-MM-DD format. Required when topicType is EVENT.")
239
+ event_start_time: Optional[str] = Field(default=None, alias="eventStartTime", description="Event start time in HH:MM (24-hour) format. Required when topicType is EVENT.")
240
+ event_end_date: Optional[str] = Field(default=None, alias="eventEndDate", description="Event end date in YYYY-MM-DD format. Required when topicType is EVENT.")
241
+ event_end_time: Optional[str] = Field(default=None, alias="eventEndTime", description="Event end time in HH:MM (24-hour) format. Required when topicType is EVENT.")
242
+ offer_coupon_code: Optional[str] = Field(default=None, alias="offerCouponCode", description="Coupon code for OFFER posts.")
243
+ offer_redeem_online_url: Optional[AnyUrl] = Field(default=None, alias="offerRedeemOnlineUrl", description="Online redemption URL for OFFER posts.")
244
+ offer_terms_conditions: Optional[str] = Field(default=None, alias="offerTermsConditions", description="Terms and conditions text for OFFER posts.")
245
+
246
+
247
+ class PostPayloadMediaItemsType(str, Enum):
248
+ IMAGE = "image"
249
+ VIDEO = "video"
250
+ GIF = "gif"
251
+ DOCUMENT = "document"
252
+
253
+
254
+ class PostPayloadMediaItems(BaseModel):
255
+ model_config = ConfigDict(extra="forbid")
256
+ type: PostPayloadMediaItemsType
257
+ url: AnyUrl
258
+ thumbnail: Optional[AnyUrl] = Field(default=None, description="Thumbnail image URL for video items. Supported on YouTube regular videos (not Shorts). JPEG, PNG, or GIF, max 2 MB, min 640 px wide.")
259
+
260
+
261
+ class PostPayloadPlatformsPlatform(str, Enum):
262
+ TWITTER = "twitter"
263
+
264
+
265
+ class PostPayloadPlatforms(BaseModel):
266
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
267
+ platform: PostPayloadPlatformsPlatform
268
+ account_id: str = Field(..., alias="accountId", description="Integration._id — find yours via GET /connect/integrations")
269
+ content: Optional[str] = Field(default=None, description="Optional per-platform text override. Use when you want to change the text for this platform because different platforms talk differently. When omitted, the top-level `content` is used.")
270
+ platform_specific_data: Optional[TwitterConfigurations] = Field(default=None, alias="platformSpecificData")
271
+
272
+
273
+ class PostPayloadPlatformsPlatform_(str, Enum):
274
+ INSTAGRAM = "instagram"
275
+
276
+
277
+ class PostPayloadPlatforms_(BaseModel):
278
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
279
+ platform: PostPayloadPlatformsPlatform_
280
+ account_id: str = Field(..., alias="accountId", description="Integration._id — find yours via GET /connect/integrations")
281
+ content: Optional[str] = Field(default=None, description="Optional per-platform text override. Use when you want to change the text for this platform because different platforms talk differently. When omitted, the top-level `content` is used.")
282
+ platform_specific_data: Optional[InstagramConfigurations] = Field(default=None, alias="platformSpecificData")
283
+
284
+
285
+ class PostPayloadPlatformsPlatform_2(str, Enum):
286
+ YOUTUBE = "youtube"
287
+
288
+
289
+ class PostPayloadPlatforms_2(BaseModel):
290
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
291
+ platform: PostPayloadPlatformsPlatform_2
292
+ account_id: str = Field(..., alias="accountId", description="Integration._id — find yours via GET /connect/integrations")
293
+ content: Optional[str] = Field(default=None, description="Optional per-platform text override. Use when you want to change the text for this platform because different platforms talk differently. When omitted, the top-level `content` is used.")
294
+ platform_specific_data: Optional[YouTubeConfigurations] = Field(default=None, alias="platformSpecificData")
295
+
296
+
297
+ class PostPayloadPlatformsPlatform_3(str, Enum):
298
+ TIKTOK = "tiktok"
299
+
300
+
301
+ class PostPayloadPlatforms_3(BaseModel):
302
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
303
+ platform: PostPayloadPlatformsPlatform_3
304
+ account_id: str = Field(..., alias="accountId", description="Integration._id — find yours via GET /connect/integrations")
305
+ content: Optional[str] = Field(default=None, description="Optional per-platform text override. Use when you want to change the text for this platform because different platforms talk differently. When omitted, the top-level `content` is used.")
306
+ platform_specific_data: Optional[TikTokConfigurations] = Field(default=None, alias="platformSpecificData")
307
+
308
+
309
+ class PostPayloadPlatformsPlatform_4(str, Enum):
310
+ PINTEREST = "pinterest"
311
+
312
+
313
+ class PostPayloadPlatforms_4(BaseModel):
314
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
315
+ platform: PostPayloadPlatformsPlatform_4
316
+ account_id: str = Field(..., alias="accountId", description="Integration._id — find yours via GET /connect/integrations")
317
+ content: Optional[str] = Field(default=None, description="Optional per-platform text override. Use when you want to change the text for this platform because different platforms talk differently. When omitted, the top-level `content` is used.")
318
+ platform_specific_data: Optional[PinterestConfigurations] = Field(default=None, alias="platformSpecificData")
319
+
320
+
321
+ class PostPayloadPlatformsPlatform_5(str, Enum):
322
+ LINKEDIN = "linkedin"
323
+
324
+
325
+ class PostPayloadPlatforms_5(BaseModel):
326
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
327
+ platform: PostPayloadPlatformsPlatform_5
328
+ account_id: str = Field(..., alias="accountId", description="Integration._id — find yours via GET /connect/integrations")
329
+ content: Optional[str] = Field(default=None, description="Optional per-platform text override. Use when you want to change the text for this platform because different platforms talk differently. When omitted, the top-level `content` is used.")
330
+ platform_specific_data: Optional[LinkedInConfigurations] = Field(default=None, alias="platformSpecificData")
331
+
332
+
333
+ class PostPayloadPlatformsPlatform_6(str, Enum):
334
+ BLUESKY = "bluesky"
335
+
336
+
337
+ class PostPayloadPlatforms_6(BaseModel):
338
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
339
+ platform: PostPayloadPlatformsPlatform_6
340
+ account_id: str = Field(..., alias="accountId", description="Integration._id — find yours via GET /connect/integrations")
341
+ content: Optional[str] = Field(default=None, description="Optional per-platform text override. Use when you want to change the text for this platform because different platforms talk differently. When omitted, the top-level `content` is used.")
342
+ platform_specific_data: Optional[BlueskyConfigurations] = Field(default=None, alias="platformSpecificData")
343
+
344
+
345
+ class PostPayloadPlatformsPlatform_7(str, Enum):
346
+ FACEBOOK = "facebook"
347
+
348
+
349
+ class PostPayloadPlatforms_7(BaseModel):
350
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
351
+ platform: PostPayloadPlatformsPlatform_7
352
+ account_id: str = Field(..., alias="accountId", description="Integration._id — find yours via GET /connect/integrations")
353
+ content: Optional[str] = Field(default=None, description="Optional per-platform text override. Use when you want to change the text for this platform because different platforms talk differently. When omitted, the top-level `content` is used.")
354
+ platform_specific_data: Optional[FacebookConfigurations] = Field(default=None, alias="platformSpecificData")
355
+
356
+
357
+ class PostPayloadPlatformsPlatform_8(str, Enum):
358
+ THREADS = "threads"
359
+
360
+
361
+ class PostPayloadPlatforms_8(BaseModel):
362
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
363
+ platform: PostPayloadPlatformsPlatform_8
364
+ account_id: str = Field(..., alias="accountId", description="Integration._id — find yours via GET /connect/integrations")
365
+ content: Optional[str] = Field(default=None, description="Optional per-platform text override. Use when you want to change the text for this platform because different platforms talk differently. When omitted, the top-level `content` is used.")
366
+ platform_specific_data: Optional[ThreadsConfigurations] = Field(default=None, alias="platformSpecificData")
367
+
368
+
369
+ class PostPayloadPlatformsPlatform_9(str, Enum):
370
+ GOOGLEBUSINESS = "googlebusiness"
371
+
372
+
373
+ class PostPayloadPlatforms_9(BaseModel):
374
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
375
+ platform: PostPayloadPlatformsPlatform_9
376
+ account_id: str = Field(..., alias="accountId", description="Integration._id — find yours via GET /connect/integrations")
377
+ content: Optional[str] = Field(default=None, description="Optional per-platform text override. Use when you want to change the text for this platform because different platforms talk differently. When omitted, the top-level `content` is used.")
378
+ platform_specific_data: Optional[GoogleBusinessConfigurations] = Field(default=None, alias="platformSpecificData")
379
+
380
+
381
+ class PostPayload(BaseModel):
382
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
383
+ content: str = Field(..., description="Post text body")
384
+ media_items: Optional[list[PostPayloadMediaItems]] = Field(default=None, alias="mediaItems", description="Media attachments (images, videos, GIFs)")
385
+ platforms: Annotated[list[Union[PostPayloadPlatforms, PostPayloadPlatforms_, PostPayloadPlatforms_2, PostPayloadPlatforms_3, PostPayloadPlatforms_4, PostPayloadPlatforms_5, PostPayloadPlatforms_6, PostPayloadPlatforms_7, PostPayloadPlatforms_8, PostPayloadPlatforms_9]], Field(min_length=1)] = Field(..., description="Target platform accounts to publish to")
386
+ publish_now: Optional[bool] = Field(default=None, alias="publishNow", description="Publish immediately. Required when scheduledFor is omitted.")
387
+ scheduled_for: Optional[datetime] = Field(default=None, alias="scheduledFor", description="ISO 8601 datetime to schedule the post for future publishing")
388
+ timezone: Optional[str] = Field(default=None, description="IANA timezone for the scheduled time (e.g. America/New_York). Defaults to UTC.")
389
+
390
+
391
+ class HealthCheckResponse(BaseModel):
392
+ """Default Response"""
393
+
394
+ ok: bool
395
+
396
+
397
+ class HealthCheckAuthResponse(BaseModel):
398
+ """Default Response"""
399
+
400
+ ok: bool
401
+
402
+
403
+ class GetLinkedInSelectionPath(BaseModel):
404
+ token: Annotated[str, Field(min_length=1)]
405
+
406
+
407
+ class GetLinkedInSelectionPlatform(str, Enum):
408
+ LINKEDIN = "linkedin"
409
+
410
+
411
+ class GetLinkedInSelectionAccountsType(str, Enum):
412
+ PERSON = "person"
413
+
414
+
415
+ class GetLinkedInSelectionAccountsType_(str, Enum):
416
+ ORGANIZATION = "organization"
417
+
418
+
419
+ class GetLinkedInSelectionAccounts(BaseModel):
420
+ id: str
421
+ type: Union[GetLinkedInSelectionAccountsType, GetLinkedInSelectionAccountsType_]
422
+ platform_user_id: str = Field(..., alias="platformUserId")
423
+ display_name: Optional[str] = Field(default=None, alias="displayName")
424
+ username: Optional[str] = None
425
+ image_url: Optional[AnyUrl] = Field(default=None, alias="imageUrl")
426
+
427
+
428
+ class GetLinkedInSelectionResponse(BaseModel):
429
+ """Default Response"""
430
+
431
+ success: bool
432
+ platform: GetLinkedInSelectionPlatform
433
+ expires_in_seconds: float = Field(..., alias="expiresInSeconds")
434
+ accounts: list[GetLinkedInSelectionAccounts]
435
+
436
+
437
+ class SubmitLinkedInSelectionBody(BaseModel):
438
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
439
+ selected_account_ids: Annotated[list[str], Field(min_length=1)] = Field(..., alias="selectedAccountIds")
440
+
441
+
442
+ class SubmitLinkedInSelectionPath(BaseModel):
443
+ token: Annotated[str, Field(min_length=1)]
444
+
445
+
446
+ class SubmitLinkedInSelectionPlatform(str, Enum):
447
+ LINKEDIN = "linkedin"
448
+
449
+
450
+ class SubmitLinkedInSelectionIntegrationsPlatform(str, Enum):
451
+ TWITTER = "twitter"
452
+ INSTAGRAM = "instagram"
453
+ YOUTUBE = "youtube"
454
+ TIKTOK = "tiktok"
455
+ PINTEREST = "pinterest"
456
+ LINKEDIN = "linkedin"
457
+ BLUESKY = "bluesky"
458
+ FACEBOOK = "facebook"
459
+ THREADS = "threads"
460
+ GOOGLEBUSINESS = "googlebusiness"
461
+
462
+
463
+ class SubmitLinkedInSelectionIntegrationsApp(BaseModel):
464
+ id: Optional[str] = None
465
+ name: Optional[str] = None
466
+ image_url: Optional[str] = Field(default=None, alias="imageUrl")
467
+
468
+
469
+ class SubmitLinkedInSelectionIntegrations(BaseModel):
470
+ id: str = Field(..., description="Use this as accountId when creating posts")
471
+ platform: SubmitLinkedInSelectionIntegrationsPlatform
472
+ platform_user_id: Optional[str] = Field(default=None, alias="platformUserId", description="The user ID on the platform, or null if not yet retrieved")
473
+ username: Optional[str] = Field(default=None, description="The public username or handle, including @ for handle-based platforms")
474
+ display_name: Optional[str] = Field(default=None, alias="displayName", description="Human-readable display name of the connected account")
475
+ profile_url: Optional[AnyUrl] = Field(default=None, alias="profileUrl", description="Public profile/page URL for the connected account, when it can be derived")
476
+ image_url: Optional[AnyUrl] = Field(default=None, alias="imageUrl", description="Profile image URL for the connected account, or null if unavailable")
477
+ platform_metadata: Optional[dict[str, Any]] = Field(default=None, alias="platformMetadata", description="Provider-specific public metadata for this connected account.")
478
+ profile_id: Optional[str] = Field(default=None, alias="profileId", description="Profile this integration belongs to, or null if it was connected without a profile")
479
+ app_id: Optional[str] = Field(default=None, alias="appId", description="The OAuth app (customer's own OAuth app) this integration was connected under, or null if postpeer's system app was used.")
480
+ app: Optional[SubmitLinkedInSelectionIntegrationsApp] = Field(default=None, description="The OAuth app metadata for BYOK integrations, or null when postpeer system app was used.")
481
+ byok: bool = Field(..., description="True when this integration was connected under the customer's own OAuth app (Bring Your Own Keys), i.e. appId is set. False when postpeer's system app is used.")
482
+ created_at: datetime = Field(..., alias="createdAt")
483
+
484
+
485
+ class SubmitLinkedInSelectionResponse(BaseModel):
486
+ """Default Response"""
487
+
488
+ success: bool
489
+ platform: SubmitLinkedInSelectionPlatform
490
+ message: str
491
+ redirect_uri: Optional[str] = Field(default=None, alias="redirectUri")
492
+ integrations: list[SubmitLinkedInSelectionIntegrations]
493
+
494
+
495
+ class GetOAuthUrlPlatform(str, Enum):
496
+ TWITTER = "twitter"
497
+ INSTAGRAM = "instagram"
498
+ YOUTUBE = "youtube"
499
+ TIKTOK = "tiktok"
500
+ PINTEREST = "pinterest"
501
+ LINKEDIN = "linkedin"
502
+ BLUESKY = "bluesky"
503
+ FACEBOOK = "facebook"
504
+ THREADS = "threads"
505
+ GOOGLEBUSINESS = "googlebusiness"
506
+
507
+
508
+ class GetOAuthUrlPath(BaseModel):
509
+ platform: GetOAuthUrlPlatform
510
+
511
+
512
+ class GetOAuthUrlQuery(BaseModel):
513
+ redirect_uri: Optional[AnyUrl] = Field(default=None, alias="redirectUri", description="Final URL to redirect to after the connection completes. In headless mode, this URL also receives selection status query parameters when customer-owned account selection is required.")
514
+ cancel_redirect_uri: Optional[AnyUrl] = Field(default=None, alias="cancelRedirectUri", description="URL to redirect to when the user cancels or denies the OAuth prompt. Falls back to redirectUri when omitted.")
515
+ headless: Optional[bool] = Field(default=False, description="When true, platforms that require account selection redirect back to redirectUri with a short-lived selectionToken so you can build your own selection UI. When false, PostPeer hosts the selection UI.")
516
+ profile_id: Optional[str] = Field(default=None, alias="profileId", description="Profile to associate the resulting integration with. Must belong to the same project. Omit to connect without a profile.")
517
+ app_id: Optional[str] = Field(default=None, alias="appId", description="Connect under your own OAuth app (Bring Your Own Keys). Pass the id of an OAuth app created via /v1/apps for this same platform. Omit to use postpeer's system app.")
518
+
519
+
520
+ class GetOAuthUrlResponse(BaseModel):
521
+ """Default Response"""
522
+
523
+ url: str
524
+
525
+
526
+ class ConnectBlueskyBody(BaseModel):
527
+ model_config = ConfigDict(extra="forbid")
528
+ identifier: str = Field(..., description='Bluesky handle (e.g. "alice.bsky.social") or DID (e.g. "did:plc:abc123").')
529
+ password: str = Field(..., description="An app password generated at https://bsky.app/settings/app-passwords. Do NOT use the account password.")
530
+
531
+
532
+ class ConnectBlueskyQuery(BaseModel):
533
+ redirect_uri: Optional[AnyUrl] = Field(default=None, alias="redirectUri", description="Final URL to redirect to after the connection completes. In headless mode, this URL also receives selection status query parameters when customer-owned account selection is required.")
534
+ cancel_redirect_uri: Optional[AnyUrl] = Field(default=None, alias="cancelRedirectUri", description="URL to redirect to when the user cancels or denies the OAuth prompt. Falls back to redirectUri when omitted.")
535
+ headless: Optional[bool] = Field(default=False, description="When true, platforms that require account selection redirect back to redirectUri with a short-lived selectionToken so you can build your own selection UI. When false, PostPeer hosts the selection UI.")
536
+ profile_id: Optional[str] = Field(default=None, alias="profileId", description="Profile to associate the resulting integration with. Must belong to the same project. Omit to connect without a profile.")
537
+ app_id: Optional[str] = Field(default=None, alias="appId", description="Connect under your own OAuth app (Bring Your Own Keys). Pass the id of an OAuth app created via /v1/apps for this same platform. Omit to use postpeer's system app.")
538
+
539
+
540
+ class ListIntegrationsPlatform(str, Enum):
541
+ TWITTER = "twitter"
542
+ INSTAGRAM = "instagram"
543
+ YOUTUBE = "youtube"
544
+ TIKTOK = "tiktok"
545
+ PINTEREST = "pinterest"
546
+ LINKEDIN = "linkedin"
547
+ BLUESKY = "bluesky"
548
+ FACEBOOK = "facebook"
549
+ THREADS = "threads"
550
+ GOOGLEBUSINESS = "googlebusiness"
551
+
552
+
553
+ class ListIntegrationsQuery(BaseModel):
554
+ platform: Optional[ListIntegrationsPlatform] = None
555
+ profile_id: Optional[str] = Field(default=None, alias="profileId", description='Filter to integrations belonging to this profile. Pass "null" (literal string) to filter to integrations with no profile.')
556
+ q: Optional[str] = Field(default=None, description="Case-insensitive search across the connected account name (displayName), username, and platform user ID.")
557
+ limit: Optional[Annotated[int, Field(ge=1, le=100)]] = Field(default=20, description="Page size (max 100)")
558
+ offset: Optional[Annotated[int, Field(ge=0)]] = Field(default=0, description="Number of integrations to skip")
559
+ sort: Optional[SortOrder] = None
560
+
561
+
562
+ class ListIntegrationsIntegrationsPlatform(str, Enum):
563
+ TWITTER = "twitter"
564
+ INSTAGRAM = "instagram"
565
+ YOUTUBE = "youtube"
566
+ TIKTOK = "tiktok"
567
+ PINTEREST = "pinterest"
568
+ LINKEDIN = "linkedin"
569
+ BLUESKY = "bluesky"
570
+ FACEBOOK = "facebook"
571
+ THREADS = "threads"
572
+ GOOGLEBUSINESS = "googlebusiness"
573
+
574
+
575
+ class ListIntegrationsIntegrationsApp(BaseModel):
576
+ id: Optional[str] = None
577
+ name: Optional[str] = None
578
+ image_url: Optional[str] = Field(default=None, alias="imageUrl")
579
+
580
+
581
+ class ListIntegrationsIntegrations(BaseModel):
582
+ id: str = Field(..., description="Use this as accountId when creating posts")
583
+ platform: ListIntegrationsIntegrationsPlatform
584
+ platform_user_id: Optional[str] = Field(default=None, alias="platformUserId", description="The user ID on the platform, or null if not yet retrieved")
585
+ username: Optional[str] = Field(default=None, description="The public username or handle, including @ for handle-based platforms")
586
+ display_name: Optional[str] = Field(default=None, alias="displayName", description="Human-readable display name of the connected account")
587
+ profile_url: Optional[AnyUrl] = Field(default=None, alias="profileUrl", description="Public profile/page URL for the connected account, when it can be derived")
588
+ image_url: Optional[AnyUrl] = Field(default=None, alias="imageUrl", description="Profile image URL for the connected account, or null if unavailable")
589
+ platform_metadata: Optional[dict[str, Any]] = Field(default=None, alias="platformMetadata", description="Provider-specific public metadata for this connected account.")
590
+ profile_id: Optional[str] = Field(default=None, alias="profileId", description="Profile this integration belongs to, or null if it was connected without a profile")
591
+ app_id: Optional[str] = Field(default=None, alias="appId", description="The OAuth app (customer's own OAuth app) this integration was connected under, or null if postpeer's system app was used.")
592
+ app: Optional[ListIntegrationsIntegrationsApp] = Field(default=None, description="The OAuth app metadata for BYOK integrations, or null when postpeer system app was used.")
593
+ byok: bool = Field(..., description="True when this integration was connected under the customer's own OAuth app (Bring Your Own Keys), i.e. appId is set. False when postpeer's system app is used.")
594
+ created_at: datetime = Field(..., alias="createdAt")
595
+
596
+
597
+ class ListIntegrationsResponse(BaseModel):
598
+ """Default Response"""
599
+
600
+ success: bool
601
+ total: Annotated[int, Field(ge=0)] = Field(..., description="Total matched integrations across all pages")
602
+ integrations: list[ListIntegrationsIntegrations]
603
+
604
+
605
+ class DisconnectIntegrationPath(BaseModel):
606
+ id: str = Field(..., description="Integration ID to disconnect")
607
+
608
+
609
+ class DisconnectIntegrationResponse(BaseModel):
610
+ """Default Response"""
611
+
612
+ success: bool
613
+ message: str
614
+
615
+
616
+ class ListProfilesQuery(BaseModel):
617
+ page: Optional[Annotated[int, Field(ge=1)]] = 1
618
+ limit: Optional[Annotated[int, Field(ge=1, le=100)]] = 50
619
+ name: Optional[Annotated[str, Field(min_length=1, max_length=200)]] = Field(default=None, description="Case-insensitive substring match on profile name")
620
+
621
+
622
+ class ListProfilesProfiles(BaseModel):
623
+ id: str
624
+ name: str
625
+ description: Optional[str] = None
626
+ integration_count: Annotated[int, Field(ge=0)] = Field(..., alias="integrationCount", description="Number of active integrations bound to this profile")
627
+ created_at: datetime = Field(..., alias="createdAt")
628
+ updated_at: datetime = Field(..., alias="updatedAt")
629
+
630
+
631
+ class ListProfilesResponse(BaseModel):
632
+ """Default Response"""
633
+
634
+ success: bool
635
+ total: Annotated[int, Field(ge=0)]
636
+ page: Annotated[int, Field(ge=1)]
637
+ limit: Annotated[int, Field(ge=1)]
638
+ profiles: list[ListProfilesProfiles]
639
+
640
+
641
+ class CreateProfileBody(BaseModel):
642
+ name: Annotated[str, Field(min_length=1, max_length=200)] = Field(..., description='Profile name (e.g. "Acme Co", "Personal Brand")')
643
+ description: Optional[Annotated[str, Field(max_length=1000)]] = Field(default=None, description="Optional description of what this profile is for")
644
+
645
+
646
+ class CreateProfileProfile(BaseModel):
647
+ id: str
648
+ name: str
649
+ description: Optional[str] = None
650
+ integration_count: Annotated[int, Field(ge=0)] = Field(..., alias="integrationCount", description="Number of active integrations bound to this profile")
651
+ created_at: datetime = Field(..., alias="createdAt")
652
+ updated_at: datetime = Field(..., alias="updatedAt")
653
+
654
+
655
+ class CreateProfileResponse(BaseModel):
656
+ """Default Response"""
657
+
658
+ success: bool
659
+ profile: CreateProfileProfile
660
+
661
+
662
+ class DeleteProfilePath(BaseModel):
663
+ id: str = Field(..., description="Profile ID")
664
+
665
+
666
+ class DeleteProfileResponse(BaseModel):
667
+ """Default Response"""
668
+
669
+ success: bool
670
+ message: str
671
+
672
+
673
+ class GetProfilePath(BaseModel):
674
+ id: str = Field(..., description="Profile ID")
675
+
676
+
677
+ class GetProfileProfile(BaseModel):
678
+ id: str
679
+ name: str
680
+ description: Optional[str] = None
681
+ integration_count: Annotated[int, Field(ge=0)] = Field(..., alias="integrationCount", description="Number of active integrations bound to this profile")
682
+ created_at: datetime = Field(..., alias="createdAt")
683
+ updated_at: datetime = Field(..., alias="updatedAt")
684
+
685
+
686
+ class GetProfileResponse(BaseModel):
687
+ """Default Response"""
688
+
689
+ success: bool
690
+ profile: GetProfileProfile
691
+
692
+
693
+ class UpdateProfileBody(BaseModel):
694
+ name: Optional[Annotated[str, Field(min_length=1, max_length=200)]] = None
695
+ description: Optional[Annotated[str, Field(max_length=1000)]] = None
696
+
697
+
698
+ class UpdateProfilePath(BaseModel):
699
+ id: str = Field(..., description="Profile ID")
700
+
701
+
702
+ class UpdateProfileProfile(BaseModel):
703
+ id: str
704
+ name: str
705
+ description: Optional[str] = None
706
+ integration_count: Annotated[int, Field(ge=0)] = Field(..., alias="integrationCount", description="Number of active integrations bound to this profile")
707
+ created_at: datetime = Field(..., alias="createdAt")
708
+ updated_at: datetime = Field(..., alias="updatedAt")
709
+
710
+
711
+ class UpdateProfileResponse(BaseModel):
712
+ """Default Response"""
713
+
714
+ success: bool
715
+ profile: UpdateProfileProfile
716
+
717
+
718
+ class ListAppsPlatform(str, Enum):
719
+ TWITTER = "twitter"
720
+ INSTAGRAM = "instagram"
721
+ YOUTUBE = "youtube"
722
+ TIKTOK = "tiktok"
723
+ PINTEREST = "pinterest"
724
+ LINKEDIN = "linkedin"
725
+ BLUESKY = "bluesky"
726
+ FACEBOOK = "facebook"
727
+ THREADS = "threads"
728
+ GOOGLEBUSINESS = "googlebusiness"
729
+
730
+
731
+ class ListAppsQuery(BaseModel):
732
+ platform: Optional[ListAppsPlatform] = None
733
+ page: Optional[Annotated[int, Field(ge=1)]] = 1
734
+ limit: Optional[Annotated[int, Field(ge=1, le=100)]] = 50
735
+ name: Optional[Annotated[str, Field(min_length=1, max_length=200)]] = Field(default=None, description="Case-insensitive substring match on app name")
736
+
737
+
738
+ class ListAppsAppsPlatform(str, Enum):
739
+ TWITTER = "twitter"
740
+ INSTAGRAM = "instagram"
741
+ YOUTUBE = "youtube"
742
+ TIKTOK = "tiktok"
743
+ PINTEREST = "pinterest"
744
+ LINKEDIN = "linkedin"
745
+ BLUESKY = "bluesky"
746
+ FACEBOOK = "facebook"
747
+ THREADS = "threads"
748
+ GOOGLEBUSINESS = "googlebusiness"
749
+
750
+
751
+ class ListAppsApps(BaseModel):
752
+ id: str = Field(..., description="Pass this as appId when connecting")
753
+ platform: ListAppsAppsPlatform
754
+ name: str
755
+ image_url: Optional[str] = Field(default=None, alias="imageUrl")
756
+ client_id: str = Field(..., alias="clientId", description="The OAuth app client id. The client secret is never returned.")
757
+ integration_count: Annotated[int, Field(ge=0)] = Field(..., alias="integrationCount", description="Number of active integrations connected under this app")
758
+ created_at: datetime = Field(..., alias="createdAt")
759
+ updated_at: datetime = Field(..., alias="updatedAt")
760
+
761
+
762
+ class ListAppsResponse(BaseModel):
763
+ """Default Response"""
764
+
765
+ success: bool
766
+ total: Annotated[int, Field(ge=0)]
767
+ page: Annotated[int, Field(ge=1)]
768
+ limit: Annotated[int, Field(ge=1)]
769
+ apps: list[ListAppsApps]
770
+
771
+
772
+ class CreateAppPlatform(str, Enum):
773
+ TWITTER = "twitter"
774
+ INSTAGRAM = "instagram"
775
+ YOUTUBE = "youtube"
776
+ TIKTOK = "tiktok"
777
+ PINTEREST = "pinterest"
778
+ LINKEDIN = "linkedin"
779
+ BLUESKY = "bluesky"
780
+ FACEBOOK = "facebook"
781
+ THREADS = "threads"
782
+ GOOGLEBUSINESS = "googlebusiness"
783
+
784
+
785
+ class CreateAppBody(BaseModel):
786
+ platform: CreateAppPlatform
787
+ name: Annotated[str, Field(min_length=1, max_length=200)] = Field(..., description='A label for this app (e.g. "Acme Twitter OAuth App")')
788
+ client_id: Annotated[str, Field(min_length=1)] = Field(..., alias="clientId", description="The client id of your OAuth app for this platform")
789
+ client_secret: Annotated[str, Field(min_length=1)] = Field(..., alias="clientSecret", description="The client secret of your OAuth app. Stored encrypted.")
790
+ image_url: Optional[AnyUrl] = Field(default=None, alias="imageUrl", description="Optional icon URL for the app")
791
+
792
+
793
+ class CreateAppAppPlatform(str, Enum):
794
+ TWITTER = "twitter"
795
+ INSTAGRAM = "instagram"
796
+ YOUTUBE = "youtube"
797
+ TIKTOK = "tiktok"
798
+ PINTEREST = "pinterest"
799
+ LINKEDIN = "linkedin"
800
+ BLUESKY = "bluesky"
801
+ FACEBOOK = "facebook"
802
+ THREADS = "threads"
803
+ GOOGLEBUSINESS = "googlebusiness"
804
+
805
+
806
+ class CreateAppApp(BaseModel):
807
+ id: str = Field(..., description="Pass this as appId when connecting")
808
+ platform: CreateAppAppPlatform
809
+ name: str
810
+ image_url: Optional[str] = Field(default=None, alias="imageUrl")
811
+ client_id: str = Field(..., alias="clientId", description="The OAuth app client id. The client secret is never returned.")
812
+ integration_count: Annotated[int, Field(ge=0)] = Field(..., alias="integrationCount", description="Number of active integrations connected under this app")
813
+ created_at: datetime = Field(..., alias="createdAt")
814
+ updated_at: datetime = Field(..., alias="updatedAt")
815
+
816
+
817
+ class CreateAppResponse(BaseModel):
818
+ """Default Response"""
819
+
820
+ success: bool
821
+ app: CreateAppApp
822
+
823
+
824
+ class DeleteAppPath(BaseModel):
825
+ id: str = Field(..., description="OAuth app ID")
826
+
827
+
828
+ class DeleteAppResponse(BaseModel):
829
+ """Default Response"""
830
+
831
+ success: bool
832
+ message: str
833
+
834
+
835
+ class GetAppPath(BaseModel):
836
+ id: str = Field(..., description="OAuth app ID")
837
+
838
+
839
+ class GetAppAppPlatform(str, Enum):
840
+ TWITTER = "twitter"
841
+ INSTAGRAM = "instagram"
842
+ YOUTUBE = "youtube"
843
+ TIKTOK = "tiktok"
844
+ PINTEREST = "pinterest"
845
+ LINKEDIN = "linkedin"
846
+ BLUESKY = "bluesky"
847
+ FACEBOOK = "facebook"
848
+ THREADS = "threads"
849
+ GOOGLEBUSINESS = "googlebusiness"
850
+
851
+
852
+ class GetAppApp(BaseModel):
853
+ id: str = Field(..., description="Pass this as appId when connecting")
854
+ platform: GetAppAppPlatform
855
+ name: str
856
+ image_url: Optional[str] = Field(default=None, alias="imageUrl")
857
+ client_id: str = Field(..., alias="clientId", description="The OAuth app client id. The client secret is never returned.")
858
+ integration_count: Annotated[int, Field(ge=0)] = Field(..., alias="integrationCount", description="Number of active integrations connected under this app")
859
+ created_at: datetime = Field(..., alias="createdAt")
860
+ updated_at: datetime = Field(..., alias="updatedAt")
861
+
862
+
863
+ class GetAppResponse(BaseModel):
864
+ """Default Response"""
865
+
866
+ success: bool
867
+ app: GetAppApp
868
+
869
+
870
+ class UpdateAppBody(BaseModel):
871
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
872
+ name: Optional[Annotated[str, Field(min_length=1, max_length=200)]] = None
873
+ image_url: Optional[str] = Field(default=None, alias="imageUrl")
874
+ client_secret: Optional[Annotated[str, Field(min_length=1)]] = Field(default=None, alias="clientSecret", description="Rotate the stored client secret. The clientId stays the same so existing tokens keep working — to switch to a different app, create a new OAuth app and reconnect.")
875
+
876
+
877
+ class UpdateAppPath(BaseModel):
878
+ id: str = Field(..., description="OAuth app ID")
879
+
880
+
881
+ class UpdateAppAppPlatform(str, Enum):
882
+ TWITTER = "twitter"
883
+ INSTAGRAM = "instagram"
884
+ YOUTUBE = "youtube"
885
+ TIKTOK = "tiktok"
886
+ PINTEREST = "pinterest"
887
+ LINKEDIN = "linkedin"
888
+ BLUESKY = "bluesky"
889
+ FACEBOOK = "facebook"
890
+ THREADS = "threads"
891
+ GOOGLEBUSINESS = "googlebusiness"
892
+
893
+
894
+ class UpdateAppApp(BaseModel):
895
+ id: str = Field(..., description="Pass this as appId when connecting")
896
+ platform: UpdateAppAppPlatform
897
+ name: str
898
+ image_url: Optional[str] = Field(default=None, alias="imageUrl")
899
+ client_id: str = Field(..., alias="clientId", description="The OAuth app client id. The client secret is never returned.")
900
+ integration_count: Annotated[int, Field(ge=0)] = Field(..., alias="integrationCount", description="Number of active integrations connected under this app")
901
+ created_at: datetime = Field(..., alias="createdAt")
902
+ updated_at: datetime = Field(..., alias="updatedAt")
903
+
904
+
905
+ class UpdateAppResponse(BaseModel):
906
+ """Default Response"""
907
+
908
+ success: bool
909
+ app: UpdateAppApp
910
+
911
+
912
+ class TestNotificationChannel(str, Enum):
913
+ WEBHOOK = "webhook"
914
+ EMAIL = "email"
915
+
916
+
917
+ class TestNotificationWebhook(BaseModel):
918
+ model_config = ConfigDict(extra="forbid")
919
+ url: AnyUrl = Field(..., description="HTTPS endpoint that receives PostPeer JSON payloads")
920
+
921
+
922
+ class TestNotificationEmail(BaseModel):
923
+ model_config = ConfigDict(extra="forbid")
924
+ recipients: Annotated[list[EmailStr], Field(min_length=1, max_length=10)]
925
+
926
+
927
+ class TestNotificationBody(BaseModel):
928
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
929
+ channel: TestNotificationChannel
930
+ profile_id: Optional[str] = Field(default=None, alias="profileId")
931
+ webhook: Optional[TestNotificationWebhook] = None
932
+ email: Optional[TestNotificationEmail] = None
933
+
934
+
935
+ class TestNotificationResponse(BaseModel):
936
+ """Default Response"""
937
+
938
+ success: bool
939
+ message: str
940
+
941
+
942
+ class ListNotificationsNotificationsChannel(str, Enum):
943
+ WEBHOOK = "webhook"
944
+ EMAIL = "email"
945
+
946
+
947
+ class ListNotificationsNotificationsEventTypes(str, Enum):
948
+ POST_SCHEDULED = "post.scheduled"
949
+ POST_PUBLISHED = "post.published"
950
+ POST_PARTIAL = "post.partial"
951
+ POST_FAILED = "post.failed"
952
+
953
+
954
+ class ListNotificationsNotificationsWebhook(BaseModel):
955
+ model_config = ConfigDict(extra="forbid")
956
+ url: AnyUrl
957
+ secret: str = Field(..., description="Webhook signing secret (masked in list responses)")
958
+
959
+
960
+ class ListNotificationsNotificationsEmail(BaseModel):
961
+ model_config = ConfigDict(extra="forbid")
962
+ recipients: Annotated[list[EmailStr], Field(min_length=1, max_length=10)]
963
+
964
+
965
+ class ListNotificationsNotifications(BaseModel):
966
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
967
+ id: str
968
+ channel: ListNotificationsNotificationsChannel
969
+ profile_id: Optional[str] = Field(default=None, alias="profileId")
970
+ event_types: list[ListNotificationsNotificationsEventTypes] = Field(..., alias="eventTypes")
971
+ only_scheduled_posts: bool = Field(..., alias="onlyScheduledPosts")
972
+ enabled: bool
973
+ webhook: Optional[ListNotificationsNotificationsWebhook] = None
974
+ email: Optional[ListNotificationsNotificationsEmail] = None
975
+ last_test_at: Optional[datetime] = Field(default=None, alias="lastTestAt")
976
+ last_test_status: Optional[str] = Field(default=None, alias="lastTestStatus")
977
+ created_at: datetime = Field(..., alias="createdAt")
978
+ updated_at: datetime = Field(..., alias="updatedAt")
979
+
980
+
981
+ class ListNotificationsResponse(BaseModel):
982
+ """Default Response"""
983
+
984
+ success: bool
985
+ notifications: list[ListNotificationsNotifications]
986
+
987
+
988
+ class CreateNotificationChannel(str, Enum):
989
+ WEBHOOK = "webhook"
990
+ EMAIL = "email"
991
+
992
+
993
+ class CreateNotificationEventTypes(str, Enum):
994
+ POST_SCHEDULED = "post.scheduled"
995
+ POST_PUBLISHED = "post.published"
996
+ POST_PARTIAL = "post.partial"
997
+ POST_FAILED = "post.failed"
998
+
999
+
1000
+ class CreateNotificationWebhook(BaseModel):
1001
+ model_config = ConfigDict(extra="forbid")
1002
+ url: AnyUrl = Field(..., description="HTTPS endpoint that receives PostPeer JSON payloads")
1003
+
1004
+
1005
+ class CreateNotificationEmail(BaseModel):
1006
+ model_config = ConfigDict(extra="forbid")
1007
+ recipients: Annotated[list[EmailStr], Field(min_length=1, max_length=10)]
1008
+
1009
+
1010
+ class CreateNotificationBody(BaseModel):
1011
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
1012
+ channel: CreateNotificationChannel
1013
+ profile_id: Optional[str] = Field(default=None, alias="profileId")
1014
+ event_types: Annotated[list[CreateNotificationEventTypes], Field(min_length=1)] = Field(..., alias="eventTypes")
1015
+ only_scheduled_posts: Optional[bool] = Field(default=False, alias="onlyScheduledPosts", description="When true, deliver matching notifications only for posts that were scheduled.")
1016
+ enabled: Optional[bool] = True
1017
+ webhook: Optional[CreateNotificationWebhook] = None
1018
+ email: Optional[CreateNotificationEmail] = None
1019
+
1020
+
1021
+ class CreateNotificationNotificationChannel(str, Enum):
1022
+ WEBHOOK = "webhook"
1023
+ EMAIL = "email"
1024
+
1025
+
1026
+ class CreateNotificationNotificationEventTypes(str, Enum):
1027
+ POST_SCHEDULED = "post.scheduled"
1028
+ POST_PUBLISHED = "post.published"
1029
+ POST_PARTIAL = "post.partial"
1030
+ POST_FAILED = "post.failed"
1031
+
1032
+
1033
+ class CreateNotificationNotificationWebhook(BaseModel):
1034
+ model_config = ConfigDict(extra="forbid")
1035
+ url: AnyUrl
1036
+ secret: str = Field(..., description="Webhook signing secret (masked in list responses)")
1037
+
1038
+
1039
+ class CreateNotificationNotificationEmail(BaseModel):
1040
+ model_config = ConfigDict(extra="forbid")
1041
+ recipients: Annotated[list[EmailStr], Field(min_length=1, max_length=10)]
1042
+
1043
+
1044
+ class CreateNotificationNotification(BaseModel):
1045
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
1046
+ id: str
1047
+ channel: CreateNotificationNotificationChannel
1048
+ profile_id: Optional[str] = Field(default=None, alias="profileId")
1049
+ event_types: list[CreateNotificationNotificationEventTypes] = Field(..., alias="eventTypes")
1050
+ only_scheduled_posts: bool = Field(..., alias="onlyScheduledPosts")
1051
+ enabled: bool
1052
+ webhook: Optional[CreateNotificationNotificationWebhook] = None
1053
+ email: Optional[CreateNotificationNotificationEmail] = None
1054
+ last_test_at: Optional[datetime] = Field(default=None, alias="lastTestAt")
1055
+ last_test_status: Optional[str] = Field(default=None, alias="lastTestStatus")
1056
+ created_at: datetime = Field(..., alias="createdAt")
1057
+ updated_at: datetime = Field(..., alias="updatedAt")
1058
+
1059
+
1060
+ class CreateNotificationResponse(BaseModel):
1061
+ """Default Response"""
1062
+
1063
+ success: bool
1064
+ notification: CreateNotificationNotification
1065
+
1066
+
1067
+ class DeleteNotificationPath(BaseModel):
1068
+ id: str = Field(..., description="Notification subscription ID")
1069
+
1070
+
1071
+ class DeleteNotificationResponse(BaseModel):
1072
+ """Default Response"""
1073
+
1074
+ success: bool
1075
+ message: str
1076
+
1077
+
1078
+ class GetNotificationPath(BaseModel):
1079
+ id: str = Field(..., description="Notification subscription ID")
1080
+
1081
+
1082
+ class GetNotificationNotificationChannel(str, Enum):
1083
+ WEBHOOK = "webhook"
1084
+ EMAIL = "email"
1085
+
1086
+
1087
+ class GetNotificationNotificationEventTypes(str, Enum):
1088
+ POST_SCHEDULED = "post.scheduled"
1089
+ POST_PUBLISHED = "post.published"
1090
+ POST_PARTIAL = "post.partial"
1091
+ POST_FAILED = "post.failed"
1092
+
1093
+
1094
+ class GetNotificationNotificationWebhook(BaseModel):
1095
+ model_config = ConfigDict(extra="forbid")
1096
+ url: AnyUrl
1097
+ secret: str = Field(..., description="Webhook signing secret (masked in list responses)")
1098
+
1099
+
1100
+ class GetNotificationNotificationEmail(BaseModel):
1101
+ model_config = ConfigDict(extra="forbid")
1102
+ recipients: Annotated[list[EmailStr], Field(min_length=1, max_length=10)]
1103
+
1104
+
1105
+ class GetNotificationNotification(BaseModel):
1106
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
1107
+ id: str
1108
+ channel: GetNotificationNotificationChannel
1109
+ profile_id: Optional[str] = Field(default=None, alias="profileId")
1110
+ event_types: list[GetNotificationNotificationEventTypes] = Field(..., alias="eventTypes")
1111
+ only_scheduled_posts: bool = Field(..., alias="onlyScheduledPosts")
1112
+ enabled: bool
1113
+ webhook: Optional[GetNotificationNotificationWebhook] = None
1114
+ email: Optional[GetNotificationNotificationEmail] = None
1115
+ last_test_at: Optional[datetime] = Field(default=None, alias="lastTestAt")
1116
+ last_test_status: Optional[str] = Field(default=None, alias="lastTestStatus")
1117
+ created_at: datetime = Field(..., alias="createdAt")
1118
+ updated_at: datetime = Field(..., alias="updatedAt")
1119
+
1120
+
1121
+ class GetNotificationResponse(BaseModel):
1122
+ """Default Response"""
1123
+
1124
+ success: bool
1125
+ notification: GetNotificationNotification
1126
+
1127
+
1128
+ class UpdateNotificationEventTypes(str, Enum):
1129
+ POST_SCHEDULED = "post.scheduled"
1130
+ POST_PUBLISHED = "post.published"
1131
+ POST_PARTIAL = "post.partial"
1132
+ POST_FAILED = "post.failed"
1133
+
1134
+
1135
+ class UpdateNotificationWebhook(BaseModel):
1136
+ model_config = ConfigDict(extra="forbid")
1137
+ url: AnyUrl = Field(..., description="HTTPS endpoint that receives PostPeer JSON payloads")
1138
+
1139
+
1140
+ class UpdateNotificationEmail(BaseModel):
1141
+ model_config = ConfigDict(extra="forbid")
1142
+ recipients: Annotated[list[EmailStr], Field(min_length=1, max_length=10)]
1143
+
1144
+
1145
+ class UpdateNotificationBody(BaseModel):
1146
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
1147
+ profile_id: Optional[str] = Field(default=None, alias="profileId")
1148
+ event_types: Optional[Annotated[list[UpdateNotificationEventTypes], Field(min_length=1)]] = Field(default=None, alias="eventTypes")
1149
+ only_scheduled_posts: Optional[bool] = Field(default=None, alias="onlyScheduledPosts", description="When true, deliver matching notifications only for posts that were scheduled.")
1150
+ enabled: Optional[bool] = None
1151
+ webhook: Optional[UpdateNotificationWebhook] = None
1152
+ email: Optional[UpdateNotificationEmail] = None
1153
+
1154
+
1155
+ class UpdateNotificationPath(BaseModel):
1156
+ id: str = Field(..., description="Notification subscription ID")
1157
+
1158
+
1159
+ class UpdateNotificationNotificationChannel(str, Enum):
1160
+ WEBHOOK = "webhook"
1161
+ EMAIL = "email"
1162
+
1163
+
1164
+ class UpdateNotificationNotificationEventTypes(str, Enum):
1165
+ POST_SCHEDULED = "post.scheduled"
1166
+ POST_PUBLISHED = "post.published"
1167
+ POST_PARTIAL = "post.partial"
1168
+ POST_FAILED = "post.failed"
1169
+
1170
+
1171
+ class UpdateNotificationNotificationWebhook(BaseModel):
1172
+ model_config = ConfigDict(extra="forbid")
1173
+ url: AnyUrl
1174
+ secret: str = Field(..., description="Webhook signing secret (masked in list responses)")
1175
+
1176
+
1177
+ class UpdateNotificationNotificationEmail(BaseModel):
1178
+ model_config = ConfigDict(extra="forbid")
1179
+ recipients: Annotated[list[EmailStr], Field(min_length=1, max_length=10)]
1180
+
1181
+
1182
+ class UpdateNotificationNotification(BaseModel):
1183
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
1184
+ id: str
1185
+ channel: UpdateNotificationNotificationChannel
1186
+ profile_id: Optional[str] = Field(default=None, alias="profileId")
1187
+ event_types: list[UpdateNotificationNotificationEventTypes] = Field(..., alias="eventTypes")
1188
+ only_scheduled_posts: bool = Field(..., alias="onlyScheduledPosts")
1189
+ enabled: bool
1190
+ webhook: Optional[UpdateNotificationNotificationWebhook] = None
1191
+ email: Optional[UpdateNotificationNotificationEmail] = None
1192
+ last_test_at: Optional[datetime] = Field(default=None, alias="lastTestAt")
1193
+ last_test_status: Optional[str] = Field(default=None, alias="lastTestStatus")
1194
+ created_at: datetime = Field(..., alias="createdAt")
1195
+ updated_at: datetime = Field(..., alias="updatedAt")
1196
+
1197
+
1198
+ class UpdateNotificationResponse(BaseModel):
1199
+ """Default Response"""
1200
+
1201
+ success: bool
1202
+ notification: UpdateNotificationNotification
1203
+
1204
+
1205
+ class ListPlatformsPlatformsName(str, Enum):
1206
+ TWITTER = "twitter"
1207
+ INSTAGRAM = "instagram"
1208
+ YOUTUBE = "youtube"
1209
+ TIKTOK = "tiktok"
1210
+ PINTEREST = "pinterest"
1211
+ LINKEDIN = "linkedin"
1212
+ BLUESKY = "bluesky"
1213
+ FACEBOOK = "facebook"
1214
+ THREADS = "threads"
1215
+ GOOGLEBUSINESS = "googlebusiness"
1216
+
1217
+
1218
+ class ListPlatformsPlatformsStatus(str, Enum):
1219
+ PROD = "prod"
1220
+ BETA = "beta"
1221
+ DEV = "dev"
1222
+
1223
+
1224
+ class ListPlatformsPlatforms(BaseModel):
1225
+ name: ListPlatformsPlatformsName
1226
+ status: ListPlatformsPlatformsStatus
1227
+
1228
+
1229
+ class ListPlatformsResponse(BaseModel):
1230
+ """Default Response"""
1231
+
1232
+ platforms: list[ListPlatformsPlatforms]
1233
+
1234
+
1235
+ class ListPostsStatus(str, Enum):
1236
+ DRAFT = "draft"
1237
+ PENDING = "pending"
1238
+ SCHEDULED = "scheduled"
1239
+ PUBLISHING = "publishing"
1240
+ PUBLISHED = "published"
1241
+ FAILED = "failed"
1242
+ PARTIAL = "partial"
1243
+
1244
+
1245
+ class ListPostsPlatform(str, Enum):
1246
+ TWITTER = "twitter"
1247
+ INSTAGRAM = "instagram"
1248
+ YOUTUBE = "youtube"
1249
+ TIKTOK = "tiktok"
1250
+ PINTEREST = "pinterest"
1251
+ LINKEDIN = "linkedin"
1252
+ BLUESKY = "bluesky"
1253
+ FACEBOOK = "facebook"
1254
+ THREADS = "threads"
1255
+ GOOGLEBUSINESS = "googlebusiness"
1256
+
1257
+
1258
+ class ListPostsQuery(BaseModel):
1259
+ status: Optional[ListPostsStatus] = None
1260
+ platform: Optional[list[ListPostsPlatform]] = Field(default=None, description="Filter by platform (repeatable — OR logic)")
1261
+ profile_id: Optional[str] = Field(default=None, alias="profileId", description='Filter to posts targeting an integration bound to this profile. Pass "null" (literal string) to filter to posts whose integrations have no profile.')
1262
+ created_after: Optional[datetime] = Field(default=None, alias="createdAfter", description="ISO 8601 lower bound on createdAt")
1263
+ created_before: Optional[datetime] = Field(default=None, alias="createdBefore", description="ISO 8601 upper bound on createdAt")
1264
+ scheduled_after: Optional[datetime] = Field(default=None, alias="scheduledAfter", description="ISO 8601 lower bound on scheduledFor")
1265
+ scheduled_before: Optional[datetime] = Field(default=None, alias="scheduledBefore", description="ISO 8601 upper bound on scheduledFor")
1266
+ limit: Optional[Annotated[int, Field(ge=1, le=100)]] = Field(default=20, description="Page size (max 100)")
1267
+ offset: Optional[Annotated[int, Field(ge=0)]] = Field(default=0, description="Number of posts to skip")
1268
+ sort: Optional[SortOrder] = None
1269
+
1270
+
1271
+ class ListPostsPostsStatus(str, Enum):
1272
+ DRAFT = "draft"
1273
+ PENDING = "pending"
1274
+ SCHEDULED = "scheduled"
1275
+ PUBLISHING = "publishing"
1276
+ PUBLISHED = "published"
1277
+ FAILED = "failed"
1278
+ PARTIAL = "partial"
1279
+
1280
+
1281
+ class ListPostsPostsMediaItemsType(str, Enum):
1282
+ IMAGE = "image"
1283
+ VIDEO = "video"
1284
+ GIF = "gif"
1285
+
1286
+
1287
+ class ListPostsPostsMediaItems(BaseModel):
1288
+ type: ListPostsPostsMediaItemsType
1289
+ url: str
1290
+ filename: str
1291
+ size: float
1292
+ mime_type: str = Field(..., alias="mimeType")
1293
+
1294
+
1295
+ class ListPostsPostsPlatformsPlatform(str, Enum):
1296
+ TWITTER = "twitter"
1297
+ INSTAGRAM = "instagram"
1298
+ YOUTUBE = "youtube"
1299
+ TIKTOK = "tiktok"
1300
+ PINTEREST = "pinterest"
1301
+ LINKEDIN = "linkedin"
1302
+ BLUESKY = "bluesky"
1303
+ FACEBOOK = "facebook"
1304
+ THREADS = "threads"
1305
+ GOOGLEBUSINESS = "googlebusiness"
1306
+
1307
+
1308
+ class ListPostsPostsPlatformsStatus(str, Enum):
1309
+ DRAFT = "draft"
1310
+ PENDING = "pending"
1311
+ SCHEDULED = "scheduled"
1312
+ PUBLISHING = "publishing"
1313
+ PUBLISHED = "published"
1314
+ FAILED = "failed"
1315
+ PARTIAL = "partial"
1316
+
1317
+
1318
+ class ListPostsPostsPlatforms(BaseModel):
1319
+ platform: ListPostsPostsPlatformsPlatform
1320
+ status: ListPostsPostsPlatformsStatus
1321
+ content: Optional[str] = Field(default=None, description="Per-platform text override that was used for this platform. Null when the top-level `content` was used.")
1322
+ platform_post_id: Optional[str] = Field(default=None, alias="platformPostId")
1323
+ platform_post_url: Optional[str] = Field(default=None, alias="platformPostUrl", description="Direct URL to the published post")
1324
+ published_at: Optional[datetime] = Field(default=None, alias="publishedAt")
1325
+ error_message: Optional[str] = Field(default=None, alias="errorMessage")
1326
+ warning_message: Optional[str] = Field(default=None, alias="warningMessage")
1327
+
1328
+
1329
+ class ListPostsPosts(BaseModel):
1330
+ post_id: str = Field(..., alias="postId", description="MongoDB ObjectId of the Post document")
1331
+ content: str
1332
+ status: ListPostsPostsStatus
1333
+ scheduled_for: Optional[datetime] = Field(default=None, alias="scheduledFor", description="ISO 8601 scheduled datetime")
1334
+ timezone: str
1335
+ media_items: list[ListPostsPostsMediaItems] = Field(..., alias="mediaItems")
1336
+ platforms: list[ListPostsPostsPlatforms]
1337
+ crossposting_enabled: bool = Field(..., alias="crosspostingEnabled")
1338
+ raw_request_body: dict[str, Any] = Field(..., alias="rawRequestBody")
1339
+ created_at: datetime = Field(..., alias="createdAt")
1340
+ updated_at: datetime = Field(..., alias="updatedAt")
1341
+
1342
+
1343
+ class ListPostsResponse(BaseModel):
1344
+ """Default Response"""
1345
+
1346
+ success: bool
1347
+ total: Annotated[int, Field(ge=0)] = Field(..., description="Total matched posts across all pages")
1348
+ posts: list[ListPostsPosts]
1349
+
1350
+
1351
+ class CreatePostMediaItemsType(str, Enum):
1352
+ IMAGE = "image"
1353
+ VIDEO = "video"
1354
+ GIF = "gif"
1355
+ DOCUMENT = "document"
1356
+
1357
+
1358
+ class CreatePostMediaItems(BaseModel):
1359
+ model_config = ConfigDict(extra="forbid")
1360
+ type: CreatePostMediaItemsType
1361
+ url: AnyUrl
1362
+ thumbnail: Optional[AnyUrl] = Field(default=None, description="Thumbnail image URL for video items. Supported on YouTube regular videos (not Shorts). JPEG, PNG, or GIF, max 2 MB, min 640 px wide.")
1363
+
1364
+
1365
+ class CreatePostPlatformsPlatform(str, Enum):
1366
+ TWITTER = "twitter"
1367
+
1368
+
1369
+ class CreatePostPlatforms(BaseModel):
1370
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
1371
+ platform: CreatePostPlatformsPlatform
1372
+ account_id: str = Field(..., alias="accountId", description="Integration._id — find yours via GET /connect/integrations")
1373
+ content: Optional[str] = Field(default=None, description="Optional per-platform text override. Use when you want to change the text for this platform because different platforms talk differently. When omitted, the top-level `content` is used.")
1374
+ platform_specific_data: Optional[TwitterConfigurations] = Field(default=None, alias="platformSpecificData")
1375
+
1376
+
1377
+ class CreatePostPlatformsPlatform_(str, Enum):
1378
+ INSTAGRAM = "instagram"
1379
+
1380
+
1381
+ class CreatePostPlatforms_(BaseModel):
1382
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
1383
+ platform: CreatePostPlatformsPlatform_
1384
+ account_id: str = Field(..., alias="accountId", description="Integration._id — find yours via GET /connect/integrations")
1385
+ content: Optional[str] = Field(default=None, description="Optional per-platform text override. Use when you want to change the text for this platform because different platforms talk differently. When omitted, the top-level `content` is used.")
1386
+ platform_specific_data: Optional[InstagramConfigurations] = Field(default=None, alias="platformSpecificData")
1387
+
1388
+
1389
+ class CreatePostPlatformsPlatform_2(str, Enum):
1390
+ YOUTUBE = "youtube"
1391
+
1392
+
1393
+ class CreatePostPlatforms_2(BaseModel):
1394
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
1395
+ platform: CreatePostPlatformsPlatform_2
1396
+ account_id: str = Field(..., alias="accountId", description="Integration._id — find yours via GET /connect/integrations")
1397
+ content: Optional[str] = Field(default=None, description="Optional per-platform text override. Use when you want to change the text for this platform because different platforms talk differently. When omitted, the top-level `content` is used.")
1398
+ platform_specific_data: Optional[YouTubeConfigurations] = Field(default=None, alias="platformSpecificData")
1399
+
1400
+
1401
+ class CreatePostPlatformsPlatform_3(str, Enum):
1402
+ TIKTOK = "tiktok"
1403
+
1404
+
1405
+ class CreatePostPlatforms_3(BaseModel):
1406
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
1407
+ platform: CreatePostPlatformsPlatform_3
1408
+ account_id: str = Field(..., alias="accountId", description="Integration._id — find yours via GET /connect/integrations")
1409
+ content: Optional[str] = Field(default=None, description="Optional per-platform text override. Use when you want to change the text for this platform because different platforms talk differently. When omitted, the top-level `content` is used.")
1410
+ platform_specific_data: Optional[TikTokConfigurations] = Field(default=None, alias="platformSpecificData")
1411
+
1412
+
1413
+ class CreatePostPlatformsPlatform_4(str, Enum):
1414
+ PINTEREST = "pinterest"
1415
+
1416
+
1417
+ class CreatePostPlatforms_4(BaseModel):
1418
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
1419
+ platform: CreatePostPlatformsPlatform_4
1420
+ account_id: str = Field(..., alias="accountId", description="Integration._id — find yours via GET /connect/integrations")
1421
+ content: Optional[str] = Field(default=None, description="Optional per-platform text override. Use when you want to change the text for this platform because different platforms talk differently. When omitted, the top-level `content` is used.")
1422
+ platform_specific_data: Optional[PinterestConfigurations] = Field(default=None, alias="platformSpecificData")
1423
+
1424
+
1425
+ class CreatePostPlatformsPlatform_5(str, Enum):
1426
+ LINKEDIN = "linkedin"
1427
+
1428
+
1429
+ class CreatePostPlatforms_5(BaseModel):
1430
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
1431
+ platform: CreatePostPlatformsPlatform_5
1432
+ account_id: str = Field(..., alias="accountId", description="Integration._id — find yours via GET /connect/integrations")
1433
+ content: Optional[str] = Field(default=None, description="Optional per-platform text override. Use when you want to change the text for this platform because different platforms talk differently. When omitted, the top-level `content` is used.")
1434
+ platform_specific_data: Optional[LinkedInConfigurations] = Field(default=None, alias="platformSpecificData")
1435
+
1436
+
1437
+ class CreatePostPlatformsPlatform_6(str, Enum):
1438
+ BLUESKY = "bluesky"
1439
+
1440
+
1441
+ class CreatePostPlatforms_6(BaseModel):
1442
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
1443
+ platform: CreatePostPlatformsPlatform_6
1444
+ account_id: str = Field(..., alias="accountId", description="Integration._id — find yours via GET /connect/integrations")
1445
+ content: Optional[str] = Field(default=None, description="Optional per-platform text override. Use when you want to change the text for this platform because different platforms talk differently. When omitted, the top-level `content` is used.")
1446
+ platform_specific_data: Optional[BlueskyConfigurations] = Field(default=None, alias="platformSpecificData")
1447
+
1448
+
1449
+ class CreatePostPlatformsPlatform_7(str, Enum):
1450
+ FACEBOOK = "facebook"
1451
+
1452
+
1453
+ class CreatePostPlatforms_7(BaseModel):
1454
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
1455
+ platform: CreatePostPlatformsPlatform_7
1456
+ account_id: str = Field(..., alias="accountId", description="Integration._id — find yours via GET /connect/integrations")
1457
+ content: Optional[str] = Field(default=None, description="Optional per-platform text override. Use when you want to change the text for this platform because different platforms talk differently. When omitted, the top-level `content` is used.")
1458
+ platform_specific_data: Optional[FacebookConfigurations] = Field(default=None, alias="platformSpecificData")
1459
+
1460
+
1461
+ class CreatePostPlatformsPlatform_8(str, Enum):
1462
+ THREADS = "threads"
1463
+
1464
+
1465
+ class CreatePostPlatforms_8(BaseModel):
1466
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
1467
+ platform: CreatePostPlatformsPlatform_8
1468
+ account_id: str = Field(..., alias="accountId", description="Integration._id — find yours via GET /connect/integrations")
1469
+ content: Optional[str] = Field(default=None, description="Optional per-platform text override. Use when you want to change the text for this platform because different platforms talk differently. When omitted, the top-level `content` is used.")
1470
+ platform_specific_data: Optional[ThreadsConfigurations] = Field(default=None, alias="platformSpecificData")
1471
+
1472
+
1473
+ class CreatePostPlatformsPlatform_9(str, Enum):
1474
+ GOOGLEBUSINESS = "googlebusiness"
1475
+
1476
+
1477
+ class CreatePostPlatforms_9(BaseModel):
1478
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
1479
+ platform: CreatePostPlatformsPlatform_9
1480
+ account_id: str = Field(..., alias="accountId", description="Integration._id — find yours via GET /connect/integrations")
1481
+ content: Optional[str] = Field(default=None, description="Optional per-platform text override. Use when you want to change the text for this platform because different platforms talk differently. When omitted, the top-level `content` is used.")
1482
+ platform_specific_data: Optional[GoogleBusinessConfigurations] = Field(default=None, alias="platformSpecificData")
1483
+
1484
+
1485
+ class CreatePostBody(BaseModel):
1486
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
1487
+ content: str = Field(..., description="Post text body")
1488
+ media_items: Optional[list[CreatePostMediaItems]] = Field(default=None, alias="mediaItems", description="Media attachments (images, videos, GIFs)")
1489
+ platforms: Annotated[list[Union[CreatePostPlatforms, CreatePostPlatforms_, CreatePostPlatforms_2, CreatePostPlatforms_3, CreatePostPlatforms_4, CreatePostPlatforms_5, CreatePostPlatforms_6, CreatePostPlatforms_7, CreatePostPlatforms_8, CreatePostPlatforms_9]], Field(min_length=1)] = Field(..., description="Target platform accounts to publish to")
1490
+ publish_now: Optional[bool] = Field(default=None, alias="publishNow", description="Publish immediately. Required when scheduledFor is omitted.")
1491
+ scheduled_for: Optional[datetime] = Field(default=None, alias="scheduledFor", description="ISO 8601 datetime to schedule the post for future publishing")
1492
+ timezone: Optional[str] = Field(default=None, description="IANA timezone for the scheduled time (e.g. America/New_York). Defaults to UTC.")
1493
+
1494
+
1495
+ class CreatePostStatus(str, Enum):
1496
+ DRAFT = "draft"
1497
+ PENDING = "pending"
1498
+ SCHEDULED = "scheduled"
1499
+ PUBLISHING = "publishing"
1500
+ PUBLISHED = "published"
1501
+ FAILED = "failed"
1502
+ PARTIAL = "partial"
1503
+
1504
+
1505
+ class CreatePostPlatformsPlatform_10(str, Enum):
1506
+ TWITTER = "twitter"
1507
+ INSTAGRAM = "instagram"
1508
+ YOUTUBE = "youtube"
1509
+ TIKTOK = "tiktok"
1510
+ PINTEREST = "pinterest"
1511
+ LINKEDIN = "linkedin"
1512
+ BLUESKY = "bluesky"
1513
+ FACEBOOK = "facebook"
1514
+ THREADS = "threads"
1515
+ GOOGLEBUSINESS = "googlebusiness"
1516
+
1517
+
1518
+ class CreatePostPlatforms_10(BaseModel):
1519
+ platform: CreatePostPlatformsPlatform_10
1520
+ success: bool = Field(..., description="For publish-now timeout fallback, true means the platform target was accepted and final status is still pending.")
1521
+ platform_post_url: Optional[str] = Field(default=None, alias="platformPostUrl", description="Direct URL to the published post")
1522
+ error: Optional[str] = Field(default=None, description="Error message when success is false")
1523
+ warning_message: Optional[str] = Field(default=None, alias="warningMessage", description="Warning message when the post published but a non-critical follow-up action failed")
1524
+
1525
+
1526
+ class CreatePostResponse(BaseModel):
1527
+ """Default Response"""
1528
+
1529
+ success: bool = Field(..., description="false only when every platform failed")
1530
+ status: CreatePostStatus
1531
+ scheduled_for: Optional[datetime] = Field(default=None, alias="scheduledFor", description="ISO 8601 datetime the post is scheduled for (only present for scheduled posts)")
1532
+ post_id: str = Field(..., alias="postId", description="id of the saved Post document")
1533
+ platforms: list[CreatePostPlatforms_10]
1534
+
1535
+
1536
+ class DeletePostPath(BaseModel):
1537
+ post_id: str = Field(..., alias="postId", description="Post identifier")
1538
+
1539
+
1540
+ class DeletePostQuery(BaseModel):
1541
+ delete_from_platforms: Optional[bool] = Field(default=False, alias="deleteFromPlatforms", description="When true, also delete supported published platform posts. Costs 1 credit per successful platform deletion.")
1542
+
1543
+
1544
+ class DeletePostPlatforms(BaseModel):
1545
+ platform: str
1546
+ integration_id: str = Field(..., alias="integrationId")
1547
+ platform_post_id: Optional[str] = Field(default=None, alias="platformPostId")
1548
+ status: str
1549
+ success: bool
1550
+ message: Optional[str] = None
1551
+ error_message: Optional[str] = Field(default=None, alias="errorMessage")
1552
+
1553
+
1554
+ class DeletePostResponse(BaseModel):
1555
+ """Default Response"""
1556
+
1557
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
1558
+ success: bool
1559
+ credits_charged: Optional[Annotated[int, Field(ge=0)]] = Field(default=None, alias="creditsCharged")
1560
+ platforms: Optional[list[DeletePostPlatforms]] = None
1561
+
1562
+
1563
+ class GetPostPath(BaseModel):
1564
+ post_id: str = Field(..., alias="postId", description="Post identifier")
1565
+
1566
+
1567
+ class GetPostPostStatus(str, Enum):
1568
+ DRAFT = "draft"
1569
+ PENDING = "pending"
1570
+ SCHEDULED = "scheduled"
1571
+ PUBLISHING = "publishing"
1572
+ PUBLISHED = "published"
1573
+ FAILED = "failed"
1574
+ PARTIAL = "partial"
1575
+
1576
+
1577
+ class GetPostPostMediaItemsType(str, Enum):
1578
+ IMAGE = "image"
1579
+ VIDEO = "video"
1580
+ GIF = "gif"
1581
+
1582
+
1583
+ class GetPostPostMediaItems(BaseModel):
1584
+ type: GetPostPostMediaItemsType
1585
+ url: str
1586
+ filename: str
1587
+ size: float
1588
+ mime_type: str = Field(..., alias="mimeType")
1589
+
1590
+
1591
+ class GetPostPostPlatformsPlatform(str, Enum):
1592
+ TWITTER = "twitter"
1593
+ INSTAGRAM = "instagram"
1594
+ YOUTUBE = "youtube"
1595
+ TIKTOK = "tiktok"
1596
+ PINTEREST = "pinterest"
1597
+ LINKEDIN = "linkedin"
1598
+ BLUESKY = "bluesky"
1599
+ FACEBOOK = "facebook"
1600
+ THREADS = "threads"
1601
+ GOOGLEBUSINESS = "googlebusiness"
1602
+
1603
+
1604
+ class GetPostPostPlatformsStatus(str, Enum):
1605
+ DRAFT = "draft"
1606
+ PENDING = "pending"
1607
+ SCHEDULED = "scheduled"
1608
+ PUBLISHING = "publishing"
1609
+ PUBLISHED = "published"
1610
+ FAILED = "failed"
1611
+ PARTIAL = "partial"
1612
+
1613
+
1614
+ class GetPostPostPlatforms(BaseModel):
1615
+ platform: GetPostPostPlatformsPlatform
1616
+ status: GetPostPostPlatformsStatus
1617
+ content: Optional[str] = Field(default=None, description="Per-platform text override that was used for this platform. Null when the top-level `content` was used.")
1618
+ platform_post_id: Optional[str] = Field(default=None, alias="platformPostId")
1619
+ platform_post_url: Optional[str] = Field(default=None, alias="platformPostUrl", description="Direct URL to the published post")
1620
+ published_at: Optional[datetime] = Field(default=None, alias="publishedAt")
1621
+ error_message: Optional[str] = Field(default=None, alias="errorMessage")
1622
+ warning_message: Optional[str] = Field(default=None, alias="warningMessage")
1623
+
1624
+
1625
+ class GetPostPost(BaseModel):
1626
+ post_id: str = Field(..., alias="postId", description="MongoDB ObjectId of the Post document")
1627
+ content: str
1628
+ status: GetPostPostStatus
1629
+ scheduled_for: Optional[datetime] = Field(default=None, alias="scheduledFor", description="ISO 8601 scheduled datetime")
1630
+ timezone: str
1631
+ media_items: list[GetPostPostMediaItems] = Field(..., alias="mediaItems")
1632
+ platforms: list[GetPostPostPlatforms]
1633
+ crossposting_enabled: bool = Field(..., alias="crosspostingEnabled")
1634
+ raw_request_body: dict[str, Any] = Field(..., alias="rawRequestBody")
1635
+ created_at: datetime = Field(..., alias="createdAt")
1636
+ updated_at: datetime = Field(..., alias="updatedAt")
1637
+
1638
+
1639
+ class GetPostResponse(BaseModel):
1640
+ """Default Response"""
1641
+
1642
+ success: bool
1643
+ post: GetPostPost
1644
+
1645
+
1646
+ class ListScheduledPostsQuery(BaseModel):
1647
+ limit: Optional[Annotated[int, Field(ge=1, le=100)]] = Field(default=20, description="Page size (max 100)")
1648
+ offset: Optional[Annotated[int, Field(ge=0)]] = Field(default=0, description="Number of scheduled posts to skip")
1649
+ sort: Optional[SortOrder] = None
1650
+
1651
+
1652
+ class ListScheduledPostsPostsMediaItemsType(str, Enum):
1653
+ IMAGE = "image"
1654
+ VIDEO = "video"
1655
+ GIF = "gif"
1656
+ DOCUMENT = "document"
1657
+
1658
+
1659
+ class ListScheduledPostsPostsMediaItems(BaseModel):
1660
+ model_config = ConfigDict(extra="forbid")
1661
+ type: ListScheduledPostsPostsMediaItemsType
1662
+ url: AnyUrl
1663
+ thumbnail: Optional[AnyUrl] = Field(default=None, description="Thumbnail image URL for video items. Supported on YouTube regular videos (not Shorts). JPEG, PNG, or GIF, max 2 MB, min 640 px wide.")
1664
+
1665
+
1666
+ class ListScheduledPostsPostsPlatformsPlatform(str, Enum):
1667
+ TWITTER = "twitter"
1668
+ INSTAGRAM = "instagram"
1669
+ YOUTUBE = "youtube"
1670
+ TIKTOK = "tiktok"
1671
+ PINTEREST = "pinterest"
1672
+ LINKEDIN = "linkedin"
1673
+ BLUESKY = "bluesky"
1674
+ FACEBOOK = "facebook"
1675
+ THREADS = "threads"
1676
+ GOOGLEBUSINESS = "googlebusiness"
1677
+
1678
+
1679
+ class ListScheduledPostsPostsPlatformsStatus(str, Enum):
1680
+ DRAFT = "draft"
1681
+ PENDING = "pending"
1682
+ SCHEDULED = "scheduled"
1683
+ PUBLISHING = "publishing"
1684
+ PUBLISHED = "published"
1685
+ FAILED = "failed"
1686
+ PARTIAL = "partial"
1687
+
1688
+
1689
+ class ListScheduledPostsPostsPlatforms(BaseModel):
1690
+ platform: ListScheduledPostsPostsPlatformsPlatform
1691
+ status: ListScheduledPostsPostsPlatformsStatus
1692
+
1693
+
1694
+ class ListScheduledPostsPosts(BaseModel):
1695
+ post_id: str = Field(..., alias="postId", description="MongoDB ObjectId of the Post document")
1696
+ content: str = Field(..., description="Post text body")
1697
+ scheduled_for: Optional[datetime] = Field(default=None, alias="scheduledFor", description="ISO 8601 scheduled datetime")
1698
+ timezone: str = Field(..., description="IANA timezone for the scheduled time")
1699
+ media_items: Optional[list[ListScheduledPostsPostsMediaItems]] = Field(default=None, alias="mediaItems", description="Media attachments")
1700
+ platforms: list[ListScheduledPostsPostsPlatforms]
1701
+ created_at: datetime = Field(..., alias="createdAt")
1702
+
1703
+
1704
+ class ListScheduledPostsResponse(BaseModel):
1705
+ """Default Response"""
1706
+
1707
+ success: bool
1708
+ total: Annotated[int, Field(ge=0)] = Field(..., description="Total matched scheduled posts across all pages")
1709
+ posts: list[ListScheduledPostsPosts]
1710
+
1711
+
1712
+ class CancelScheduledPostPath(BaseModel):
1713
+ post_id: str = Field(..., alias="postId")
1714
+
1715
+
1716
+ class CancelScheduledPostResponse(BaseModel):
1717
+ """Default Response"""
1718
+
1719
+ success: bool
1720
+ message: str
1721
+
1722
+
1723
+ class ReschedulePostBody(BaseModel):
1724
+ scheduled_for: datetime = Field(..., alias="scheduledFor", description="New ISO 8601 datetime to schedule the post")
1725
+ timezone: Optional[str] = Field(default=None, description="IANA timezone")
1726
+
1727
+
1728
+ class ReschedulePostPath(BaseModel):
1729
+ post_id: str = Field(..., alias="postId")
1730
+
1731
+
1732
+ class ReschedulePostResponse(BaseModel):
1733
+ """Default Response"""
1734
+
1735
+ success: bool
1736
+ message: str
1737
+ scheduled_for: str = Field(..., alias="scheduledFor")
1738
+
1739
+
1740
+ class CreateMediaUploadBody(BaseModel):
1741
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
1742
+ filename: Annotated[str, Field(min_length=1)]
1743
+ mime_type: Annotated[str, Field(min_length=1)] = Field(..., alias="mimeType")
1744
+
1745
+
1746
+ class CreateMediaUploadData(BaseModel):
1747
+ upload_url: str = Field(..., alias="uploadUrl")
1748
+ public_url: str = Field(..., alias="publicUrl")
1749
+
1750
+
1751
+ class CreateMediaUploadResponse(BaseModel):
1752
+ """Default Response"""
1753
+
1754
+ success: bool
1755
+ data: CreateMediaUploadData
1756
+
1757
+
1758
+ class GetAnalyticsSource(str, Enum):
1759
+ """Where the result came from. "postpeer" = posts published via PostPeer (stored in our DB). "platform" = fetched directly from the connected platform account."""
1760
+
1761
+ POSTPEER = "postpeer"
1762
+ PLATFORM = "platform"
1763
+
1764
+
1765
+ class GetAnalyticsSortBy(str, Enum):
1766
+ """Sort results by this metric"""
1767
+
1768
+ DATE = "date"
1769
+ LIKES = "likes"
1770
+ COMMENTS = "comments"
1771
+ IMPRESSIONS = "impressions"
1772
+ VIEWS = "views"
1773
+ SHARES = "shares"
1774
+ SAVES = "saves"
1775
+ CLICKS = "clicks"
1776
+ ENGAGEMENT = "engagement"
1777
+
1778
+
1779
+ class GetAnalyticsQuery(BaseModel):
1780
+ post_id: Optional[str] = Field(default=None, alias="postId", description="PostPeer post ID or external platform post ID (auto-resolved). When omitted, returns a paginated list of all published posts with analytics.")
1781
+ platform: Optional[Platform] = None
1782
+ account_id: Optional[str] = Field(default=None, alias="accountId", description="Integration ID. Required for external ID lookups and source=platform.")
1783
+ source: Optional[GetAnalyticsSource] = Field(default=None, description='Where the result came from. "postpeer" = posts published via PostPeer (stored in our DB). "platform" = fetched directly from the connected platform account.')
1784
+ from_date: Optional[date] = Field(default=None, alias="fromDate", description="Inclusive start date (YYYY-MM-DD). Defaults to 90 days ago.")
1785
+ to_date: Optional[date] = Field(default=None, alias="toDate", description="Inclusive end date (YYYY-MM-DD). Defaults to today.")
1786
+ sort_by: Optional[GetAnalyticsSortBy] = Field(default=None, alias="sortBy", description="Sort results by this metric")
1787
+ order: Optional[SortOrder] = None
1788
+ limit: Optional[Annotated[int, Field(ge=1, le=100)]] = Field(default=50, description="Page size (1-100)")
1789
+ page: Optional[Annotated[int, Field(ge=1)]] = Field(default=1, description="Page number")
1790
+
1791
+
1792
+ class GetAnalyticsPostSource(str, Enum):
1793
+ """Where the result came from. "postpeer" = posts published via PostPeer (stored in our DB). "platform" = fetched directly from the connected platform account."""
1794
+
1795
+ POSTPEER = "postpeer"
1796
+ PLATFORM = "platform"
1797
+
1798
+
1799
+ class GetAnalyticsPostAggregated(BaseModel):
1800
+ impressions: Optional[float] = None
1801
+ reach: Optional[float] = None
1802
+ likes: Optional[float] = None
1803
+ comments: Optional[float] = None
1804
+ shares: Optional[float] = None
1805
+ saves: Optional[float] = None
1806
+ clicks: Optional[float] = None
1807
+ views: Optional[float] = None
1808
+ engagement_rate: Optional[float] = Field(default=None, alias="engagementRate", description="Engagement rate (0-1). null when the platform does not report engagement.")
1809
+
1810
+
1811
+ class GetAnalyticsPostPlatformsMetrics(BaseModel):
1812
+ impressions: Optional[float] = None
1813
+ reach: Optional[float] = None
1814
+ likes: Optional[float] = None
1815
+ comments: Optional[float] = None
1816
+ shares: Optional[float] = None
1817
+ saves: Optional[float] = None
1818
+ clicks: Optional[float] = None
1819
+ views: Optional[float] = None
1820
+ engagement_rate: Optional[float] = Field(default=None, alias="engagementRate", description="Engagement rate (0-1). null when the platform does not report engagement.")
1821
+
1822
+
1823
+ class GetAnalyticsPostPlatforms(BaseModel):
1824
+ platform: Platform
1825
+ platform_post_id: str = Field(..., alias="platformPostId", description="Native post ID on the platform")
1826
+ platform_post_url: Optional[str] = Field(default=None, alias="platformPostUrl", description="Direct URL to the published post, if known")
1827
+ metrics: GetAnalyticsPostPlatformsMetrics
1828
+
1829
+
1830
+ class GetAnalyticsPost(BaseModel):
1831
+ source: GetAnalyticsPostSource = Field(..., description='Where the result came from. "postpeer" = posts published via PostPeer (stored in our DB). "platform" = fetched directly from the connected platform account.')
1832
+ post_id: Optional[str] = Field(default=None, alias="postId", description="PostPeer post ID. null when source=platform (post fetched directly from the platform).")
1833
+ content: Optional[str] = None
1834
+ published_at: Optional[datetime] = Field(default=None, alias="publishedAt")
1835
+ aggregated: GetAnalyticsPostAggregated
1836
+ platforms: list[GetAnalyticsPostPlatforms]
1837
+
1838
+
1839
+ class GetAnalytics(BaseModel):
1840
+ success: bool
1841
+ post: GetAnalyticsPost
1842
+
1843
+
1844
+ class GetAnalyticsPostsSource(str, Enum):
1845
+ """Where the result came from. "postpeer" = posts published via PostPeer (stored in our DB). "platform" = fetched directly from the connected platform account."""
1846
+
1847
+ POSTPEER = "postpeer"
1848
+ PLATFORM = "platform"
1849
+
1850
+
1851
+ class GetAnalyticsPostsAggregated(BaseModel):
1852
+ impressions: Optional[float] = None
1853
+ reach: Optional[float] = None
1854
+ likes: Optional[float] = None
1855
+ comments: Optional[float] = None
1856
+ shares: Optional[float] = None
1857
+ saves: Optional[float] = None
1858
+ clicks: Optional[float] = None
1859
+ views: Optional[float] = None
1860
+ engagement_rate: Optional[float] = Field(default=None, alias="engagementRate", description="Engagement rate (0-1). null when the platform does not report engagement.")
1861
+
1862
+
1863
+ class GetAnalyticsPostsPlatformsMetrics(BaseModel):
1864
+ impressions: Optional[float] = None
1865
+ reach: Optional[float] = None
1866
+ likes: Optional[float] = None
1867
+ comments: Optional[float] = None
1868
+ shares: Optional[float] = None
1869
+ saves: Optional[float] = None
1870
+ clicks: Optional[float] = None
1871
+ views: Optional[float] = None
1872
+ engagement_rate: Optional[float] = Field(default=None, alias="engagementRate", description="Engagement rate (0-1). null when the platform does not report engagement.")
1873
+
1874
+
1875
+ class GetAnalyticsPostsPlatforms(BaseModel):
1876
+ platform: Platform
1877
+ platform_post_id: str = Field(..., alias="platformPostId", description="Native post ID on the platform")
1878
+ platform_post_url: Optional[str] = Field(default=None, alias="platformPostUrl", description="Direct URL to the published post, if known")
1879
+ metrics: GetAnalyticsPostsPlatformsMetrics
1880
+
1881
+
1882
+ class GetAnalyticsPosts(BaseModel):
1883
+ source: GetAnalyticsPostsSource = Field(..., description='Where the result came from. "postpeer" = posts published via PostPeer (stored in our DB). "platform" = fetched directly from the connected platform account.')
1884
+ post_id: Optional[str] = Field(default=None, alias="postId", description="PostPeer post ID. null when source=platform (post fetched directly from the platform).")
1885
+ content: Optional[str] = None
1886
+ published_at: Optional[datetime] = Field(default=None, alias="publishedAt")
1887
+ aggregated: GetAnalyticsPostsAggregated
1888
+ platforms: list[GetAnalyticsPostsPlatforms]
1889
+
1890
+
1891
+ class GetAnalytics_(BaseModel):
1892
+ success: bool
1893
+ total: Annotated[int, Field(ge=0)] = Field(..., description="Total matched posts across all pages")
1894
+ page: Annotated[int, Field(ge=1)]
1895
+ limit: Annotated[int, Field(ge=1)]
1896
+ posts: list[GetAnalyticsPosts]
1897
+
1898
+
1899
+ class GetAnalyticsResponse(RootModel[Union[GetAnalytics, GetAnalytics_]]):
1900
+ """Single-post response (when postId is supplied) or paginated list response."""
1901
+
1902
+ root: Union[GetAnalytics, GetAnalytics_] = Field(..., description="Single-post response (when postId is supplied) or paginated list response.")
1903
+
1904
+
1905
+ class GetUsageQuery(BaseModel):
1906
+ profile_id: Optional[str] = Field(default=None, alias="profileId", description="Return usage for this profile only. Mutually exclusive with integrationId.")
1907
+ integration_id: Optional[str] = Field(default=None, alias="integrationId", description="Return usage for this integration only. Mutually exclusive with profileId.")
1908
+ from_: Optional[Annotated[str, Field(pattern=r"^\d{4}-(0[1-9]|1[0-2])$")]] = Field(default=None, alias="from", description="Inclusive start month (YYYY-MM). Filters the usage history array.")
1909
+ to: Optional[Annotated[str, Field(pattern=r"^\d{4}-(0[1-9]|1[0-2])$")]] = Field(default=None, description="Inclusive end month (YYYY-MM). Filters the usage history array.")
1910
+
1911
+
1912
+ class GetUsageUsage(BaseModel):
1913
+ year: int = Field(..., description="Calendar year")
1914
+ month: Annotated[int, Field(ge=1, le=12)] = Field(..., description="Calendar month (1–12)")
1915
+ count: Annotated[int, Field(ge=0)] = Field(..., description="Credits used this month")
1916
+ platform: dict[str, int] = Field(..., description="Credits broken down by platform name")
1917
+
1918
+
1919
+ class GetUsageBalanceMonthly(BaseModel):
1920
+ limit: int = Field(..., description="Total monthly credits included in your plan")
1921
+ used: int = Field(..., description="Monthly credits used so far this billing cycle")
1922
+ remaining: int = Field(..., description="Monthly credits still available this cycle")
1923
+ cycle_start: datetime = Field(..., alias="cycleStart", description="Start of the current billing cycle")
1924
+ cycle_end: datetime = Field(..., alias="cycleEnd", description="End of the current billing cycle — resets here")
1925
+
1926
+
1927
+ class GetUsageBalancePurchased(BaseModel):
1928
+ total: int = Field(..., description="Total one-time credits purchased (never expire)")
1929
+ used: int = Field(..., description="One-time credits consumed so far")
1930
+ remaining: int = Field(..., description="One-time credits still available")
1931
+
1932
+
1933
+ class GetUsageBalance(BaseModel):
1934
+ """Current credit balance. Only present on project-level requests (no profileId or integrationId filter)."""
1935
+
1936
+ monthly: GetUsageBalanceMonthly
1937
+ purchased: GetUsageBalancePurchased
1938
+
1939
+
1940
+ class GetUsageResponse(BaseModel):
1941
+ """Default Response"""
1942
+
1943
+ success: bool
1944
+ total_usage: Annotated[int, Field(ge=0)] = Field(..., alias="totalUsage", description="All-time credits used")
1945
+ usage: list[GetUsageUsage] = Field(..., description="Monthly credit history, oldest first")
1946
+ balance: Optional[GetUsageBalance] = Field(default=None, description="Current credit balance. Only present on project-level requests (no profileId or integrationId filter).")
1947
+
1948
+
1949
+ class GetPinterestBoardsQuery(BaseModel):
1950
+ account_id: Optional[str] = Field(default=None, alias="accountId", description="Integration ID of the Pinterest account. If omitted, uses the first connected Pinterest account.")
1951
+
1952
+
1953
+ class GetPinterestBoardsBoards(BaseModel):
1954
+ id: str
1955
+ name: str
1956
+ description: Optional[str] = None
1957
+ privacy: str
1958
+
1959
+
1960
+ class GetPinterestBoardsResponse(BaseModel):
1961
+ """Default Response"""
1962
+
1963
+ success: bool
1964
+ boards: list[GetPinterestBoardsBoards]
1965
+
1966
+
1967
+ class GetTikTokCreatorInfoQuery(BaseModel):
1968
+ account_id: Optional[str] = Field(default=None, alias="accountId", description="Integration ID of the TikTok account. If omitted, uses the first connected TikTok account.")
1969
+
1970
+
1971
+ class GetTikTokCreatorInfoDataPrivacyLevelOptions(str, Enum):
1972
+ PUBLIC_TO_EVERYONE = "PUBLIC_TO_EVERYONE"
1973
+ MUTUAL_FOLLOW_FRIENDS = "MUTUAL_FOLLOW_FRIENDS"
1974
+ FOLLOWER_OF_CREATOR = "FOLLOWER_OF_CREATOR"
1975
+ SELF_ONLY = "SELF_ONLY"
1976
+
1977
+
1978
+ class GetTikTokCreatorInfoData(BaseModel):
1979
+ creator_avatar_url: Union[str, Any] = Field(..., alias="creatorAvatarUrl", description="Profile avatar URL returned by TikTok.")
1980
+ creator_username: Union[str, Any] = Field(..., alias="creatorUsername", description="Username (@handle) of the creator.")
1981
+ creator_nickname: Union[str, Any] = Field(..., alias="creatorNickname", description="Display name of the creator.")
1982
+ privacy_level_options: list[GetTikTokCreatorInfoDataPrivacyLevelOptions] = Field(..., alias="privacyLevelOptions", description="Privacy levels available to this creator. Your UX must restrict the privacy dropdown to these values.")
1983
+ comment_disabled: bool = Field(..., alias="commentDisabled", description="If true, the creator has disabled comments in their app settings — grey out the Allow Comment toggle.")
1984
+ duet_disabled: bool = Field(..., alias="duetDisabled", description="If true, the creator has disabled duet in their app settings — grey out the Allow Duet toggle.")
1985
+ stitch_disabled: bool = Field(..., alias="stitchDisabled", description="If true, the creator has disabled stitch in their app settings — grey out the Allow Stitch toggle.")
1986
+ max_video_post_duration_sec: float = Field(..., alias="maxVideoPostDurationSec", description="Maximum video duration (in seconds) this creator may post. Reject videos longer than this before upload.")
1987
+
1988
+
1989
+ class GetTikTokCreatorInfoResponse(BaseModel):
1990
+ """Default Response"""
1991
+
1992
+ success: bool
1993
+ data: Optional[GetTikTokCreatorInfoData] = None
1994
+ error: Optional[str] = None
1995
+
1996
+
1997
+ class AiWriteContentPlatforms(str, Enum):
1998
+ TWITTER = "twitter"
1999
+ INSTAGRAM = "instagram"
2000
+ YOUTUBE = "youtube"
2001
+ TIKTOK = "tiktok"
2002
+ PINTEREST = "pinterest"
2003
+ LINKEDIN = "linkedin"
2004
+ BLUESKY = "bluesky"
2005
+ FACEBOOK = "facebook"
2006
+ THREADS = "threads"
2007
+ GOOGLEBUSINESS = "googlebusiness"
2008
+
2009
+
2010
+ class AiWriteContentBody(BaseModel):
2011
+ description: Annotated[str, Field(min_length=3, max_length=1500)] = Field(..., description="Free-form description of what the post should be about, in the creator's own words.")
2012
+ platforms: Optional[list[AiWriteContentPlatforms]] = Field(default=None, description="Platforms this post will target. Used to fit the strictest character limit.")
2013
+ existing_content: Optional[str] = Field(default=None, alias="existingContent", description="Optional existing draft to rewrite/improve rather than start from scratch.")
2014
+
2015
+
2016
+ class AiWriteContentResponse(BaseModel):
2017
+ """Default Response"""
2018
+
2019
+ success: bool
2020
+ content: str
2021
+ credits_charged: float = Field(..., alias="creditsCharged")
2022
+
2023
+
2024
+ class AiGenerateImageAspectRatio(str, Enum):
2025
+ """Output aspect ratio. Defaults to square when omitted."""
2026
+
2027
+ SQUARE = "square"
2028
+ VERTICAL = "vertical"
2029
+ LANDSCAPE = "landscape"
2030
+
2031
+
2032
+ class AiGenerateImageStyle(str, Enum):
2033
+ """Visual style preset. Adds style guidance to the prompt. Omit for the model to pick whatever fits the brief."""
2034
+
2035
+ PHOTO = "photo"
2036
+ ILLUSTRATION = "illustration"
2037
+ MINIMAL = "minimal"
2038
+ VIBRANT = "vibrant"
2039
+ CINEMATIC = "cinematic"
2040
+ _3D_RENDER = "3d-render"
2041
+ RETRO = "retro"
2042
+ HAND_DRAWN = "hand-drawn"
2043
+
2044
+
2045
+ class AiGenerateImageBody(BaseModel):
2046
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
2047
+ description: Annotated[str, Field(min_length=3, max_length=1500)]
2048
+ aspect_ratio: Optional[AiGenerateImageAspectRatio] = Field(default=None, alias="aspectRatio", description="Output aspect ratio. Defaults to square when omitted.")
2049
+ style: Optional[AiGenerateImageStyle] = Field(default=None, description="Visual style preset. Adds style guidance to the prompt. Omit for the model to pick whatever fits the brief.")
2050
+ reference_image_urls: Optional[Annotated[list[AnyUrl], Field(max_length=4)]] = Field(default=None, alias="referenceImageUrls", description='Reference images. Used as style/vibe inspiration ONLY. The model will not copy them. Useful for "match my brand look" or "same composition as this".')
2051
+ asset_image_urls: Optional[Annotated[list[AnyUrl], Field(max_length=4)]] = Field(default=None, alias="assetImageUrls", description="Asset images that MUST appear in the generated image (e.g. a brand logo, a specific product photo). The model will place them faithfully according to the brief, without redrawing them.")
2052
+ reference_image_url: Optional[AnyUrl] = Field(default=None, alias="referenceImageUrl", description="DEPRECATED: use referenceImageUrls instead. Still accepted for backwards compatibility.")
2053
+
2054
+
2055
+ class AiGenerateImageResponse(BaseModel):
2056
+ """Default Response"""
2057
+
2058
+ success: bool
2059
+ url: AnyUrl
2060
+ mime_type: str = Field(..., alias="mimeType")
2061
+ credits_charged: float = Field(..., alias="creditsCharged")