Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@ All notable changes to this project are documented here. The format follows

### Added

- `whatsapp()` for a WhatsApp Business connection: the business profile
(`getProfile`, `updateProfile`, `requestDisplayName`, `setUsername`), message
templates including the platform's own library (`listTemplates`,
`createTemplate`, `importTemplate`, …), groups, blocking, commerce settings and
flows (`createFlow`, `uploadFlowJson`, `publishFlow`, `listFlowResponses`, …),
plus `getAccountEvents`. All need the `accounts` scope.
- `whatsapp().createSandboxSession` and `listSandboxSessions` invite a tester to
the platform-owned WhatsApp test number. Inviting sends a template, so it needs
the `publish` scope.
- `Platforms.WHATSAPP`.
- `blog()`: articles for a website. `getSettings`, `updateSettings`, `rotateWebsiteSecret`
and `testWebsite`; `listKeywords`, `planKeywords`, `addKeyword`, `updateKeyword` and
`deleteKeyword`; `listArticles`, `requestArticle`, `getArticle`, `updateArticle`,
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ long failed = client.posts().stream(PostListParams.create().workspaceId(workspac
| `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` |
| `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` |
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/com/fopost/sdk/FoPost.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.fopost.sdk.resource.SequencesResource;
import com.fopost.sdk.resource.ValidateResource;
import com.fopost.sdk.resource.WebhooksResource;
import com.fopost.sdk.resource.WhatsappResource;
import com.fopost.sdk.resource.WorkspacesResource;
import java.time.Duration;
import java.util.Map;
Expand Down Expand Up @@ -80,6 +81,7 @@ public final class FoPost {
private final SequencesResource sequences;
private final ActivityResource activity;
private final GoogleBusinessResource googleBusiness;
private final WhatsappResource whatsapp;
private final InboxResource inbox;
private final AdsResource ads;
private final GoogleAdsResource googleAds;
Expand All @@ -101,6 +103,7 @@ private FoPost(ApiClient http) {
this.automations = new AutomationsResource(http);
this.media = new MediaResource(http);
this.ai = new AiResource(http);
this.whatsapp = new WhatsappResource(http);
this.inbox = new InboxResource(http);
this.contacts = new ContactsResource(http);
this.broadcasts = new BroadcastsResource(http);
Expand Down Expand Up @@ -153,6 +156,11 @@ public WebhooksResource webhooks() {
return webhooks;
}

/** WhatsApp Business: templates, flows, groups, blocking and commerce. */
public WhatsappResource whatsapp() {
return whatsapp;
}

public AnalyticsResource analytics() {
return analytics;
}
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/com/fopost/sdk/model/Platforms.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,11 @@ private Platforms() {}
public static final String WHOP = "whop";
public static final String SKOOL = "skool";

public static final String WHATSAPP = "whatsapp";

public static final List<String> ALL = List.of(
TWITTER, LINKEDIN, FACEBOOK, INSTAGRAM, INSTAGRAM_BUSINESS, TELEGRAM, TWITCH, DISCORD,
SLACK, REDDIT, PINTEREST, SNAPCHAT, TUMBLR, DRIBBBLE, MEWE, TIKTOK, YOUTUBE, BLUESKY, THREADS,
MASTODON, LEMMY, DEVTO, HASHNODE, MEDIUM, SUBSTACK, GOOGLE_BUSINESS, KICK, LISTMONK,
WORDPRESS, NOSTR, WHOP, SKOOL);
WORDPRESS, NOSTR, WHOP, SKOOL, WHATSAPP);
}
6 changes: 6 additions & 0 deletions src/main/java/com/fopost/sdk/model/WhatsappBlockResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.fopost.sdk.model;

import java.util.List;

/** What the platform took and what it refused. */
public record WhatsappBlockResult(List<String> blocked, List<String> unblocked, List<String> failed) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.fopost.sdk.model;

/** Whether the cart and catalog show on the number, and which catalog is linked. */
public record WhatsappCommerceSettings(Boolean cartEnabled, Boolean catalogVisible, String catalogId) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.fopost.sdk.model;

/** Whether a business public key is registered. The key itself never comes back. */
public record WhatsappEncryptionKeyStatus(boolean hasKey, String signatureStatus) {}
16 changes: 16 additions & 0 deletions src/main/java/com/fopost/sdk/model/WhatsappFlow.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.fopost.sdk.model;

import java.time.Instant;
import java.util.List;

/** An in-chat form. The platform validates it and owns its status. */
public record WhatsappFlow(
String id,
String name,
String status,
List<String> categories,
List<WhatsappFlowValidationError> validationErrors,
String endpointUri,
String jsonVersion,
String previewUrl,
Instant previewExpiresAt) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.fopost.sdk.model;

import java.util.List;

/**
* The platform's verdict on an uploaded flow definition. It answers with the
* errors rather than refusing the upload, so they arrive as data.
*/
public record WhatsappFlowJsonResult(boolean success, List<WhatsappFlowValidationError> validationErrors) {}
12 changes: 12 additions & 0 deletions src/main/java/com/fopost/sdk/model/WhatsappFlowResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.fopost.sdk.model;

import java.time.Instant;
import java.util.Map;

/** What one person submitted through a flow. */
public record WhatsappFlowResponse(
String messageId,
String waId,
String flowToken,
Map<String, Object> answers,
Instant respondedAt) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.fopost.sdk.model;

/** One problem the platform found in a flow definition. */
public record WhatsappFlowValidationError(String error, String message) {}
15 changes: 15 additions & 0 deletions src/main/java/com/fopost/sdk/model/WhatsappGroup.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.fopost.sdk.model;

import java.time.Instant;

/**
* A group on the business number. Participation is invite-only: no endpoint adds
* someone, so {@code inviteLink} is how they join.
*/
public record WhatsappGroup(
String id,
String subject,
String description,
Integer participantCount,
String inviteLink,
Instant createdAt) {}
21 changes: 21 additions & 0 deletions src/main/java/com/fopost/sdk/model/WhatsappProfile.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.fopost.sdk.model;

import java.util.List;

/**
* The business profile on a WhatsApp number, plus how the platform rates it.
* {@code displayNameStatus} is the platform's review state for the display name.
*/
public record WhatsappProfile(
String about,
String address,
String description,
String email,
String vertical,
List<String> websites,
String profilePictureUrl,
String displayName,
String displayNameStatus,
String username,
String qualityRating,
String messagingLimitTier) {}
15 changes: 15 additions & 0 deletions src/main/java/com/fopost/sdk/model/WhatsappSandboxSession.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.fopost.sdk.model;

import java.time.Instant;

/**
* A sandbox invitation. Only the last four digits of the tester's number
* travel; the number itself is never stored.
*/
public record WhatsappSandboxSession(
String id,
String status,
String phoneNumberLast4,
Instant invitedAt,
Instant activatedAt,
Instant expiresAt) {}
19 changes: 19 additions & 0 deletions src/main/java/com/fopost/sdk/model/WhatsappTemplate.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.fopost.sdk.model;

import java.util.List;
import java.util.Map;

/**
* A message template. {@code status} is the review outcome the platform
* assigned, passed through unchanged: nothing marks a template approved but the
* platform.
*/
public record WhatsappTemplate(
String id,
String name,
String language,
String category,
String status,
String rejectedReason,
List<Map<String, Object>> components,
String qualityScore) {}
Loading
Loading