From ade3dd69b2274696cf11b02db6b1c4ee2331e0a3 Mon Sep 17 00:00:00 2001 From: Rajeh Taher Date: Sat, 26 Sep 2026 23:06:34 +0200 Subject: [PATCH 1/3] Add typed raw WABA marketing status read --- README.md | 3 +- contracts/cloud-api-supplements.json | 8 ++++ .../2026-09-26-marketing-status-consumer.md | 23 ++++++++++ packages/typescript/README.md | 7 +++ packages/typescript/src/index.ts | 2 + packages/typescript/src/messaging/client.ts | 3 ++ .../src/messaging/cloud-marketing.ts | 45 +++++++++++++++++++ 7 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 docs/internal/2026-09-26-marketing-status-consumer.md create mode 100644 packages/typescript/src/messaging/cloud-marketing.ts diff --git a/README.md b/README.md index 6801b69c..d20796e5 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ browser runtime, shared UI contracts, Web Components, React bindings, thin Next.js server helpers, and a production-gated developer assistant. The exact Messaging and Platform sources are pinned in `contracts/source.json`; pending Official API, Flows and catalog dependencies are recorded in `contracts/cloud-api-supplements.json`. Full Graph API parity -is outside this SDK's scope; `cloudCatalogs.list` and `flowEncryption` provide +is outside this SDK's scope; `cloudCatalogs`, `cloudMarketing.status`, and `flowEncryption` provide typed clients for their respective Graph resources. The API includes an enrolled hosted message history beta. @@ -138,6 +138,7 @@ The handwritten Messaging resources in this milestone are: - `cloudTemplates`: list, retrieve, create, edit and delete Meta templates for a Number with an Official API connection; separate from project template drafts - `cloudCatalogs`: read WABA product-catalog links through the Graph facade +- `cloudMarketing`: read Meta's raw WABA Marketing Messages status strings without interpreting eligibility - `flowEncryption`: read or register a public Flow encryption key for one Meta phone number - `business`: manage the connected Business App profile, commerce catalog, products, collections, orders, compliance, linked accounts, and eligibility diff --git a/contracts/cloud-api-supplements.json b/contracts/cloud-api-supplements.json index 429c69b0..fe1570e1 100644 --- a/contracts/cloud-api-supplements.json +++ b/contracts/cloud-api-supplements.json @@ -145,6 +145,14 @@ "sha256": "b9d3778f17a90fd0c58e0cb1b3f6ef689661980fa83ad7565bc55ae4ab93fab4", "operationIds": ["graphListCatalogProducts"], "merged": false + }, + { + "pullRequest": "https://github.com/polymorfa/polymorfa/pull/383", + "commit": "1e1d613de599c2b4334f8de81fab087c74f31424", + "sourcePath": "docs/api-reference/openapi.graph.json", + "sha256": "1270c8fb32a09cb717f3ea8edd6bd657e8ff3110e03a6286e68d5e16affff474", + "operationIds": ["graphGetMarketingStatus"], + "merged": false } ] } diff --git a/docs/internal/2026-09-26-marketing-status-consumer.md b/docs/internal/2026-09-26-marketing-status-consumer.md new file mode 100644 index 00000000..d2e3aeef --- /dev/null +++ b/docs/internal/2026-09-26-marketing-status-consumer.md @@ -0,0 +1,23 @@ +# Raw Marketing Messages WABA status consumer + +`MessagingClient.cloudMarketing.status` consumes Polymorfa API PR #383 at +`1e1d613de599c2b4334f8de81fab087c74f31424`, with Graph OpenAPI copy +`docs/api-reference/openapi.graph.json` SHA-256 +`1270c8fb32a09cb717f3ea8edd6bd657e8ff3110e03a6286e68d5e16affff474`. +The exact operation is `graphGetMarketingStatus`. It reads raw optional WABA +status strings and preserves the API's Graph error behavior. No status value is +mapped to accepted terms, eligibility, insight availability, or a send decision. + +API: implemented in the separate source PR, not merged or deployed by this SDK +change. SDKs: TypeScript server Messaging resource and public type updated; +other language clients in this workspace do not expose this Graph facade +resource and remain unaffected by the current contract. CLI: companion +read-only command is stacked separately and needs a published SDK artifact. +Docs: this SDK's overview and TypeScript page are updated; API public method +documentation remains in the API PR. Feature release: the existing Graph beta +gate is unchanged; installed SDK code is not customer availability. Admin: +no capability or staff state changes. + +No tests, typechecks, builds, documentation checks or live Meta calls were run +at the user's request. Publication, exact package integrity, CLI pin, and live +account acceptance remain separate gates. diff --git a/packages/typescript/README.md b/packages/typescript/README.md index b24f1e3c..c6c1391a 100644 --- a/packages/typescript/README.md +++ b/packages/typescript/README.md @@ -394,6 +394,13 @@ from a catalog linked to that WABA. It has the same server-credential and to request the next page. The API rejects catalogs it cannot verify as linked; listing products does not grant permission to send them. +`messaging.cloudMarketing.status(wabaId, { version: "v26.0" })` reads Meta's +raw `marketing_messages_lite_api_status` and +`marketing_messages_onboarding_status` strings through an Official API Number +in the credential's project. It requires `sessions:read` and an organization +API key or project token. The fields do not establish terms acceptance, +recipient permission, eligibility, or permission to send. + `messaging.flowEncryption.retrieve(phoneNumberId, { version: "v26.0" })` reads the registered public key and Meta signature status with `sessions:read`. `messaging.flowEncryption.register(phoneNumberId, diff --git a/packages/typescript/src/index.ts b/packages/typescript/src/index.ts index 6fb4473f..ddb473c5 100644 --- a/packages/typescript/src/index.ts +++ b/packages/typescript/src/index.ts @@ -61,6 +61,8 @@ export { } from "./errors.js"; export { MessagingClient } from "./messaging/client.js"; export { CloudCatalogsResource } from "./messaging/cloud-catalogs.js"; +export { CloudMarketingResource } from "./messaging/cloud-marketing.js"; +export type { CloudMarketingStatus, GetCloudMarketingStatusParams } from "./messaging/cloud-marketing.js"; export { FlowEncryptionResource } from "./messaging/flow-encryption.js"; export type { FlowEncryptionKey, diff --git a/packages/typescript/src/messaging/client.ts b/packages/typescript/src/messaging/client.ts index 2d8b3d7c..5c33b1ee 100644 --- a/packages/typescript/src/messaging/client.ts +++ b/packages/typescript/src/messaging/client.ts @@ -30,6 +30,7 @@ import { SessionsResource } from "./sessions.js"; import { TemplatesResource } from "./templates.js"; import { CloudTemplatesResource } from "./cloud-templates.js"; import { CloudCatalogsResource } from "./cloud-catalogs.js"; +import { CloudMarketingResource } from "./cloud-marketing.js"; import { FlowEncryptionResource } from "./flow-encryption.js"; import { UsersResource } from "./users.js"; import { VoipResource } from "./voip.js"; @@ -62,6 +63,7 @@ export class MessagingClient { readonly templates: TemplatesResource; readonly cloudTemplates: CloudTemplatesResource; readonly cloudCatalogs: CloudCatalogsResource; + readonly cloudMarketing: CloudMarketingResource; readonly flowEncryption: FlowEncryptionResource; readonly users: UsersResource; readonly voip: VoipResource; @@ -110,6 +112,7 @@ export class MessagingClient { this.templates = new TemplatesResource(transport); this.cloudTemplates = new CloudTemplatesResource(transport); this.cloudCatalogs = new CloudCatalogsResource(transport, credential.type); + this.cloudMarketing = new CloudMarketingResource(transport, credential.type); this.flowEncryption = new FlowEncryptionResource( transport, credential.type, diff --git a/packages/typescript/src/messaging/cloud-marketing.ts b/packages/typescript/src/messaging/cloud-marketing.ts new file mode 100644 index 00000000..47bf24ee --- /dev/null +++ b/packages/typescript/src/messaging/cloud-marketing.ts @@ -0,0 +1,45 @@ +import type { MessagingCredential } from "../credentials.js"; +import { PolymorfaConfigurationError } from "../errors.js"; +import { HttpTransport } from "../transport/http.js"; +import type { ApiResponse, RequestOptions } from "../transport/types.js"; + +/** Meta WABA observations. Neither string is an eligibility or terms grant. */ +export interface CloudMarketingStatus { + readonly id: string; + readonly marketing_messages_lite_api_status?: string; + readonly marketing_messages_onboarding_status?: string; +} + +export interface GetCloudMarketingStatusParams { + /** Meta Graph version, for example v26.0. */ + readonly version: string; +} + +export class CloudMarketingResource { + constructor( + private readonly transport: HttpTransport, + private readonly credentialType: MessagingCredential["type"], + ) {} + + /** Read raw WABA status fields through a project-owned Official API Number. */ + status( + wabaId: string, + params: GetCloudMarketingStatusParams, + options: RequestOptions = {}, + ): Promise> { + if (this.credentialType === "clientToken") { + throw new PolymorfaConfigurationError( + "Official API marketing status requires an organization API key or project token.", + "credential", + ); + } + if (!wabaId.trim() || !params.version.trim()) { + throw new PolymorfaConfigurationError("Provide a WABA ID and Graph version."); + } + return this.transport.request({ + method: "GET", + path: `/graph/whatsapp/${encodeURIComponent(params.version)}/${encodeURIComponent(wabaId)}/marketing_messages/status`, + ...options, + }); + } +} From 15ec1e75b1dd8e83aed19b91c605423f51d1a116 Mon Sep 17 00:00:00 2001 From: Rajeh Taher Date: Sat, 26 Sep 2026 23:29:43 +0200 Subject: [PATCH 2/3] style(sdk): format Cloud marketing resource --- packages/typescript/src/messaging/client.ts | 5 ++++- packages/typescript/src/messaging/cloud-marketing.ts | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/typescript/src/messaging/client.ts b/packages/typescript/src/messaging/client.ts index 5c33b1ee..288b1ec8 100644 --- a/packages/typescript/src/messaging/client.ts +++ b/packages/typescript/src/messaging/client.ts @@ -112,7 +112,10 @@ export class MessagingClient { this.templates = new TemplatesResource(transport); this.cloudTemplates = new CloudTemplatesResource(transport); this.cloudCatalogs = new CloudCatalogsResource(transport, credential.type); - this.cloudMarketing = new CloudMarketingResource(transport, credential.type); + this.cloudMarketing = new CloudMarketingResource( + transport, + credential.type, + ); this.flowEncryption = new FlowEncryptionResource( transport, credential.type, diff --git a/packages/typescript/src/messaging/cloud-marketing.ts b/packages/typescript/src/messaging/cloud-marketing.ts index 47bf24ee..33ffc43d 100644 --- a/packages/typescript/src/messaging/cloud-marketing.ts +++ b/packages/typescript/src/messaging/cloud-marketing.ts @@ -34,7 +34,9 @@ export class CloudMarketingResource { ); } if (!wabaId.trim() || !params.version.trim()) { - throw new PolymorfaConfigurationError("Provide a WABA ID and Graph version."); + throw new PolymorfaConfigurationError( + "Provide a WABA ID and Graph version.", + ); } return this.transport.request({ method: "GET", From 7f8585b4260c509e8d330d59de9e2646abf7f625 Mon Sep 17 00:00:00 2001 From: Rajeh Taher Date: Thu, 1 Oct 2026 15:35:12 +0300 Subject: [PATCH 3/3] Format SDK exports --- packages/typescript/src/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/typescript/src/index.ts b/packages/typescript/src/index.ts index 8927c7d5..6be63753 100644 --- a/packages/typescript/src/index.ts +++ b/packages/typescript/src/index.ts @@ -62,7 +62,10 @@ export { export { MessagingClient } from "./messaging/client.js"; export { CloudCatalogsResource } from "./messaging/cloud-catalogs.js"; export { CloudMarketingResource } from "./messaging/cloud-marketing.js"; -export type { CloudMarketingStatus, GetCloudMarketingStatusParams } from "./messaging/cloud-marketing.js"; +export type { + CloudMarketingStatus, + GetCloudMarketingStatusParams, +} from "./messaging/cloud-marketing.js"; export { FlowEncryptionResource } from "./messaging/flow-encryption.js"; export type { FlowEncryptionKey,