diff --git a/README.md b/README.md index 50b5bf6..4aab69e 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,7 @@ long failed = client.posts().stream(PostListParams.create().workspaceId(workspac | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `posts()` | `list`, `autoPaginate`, `stream`, `get`, `create`, `update`, `delete`, `duplicate`, `publish`, `retry`, `cancel`, `preflight`, `deliveries`, `publishRuns`, `analytics`, `bulkShift`, `bulkLabel`, `bulkDelete`, `validateImport`, `commitImport`, `rollbackImport` | | `workspaces()` | `list`, `get`, `create`, `update`, `delete`, `analytics` | -| `accounts()` | `list`, `get`, `create`, `rename`, `move`, `delete`, `healthSummary`, `health`, `togglePrimary`, `validate`, `refreshToken`, `analytics`, `createTelegramConnectCode`, `getTelegramConnectStatus`, `getTelegramBotCommands`, `setTelegramBotCommands`, `deleteTelegramBotCommands`, `listSlackChannels`, `listSlackMembers`, `getSlackIdentity`, `updateSlackIdentity`, `getIceBreakers`, `setIceBreakers`, `deleteIceBreakers`, `getPersistentMenu`, `setPersistentMenu`, `deletePersistentMenu`, `getGreeting`, `setGreeting`, `deleteGreeting`, `getWebhookSubscription`, `resubscribeWebhook`, `communities()`, `listDiscordChannels`, `switchDiscordChannel`, `getDiscordIdentity`, `updateDiscordIdentity`, `listDiscordPins`, `deleteDiscordMessage`, `pinDiscordMessage`, `unpinDiscordMessage`, `crosspostDiscordMessage`, `createDiscordThread`, `sendDiscordDm`, `listDiscordEvents`, `getDiscordEvent`, `createDiscordEvent`, `updateDiscordEvent`, `deleteDiscordEvent`, `listDiscordMembers`, `getDiscordMember`, `listDiscordRoles`, `createDiscordRole`, `updateDiscordRole`, `deleteDiscordRole`, `addDiscordMemberRole`, `removeDiscordMemberRole`, `platformMetrics` | +| `accounts()` | `list`, `get`, `create`, `rename`, `move`, `delete`, `healthSummary`, `health`, `togglePrimary`, `validate`, `refreshToken`, `analytics`, `createTelegramConnectCode`, `getTelegramConnectStatus`, `getTelegramBotCommands`, `setTelegramBotCommands`, `deleteTelegramBotCommands`, `redditSubreddits`, `redditSubredditRules`, `redditFlairs`, `setRedditDefaultSubreddit`, `listSlackChannels`, `listSlackMembers`, `getSlackIdentity`, `updateSlackIdentity`, `getIceBreakers`, `setIceBreakers`, `deleteIceBreakers`, `getPersistentMenu`, `setPersistentMenu`, `deletePersistentMenu`, `getGreeting`, `setGreeting`, `deleteGreeting`, `getWebhookSubscription`, `resubscribeWebhook`, `communities()`, `listDiscordChannels`, `switchDiscordChannel`, `getDiscordIdentity`, `updateDiscordIdentity`, `listDiscordPins`, `deleteDiscordMessage`, `pinDiscordMessage`, `unpinDiscordMessage`, `crosspostDiscordMessage`, `createDiscordThread`, `sendDiscordDm`, `listDiscordEvents`, `getDiscordEvent`, `createDiscordEvent`, `updateDiscordEvent`, `deleteDiscordEvent`, `listDiscordMembers`, `getDiscordMember`, `listDiscordRoles`, `createDiscordRole`, `updateDiscordRole`, `deleteDiscordRole`, `addDiscordMemberRole`, `removeDiscordMemberRole`, `platformMetrics` | | `accountGroups()` | `list`, `get`, `create`, `update`, `delete`, `setMembers` | | `labels()` | `list`, `get`, `create`, `update`, `delete` | | `webhooks()` | `list`, `create`, `update`, `delete`, `test`, `verify` | @@ -108,19 +108,19 @@ long failed = client.posts().stream(PostListParams.create().workspaceId(workspac | `automations()` | `list`, `get`, `create`, `update`, `delete`, `toggle`, `runs`, `run`, `trigger`, `stats` | | `media()` | `list`, `limits`, `upload`, `presign`, `complete`, `uploadDirect`, `delete` | | `ai()` | `credits`, `generateCaption`, `rewrite`, `repurposeUrl` | -| `inbox()` | `list`, `threads`, `conversations`, `unreadCount`, `accounts`, `platforms`, `markThreadRead`, `markConversationRead`, `refresh`, `update`, `editComment`, `reply`, `hide`, `unhide`, `delete`, `like`, `unlike`, `pin`, `unpin`, `react`, `startConversation`, `setTyping`, `passThreadControl`, `takeThreadControl`, `handover`, `listApprovals`, `approveReply`, `rejectReply` | +| `inbox()` | `list`, `threads`, `conversations`, `unreadCount`, `accounts`, `platforms`, `markThreadRead`, `markConversationRead`, `refresh`, `update`, `editComment`, `reply`, `hide`, `unhide`, `delete`, `like`, `unlike`, `vote`, `pin`, `unpin`, `react`, `startConversation`, `setTyping`, `passThreadControl`, `takeThreadControl`, `handover`, `listApprovals`, `approveReply`, `rejectReply` | | `contacts()` | `list`, `get`, `create`, `update`, `delete`, `conversations`, `importCsv`, `listFields`, `createField`, `updateField`, `updateFieldOptions`, `deleteField`, `conversationAnalytics` | | `broadcasts()` | `list`, `get`, `create`, `update`, `delete`, `send`, `cancel`, `recipients` | | `sequences()` | `list`, `get`, `create`, `update`, `delete`, `enroll`, `unenroll`, `enrollments` | | `knowledge()` | `list`, `create`, `createText`, `createUrl`, `createFile`, `update`, `delete`, `sync`, `search` | | `ads()` | `list`, `external`, `boostable`, `connections`, `sources`, `authorizeMeta`, `deleteConnection`, `boost`, `create`, `refresh`, `setStatus`, `delete`, `accountTree`, `createCampaign`, `campaign`, `updateCampaign`, `deleteCampaign`, `duplicateCampaign`, `createAdSet`, `adSet`, `updateAdSet`, `deleteAdSet`, `duplicateAdSet`, `createNetworkAd`, `networkAd`, `updateNetworkAd`, `deleteNetworkAd`, `duplicateNetworkAd`, `bulkSetStatus`, `creatives`, `createCreative`, `creative`, `deleteCreative`, `estimateReach`, `insights`, `adInsights`, `audiences`, `createAudience`, `audience`, `updateAudience`, `deleteAudience`, `addAudienceUsers`, `searchTargeting`, `leadForms`, `createLeadForm`, `leadForm`, `archiveLeadForm`, `leads`, `leadsFeed`, `leadPages`, `subscribeLeadPage`, `unsubscribeLeadPage`, `goals`, `catalogs`, `createCatalog`, `catalog`, `updateCatalog`, `deleteCatalog`, `catalogProducts`, `writeCatalogProducts`, `productFeeds`, `createProductFeed`, `deleteProductFeed`, `feedUploads`, `startFeedUpload`, `productSets`, `createProductSet`, `updateProductSet`, `deleteProductSet`, `reachFrequency`, `createReachFrequency`, `reachFrequencyPrediction`, `reserveReachFrequency`, `cancelReachFrequency`, `library`, `partnershipCreators`, `requestPartnership`, `revokePartnership`, `accountActivity`, `labels`, `createLabel`, `updateLabel`, `deleteLabel`, `applyLabel`, `studies`, `createStudy`, `study`, `deleteStudy`, `iosCampaignLimits`, `highDemandPeriods`, `createHighDemandPeriod`, `deleteHighDemandPeriod`, `valueRuleSets`, `createValueRuleSet`, `deleteValueRuleSet` | -| `inbox()` | `list`, `threads`, `conversations`, `unreadCount`, `accounts`, `platforms`, `markThreadRead`, `markConversationRead`, `refresh`, `update`, `editComment`, `reply`, `hide`, `unhide`, `delete`, `like`, `unlike`, `pin`, `unpin`, `react`, `startConversation`, `setTyping`, `listApprovals`, `approveReply`, `rejectReply` | +| `inbox()` | `list`, `threads`, `conversations`, `unreadCount`, `accounts`, `platforms`, `markThreadRead`, `markConversationRead`, `refresh`, `update`, `editComment`, `reply`, `hide`, `unhide`, `delete`, `like`, `unlike`, `vote`, `pin`, `unpin`, `react`, `startConversation`, `setTyping`, `listApprovals`, `approveReply`, `rejectReply` | | `ads()` | `list`, `external`, `boostable`, `connections`, `sources`, `authorizeMeta`, `deleteConnection`, `boost`, `create`, `refresh`, `setStatus`, `delete`, `accountTree`, `createCampaign`, `campaign`, `updateCampaign`, `deleteCampaign`, `duplicateCampaign`, `createAdSet`, `adSet`, `updateAdSet`, `deleteAdSet`, `duplicateAdSet`, `createNetworkAd`, `networkAd`, `updateNetworkAd`, `deleteNetworkAd`, `duplicateNetworkAd`, `bulkSetStatus`, `creatives`, `createCreative`, `creative`, `deleteCreative`, `estimateReach`, `insights`, `adInsights`, `audiences`, `createAudience`, `audience`, `updateAudience`, `deleteAudience`, `addAudienceUsers`, `searchTargeting`, `leadForms`, `createLeadForm`, `leadForm`, `archiveLeadForm`, `leads`, `leadsFeed`, `leadPages`, `subscribeLeadPage`, `unsubscribeLeadPage` | | `whatsapp()` | `getProfile`, `updateProfile`, `requestDisplayName`, `setUsername`, `listTemplates`, `listTemplateLibrary`, `getTemplate`, `createTemplate`, `importTemplate`, `updateTemplate`, `deleteTemplate`, `listGroups`, `createGroup`, `getGroup`, `updateGroup`, `deleteGroup`, `getGroupInviteLink`, `resetGroupInviteLink`, `removeGroupParticipants`, `listBlocked`, `blockUsers`, `unblockUsers`, `getCommerceSettings`, `updateCommerceSettings`, `linkCatalog`, `listFlows`, `getFlow`, `createFlow`, `updateFlow`, `deleteFlow`, `uploadFlowJson`, `publishFlow`, `deprecateFlow`, `listFlowResponses`, `getEncryptionKeyStatus`, `setEncryptionKey`, `getAccountEvents`, `listSandboxSessions`, `createSandboxSession` | | `ads()` | `list`, `external`, `boostable`, `connections`, `sources`, `providers`, `authorize`, `deleteConnection`, `boost`, `create`, `refresh`, `setStatus`, `delete`, `accountTree`, `createCampaign`, `campaign`, `updateCampaign`, `deleteCampaign`, `duplicateCampaign`, `createAdSet`, `adSet`, `updateAdSet`, `deleteAdSet`, `duplicateAdSet`, `createNetworkAd`, `networkAd`, `updateNetworkAd`, `deleteNetworkAd`, `duplicateNetworkAd`, `bulkSetStatus`, `creatives`, `createCreative`, `creative`, `deleteCreative`, `estimateReach`, `insights`, `adInsights`, `audiences`, `createAudience`, `audience`, `updateAudience`, `deleteAudience`, `addAudienceUsers`, `addAudienceCompanies`, `searchTargeting`, `leadForms`, `createLeadForm`, `leadForm`, `archiveLeadForm`, `leads`, `leadsFeed`, `leadPages`, `subscribeLeadPage`, `unsubscribeLeadPage`, `bidPricing`, `supplyForecast`, `conversionRules`, `createConversionRule`, `conversionRule`, `updateConversionRule`, `deleteConversionRule`, `attachConversionRule`, `detachConversionRule`, `conversionMetrics`, `sendConversionEvents` | | `googleAds()` | `recommendations`, `optimizationScore`, `applyRecommendations`, `dismissRecommendations`, `keywords`, `createKeyword`, `updateKeyword`, `deleteKeyword`, `keywordIdeas`, `keywordMetrics`, `searchTerms`, `bidStrategies`, `createBidStrategy`, `adSchedule`, `setAdSchedule`, `negativeKeywordLists`, `createNegativeKeywordList`, `addNegativeKeywords`, `attachNegativeKeywordList`, `assets`, `createAsset`, `attachAsset`, `deleteAsset`, `assetGroups`, `createAssetGroup`, `updateAssetGroup`, `deleteAssetGroup`, `localServicesLeads`, `conversionActions`, `createConversionAction`, `uploadConversions`, `uploadConversionAdjustments`, `query` | | `googleBusiness()` | `getLocation`, `updateLocation`, `getAttributes`, `updateAttributes`, `getMenus`, `replaceMenus`, `getServices`, `replaceServices`, `listMedia`, `addMedia`, `deleteMedia`, `listPlaceActions`, `createPlaceAction`, `updatePlaceAction`, `deletePlaceAction`, `getVerificationOptions`, `startVerification`, `completeVerification`, `getPerformance`, `getSearchKeywords`, `assign` | -| `validate()` | `post`, `length`, `media` | +| `validate()` | `post`, `length`, `media`, `subreddit` | | `activity()` | `list` | `accounts().communities()` covers the X communities an account can post into: `list`, `sync`, diff --git a/src/main/java/com/fopost/sdk/model/Account.java b/src/main/java/com/fopost/sdk/model/Account.java index 8708d18..416f965 100644 --- a/src/main/java/com/fopost/sdk/model/Account.java +++ b/src/main/java/com/fopost/sdk/model/Account.java @@ -6,8 +6,11 @@ * A connected social account. * *
Named {@code Account} for the platform account, not the billing account. Which fields - * arrive depends on the endpoint: the list gives health and primary state, the detail gives - * timestamps and the owning workspace. {@code name} is the display name when one is set, and + * arrive depends on the endpoint: the list gives health, primary state and + * {@code reconnectRequired}, the detail gives timestamps and the owning workspace. + * + *
{@code reconnectRequired} is true when the account was connected before a permission it + * now needs was asked for; reconnecting it is the fix. {@code name} is the display name when one is set, and * {@code platformName} is always the name from the platform. */ public record Account( diff --git a/src/main/java/com/fopost/sdk/model/InboxItem.java b/src/main/java/com/fopost/sdk/model/InboxItem.java index 3f5660a..f358909 100644 --- a/src/main/java/com/fopost/sdk/model/InboxItem.java +++ b/src/main/java/com/fopost/sdk/model/InboxItem.java @@ -41,10 +41,12 @@ public record InboxItem( Boolean canHide, Boolean canDelete, Boolean liked, + String vote, Boolean pinned, String reaction, Instant editedAt, Boolean canLike, + Boolean canVote, Boolean canPin, Boolean canEdit, Boolean canReact, diff --git a/src/main/java/com/fopost/sdk/model/RedditDefaultSubreddit.java b/src/main/java/com/fopost/sdk/model/RedditDefaultSubreddit.java new file mode 100644 index 0000000..455e788 --- /dev/null +++ b/src/main/java/com/fopost/sdk/model/RedditDefaultSubreddit.java @@ -0,0 +1,8 @@ +package com.fopost.sdk.model; + +/** + * Where posts from a Reddit account go when a post names no subreddit. + * + *
A null {@code subreddit} means the account's own profile page, which always accepts a post. + */ +public record RedditDefaultSubreddit(String subreddit) {} diff --git a/src/main/java/com/fopost/sdk/model/RedditFlair.java b/src/main/java/com/fopost/sdk/model/RedditFlair.java new file mode 100644 index 0000000..acd4f26 --- /dev/null +++ b/src/main/java/com/fopost/sdk/model/RedditFlair.java @@ -0,0 +1,8 @@ +package com.fopost.sdk.model; + +/** + * A post flair, valid only in the subreddit it came from. + * + *
{@code editable} means the label may be replaced with your own text.
+ */
+public record RedditFlair(String id, String text, Boolean editable) {}
diff --git a/src/main/java/com/fopost/sdk/model/RedditFlairs.java b/src/main/java/com/fopost/sdk/model/RedditFlairs.java
new file mode 100644
index 0000000..710d320
--- /dev/null
+++ b/src/main/java/com/fopost/sdk/model/RedditFlairs.java
@@ -0,0 +1,6 @@
+package com.fopost.sdk.model;
+
+import java.util.List;
+
+/** The post flairs one subreddit offers. */
+public record RedditFlairs(String subreddit, List {@code name} carries no {@code r/} prefix. {@code canPost} is false where the account may
+ * read but not submit, and {@code isDefault} marks where posts go when a post names no subreddit.
+ */
+public record RedditSubreddit(
+ String name,
+ String title,
+ Long subscribers,
+ Boolean over18,
+ Boolean canPost,
+ Boolean flairEnabled,
+ String iconUrl,
+ Boolean isDefault) {}
diff --git a/src/main/java/com/fopost/sdk/model/RedditSubredditRule.java b/src/main/java/com/fopost/sdk/model/RedditSubredditRule.java
new file mode 100644
index 0000000..e9ebc28
--- /dev/null
+++ b/src/main/java/com/fopost/sdk/model/RedditSubredditRule.java
@@ -0,0 +1,4 @@
+package com.fopost.sdk.model;
+
+/** One rule a subreddit publishes. {@code appliesTo} is {@code link}, {@code comment} or {@code all}. */
+public record RedditSubredditRule(String name, String description, String appliesTo) {}
diff --git a/src/main/java/com/fopost/sdk/model/RedditSubredditRules.java b/src/main/java/com/fopost/sdk/model/RedditSubredditRules.java
new file mode 100644
index 0000000..d5028fd
--- /dev/null
+++ b/src/main/java/com/fopost/sdk/model/RedditSubredditRules.java
@@ -0,0 +1,6 @@
+package com.fopost.sdk.model;
+
+import java.util.List;
+
+/** A subreddit's rules, in its own order. Show them before publishing. */
+public record RedditSubredditRules(String subreddit, List {@code ok} is true when both hold. A private, banned or missing subreddit answers 200 with
+ * {@code exists} false rather than an error.
+ */
+public record SubredditCheck(
+ String subreddit,
+ Boolean exists,
+ Boolean canPost,
+ // Neither the snake strategy nor the camel alias covers a digit boundary.
+ @JsonAlias("over_18") Boolean over18,
+ Boolean flairEnabled,
+ Boolean ok) {}
diff --git a/src/main/java/com/fopost/sdk/resource/AccountsResource.java b/src/main/java/com/fopost/sdk/resource/AccountsResource.java
index 05fa483..dbb7728 100644
--- a/src/main/java/com/fopost/sdk/resource/AccountsResource.java
+++ b/src/main/java/com/fopost/sdk/resource/AccountsResource.java
@@ -32,6 +32,10 @@
import com.fopost.sdk.model.InstagramStoryInsights;
import com.fopost.sdk.model.LinkedInMention;
import com.fopost.sdk.model.PinterestBoard;
+import com.fopost.sdk.model.RedditDefaultSubreddit;
+import com.fopost.sdk.model.RedditFlairs;
+import com.fopost.sdk.model.RedditSubreddit;
+import com.fopost.sdk.model.RedditSubredditRules;
import com.fopost.sdk.model.SlackChannel;
import com.fopost.sdk.model.SlackIdentity;
import com.fopost.sdk.model.SlackMember;
@@ -554,6 +558,47 @@ private DiscordAck ack(JsonNode body) {
return http.convert(ApiClient.unwrap(body), DiscordAck.class);
}
+ /**
+ * Subreddits a Reddit account is in, busiest first, plus its own profile page.
+ *
+ * A 409 with code {@code reconnect_required} means the grant is short of a permission
+ * this read needs, and the account has to be reconnected.
+ */
+ public List The check runs with that account's own token, so {@code accountId} is required.
+ */
+ public SubredditCheck subreddit(String accountId, String name) {
+ Map