Skip to main content
TypeScript SDK covers installation and client setup. The private development repositories contain the TypeScript server SDK and the Polymorfa CLI. They have not been published to npm. Repository access is required for the GitHub installs documented below. Keep Number, user, conversation, and message IDs as strings, including IDs containing only decimal digits. Use the Number’s testMode field to identify Test Numbers; do not infer it from the ID or convert the ID to a JavaScript number. Channel message actions also use the Polymorfa message id. The numeric position returned by channel reads is only a pagination cursor. See Channel messages. API method pages include cURL and SDK preview examples alongside their parameters, responses, and interactive request playground. SDK preview examples show the intended client call, but they are not an installation or release announcement. Use the cURL example for an executable request today.

Do not install unverified names

A package name alone does not prove that Polymorfa publishes or maintains the artifact. Install an SDK only when its exact package name and version appear in the Changelog and this page.
The public PyPI project named polymorfa-sdk is not the Polymorfa WhatsApp SDK. Do not install it for a Polymorfa integration.
Before installing a future SDK release, verify all of the following:
  • The package and version appear in a Polymorfa changelog entry.
  • The registry publisher and repository link point to an official Polymorfa organization.
  • The install name exactly matches the name in these docs.
  • The package version supports the API date you intend to use.

Use the API directly

Organization and project keys may be personal or service-account owned. Both use the same bearer header and support restricted permissions. Organization keys apply their selected permissions across the team and all its projects; project keys remain confined to one project. See key ownership. Keep organization and project credentials on trusted servers. Browser and mobile code must use a short-lived client token limited to the actions it needs. See Authentication for credential audiences and the scope list. Browser-token issuance and session-rule updates require all scopes listed under client token delegation, including when using the VoIP token endpoint. Generated clients should use the documented message-template fields id and createdAt. Machine operation IDs are code-generation details; customer-facing method names and URLs are organized by task in the Guides navigation.

Handle outbound call limits

POST /messaging/voip/calls returns 429 when the source session reaches its outbound-start limit. The limit applies across server keys and client tokens; client-token setup and concurrency limits also apply. Wait until the next minute before retrying a source-session rate-limit refusal. See the Calls guide. For call.ended, SDKs expose from as nullable. It is null when reason is pod_lost, because the lost media host cannot supply an authoritative remote-party identity.

Regenerate Platform API clients

The Platform API now publishes dot-free REST operation identifiers instead of the former internal action identifiers. If you generated a private client from an older Platform OpenAPI document, regenerate it from the latest contract and compile your integration before deploying it. HTTP methods and paths did not change, so match any hand-written wrapper by its HTTP method and path while updating the generated method call. Polymorfa does not retain aliases for the removed identifiers. The testing-number country enum now contains all 243 WhatsApp-supported ISO alpha-2 codes instead of four regional examples. Regenerate a private Platform client so its generated country type matches the expanded request schema. The Platform contract also includes Customer resources and Customer ownership on session rows. Regenerate a private Platform client to receive the customers:read and customers:manage operations, the optional customerId testing-number field, and the nullable customer projection on session responses. This does not change the SDK release status above.

Customers

Install the TypeScript server SDK from its development branch:
Client.customers covers status and enablement, Customer records, assigned Numbers, recent events, pairing links, and Number transfers.
Customer identity uses externalCustomerId; a phone number belongs to a Number or a pairing invitation, not to the Customer profile. The URL is present only on the first successful create response. An idempotent replay returns url: null. customers.list() keeps cursor state under response.data.page. Install the private CLI development branch when you need the same workflow in a terminal:
Customer commands require an organization server key and an explicit project ID. Destructive commands ask for confirmation unless --yes is present.

Channel deletion

No published Polymorfa SDK exposes channel deletion yet. Use a direct DELETE /messaging/{session}/channels/{id} request. The call is synchronous and confirms with { "success": true, "data": { "status": "DELETED" } } rather than a bare success envelope, so a generated client must read data.status instead of treating the response as empty. If you generate a private client from the Messaging API OpenAPI document, the operation ID is deleteChannel. Handle 400 for a malformed or non-channel identifier and 502 for a deletion WhatsApp rejected or could not complete; neither carries upstream error text.

Presence observation

No published Polymorfa SDK exposes presence observation yet. Use direct HTTPS requests. The modes, scopes, and per-session bounds are documented in Linked-device controls. The observation-policy operations and the presence operations take different credentials: A project credential works across the whole presence surface: the operations that set a policy and the operations that policy governs. Client tokens do not use these scopes. A client token carries an empty scope mask and is authorized only by the allowed actions recorded on it, so grant the action rather than the scope: A client token without the matching action receives 403 no matter which scopes the organization credential that minted it holds. Client tokens cannot call the observation-policy operations or set the session’s own presence. Use a Polymorfa conversation ID or an E.164 phone number for the chat identifier. Percent-encode path parameters, including the leading + in phone numbers. Raw WhatsApp JIDs and LIDs are not public conversation identifiers. Encoded path separators %2F and %252F are rejected rather than decoded into a segment boundary, so a client token cannot reach a route its recorded action does not cover. If you generate a private client from the Messaging API OpenAPI document, the operation IDs are getProjectObservationPolicy, updateProjectObservationPolicy, getSessionObservationPolicy, updateSessionObservationPolicy, getPresence, setPresence, getChatPresence, and subscribePresence.

Regenerate clients for the presence types

@polymorfa/types splits the presence contract into two interfaces. The change is not a field rename: each interface now describes a different thing, so regenerate any client built against the previous shape.
  • PresenceData is now only the session’s own presence, returned by GET /messaging/{session}/presence. It carries desired, desiredAt, lastSent, lastSentAt, and authoritative, which is always false because the linked-device protocol has no synchronous server read of the current session presence. Its previous available and lastSeen fields are gone.
  • Contact and chat observation is now ChatPresenceData, returned by GET /messaging/{session}/presence/{chatId}. Read status first: unknown, fresh, or stale, with unknownReason giving disabled, not_observed, or suspended. available and lastSeen are optional here and are absent for a contact the policy did not observe, so code that treated available as always present must handle undefined.
  • lastSeen is an ISO 8601 timestamp string on ChatPresenceData. It was a Unix timestamp in seconds on PresenceData. Arithmetic on the old numeric value must be replaced with date parsing.
  • ChatPresenceData no longer carries composing and paused participant arrays. A single optional chatState object reports sender, state, optional media, observedAt, and stale.
  • ChatPresenceData adds policy and typingPolicy, both ObservationMode (off, events, or cache), reporting the effective policy that produced the response, alongside typingStatus, typingUnknownReason, stale, and subscriptionExpiresAt.
Generated contact, participant, user-info, blocklist, and webhook types use id as the stable Polymorfa user key. It does not contain a WhatsApp LID. The optional phoneNumber, bsuid, and username fields are aliases and must not be used as independent contact keys. See User identities for lookup and upsert guidance. No published Polymorfa SDK exposes the identity verification operation yet. Use the direct Messaging API endpoint documented in User identities. The response contains the 60-digit code and base64 display-QR payload for an Polymorfa user ID; the verification-key payload is not part of the public response.

WhatsApp Business App commerce

No published Polymorfa SDK exposes catalog, product, collection, or order methods yet. Use direct HTTPS requests for these operations and grant the calling organization credential the business:read scope. Request bounds and resource workflows are documented in Catalogs and commerce. If you generate a private client from the Messaging API OpenAPI document, use the getBusinessCatalog, getBusinessProduct, getBusinessCollections, getBusinessCollection, and getBusinessOrder operation IDs. Keep order lookup tokens in the POST body.

BanSafe

No published Polymorfa SDK exposes BanSafe yet. Use direct HTTPS requests. The scores, findings, restrictions, and privacy boundary are documented in BanSafe. If you generate a private client from the Platform API OpenAPI document, the BanSafe operation IDs are listBanSafeHealth, getBanSafeHealth, listBanSafeHealthHistory, listBanSafeFindings, acknowledgeBanSafeFinding, listBanSafeSignals, getBanSafeTelemetry, listBanSafeTelemetryHistory, listBanSafeCollection, listBanSafeHealthActions, listBanSafeEnforcement, appealBanSafeEnforcement, listBanSafeIncidents, createBanSafeIncident, retractBanSafeIncident, listBanSafeClaims, getBanSafeClaim, getProjectWarmupPlanSettings, updateProjectWarmupPlanSettings, getInsuranceEvidenceSettings, and updateInsuranceEvidenceSettings. They add the request and response types BanSafeNumber, BanSafeNumberDetail, BanSafeNumberWarmup, BanSafeFinding, BanSafeHealthProbabilities, BanSafeObservedAccountState, BanSafeNumberEnforcement, BanSafeHealthHistory, BanSafeHealthPoint, BanSafeFindingAcknowledgement, BanSafeSignalDefinition, BanSafeSignalCodeCount, BanSafeSignal, BanSafeCollectionStatus, BanSafeTelemetrySnapshot, BanSafeCollectionSession, BanSafeTelemetryDetail, BanSafeHealthAction, BanSafeEnforcementSummary, BanSafeAppealReceipt, BanSafeIncident, BanSafeIncidentReceipt, BanSafeClaim, BanSafeClaimEvidence, ProjectWarmupPlan, WarmupPlanSettings, WarmupCurvePoint, UpdateProjectWarmupPlanInput, ProjectInsuranceEvidence, UpdateProjectInsuranceEvidenceInput, AcknowledgeBanSafeFindingInput, AppealBanSafeEnforcementInput, and ReportBanSafeIncidentInput. acknowledgeBanSafeFinding and appealBanSafeEnforcement carry no x-required-scope and accept only a signed-in Console session, so leave them out of a client built for an organization key or a project token. retractBanSafeIncident takes sessions:manage like createBanSafeIncident. The five telemetry, collection, and Health-action inspection methods take sessions:read. Their paginated methods preserve the response page object; the cursors are opaque and cannot be reconstructed from the final row. Safe Mode, the warm-up plan, and insurance evidence are each on both documents under different operation IDs, so a client generated from both gets two names for one surface. Both documents define ProjectSafeMode, SessionSafeMode, and ProjectWarmupPlan; each setting on SessionSafeMode additionally accepts inherit. The Platform document additionally defines SafeModeSettings, SafeModeOverride, SafeModeApplied, UpdateProjectSafeModeInput, UpdateSessionSafeModeInput, WarmupPlanSettings, WarmupCurvePoint, and UpdateProjectWarmupPlanInput. Both documents type insurance evidence as ProjectInsuranceEvidence. The Platform write body uses UpdateProjectInsuranceEvidenceInput, with a required boolean enabled. A write can return 503 propagation_pending after storing the setting if a connected number has not confirmed it. A generated client must preserve nullable Health fields. health is null without a supported estimate or enough fresh evidence. Do not render null as zero: zero is the lowest valid estimate. Read healthSource, healthEstimatorVersion, healthUnavailableReason, healthFeatureCoverage, healthEvaluatedAt, and healthExplanation before presenting availability, freshness, or deductions. Rules-v1 estimates have null model probabilities. Telemetry signals also preserve nullability. measured: false carries null value, sampleSize, and codes; a numeric zero remains a measured value. BanSafeHealthAction.outcome uses the closed public outcome vocabulary and does not carry worker retry or lease state. BanSafeClaimEvidence.attributionRuleVersion is also nullable. A number names the attribution rules used when the claim was filed; null identifies a claim filed before Polymorfa recorded rule versions. Do not replace null with the latest version. BanSafeNumberDetail.warmup reports enabled, tenureDay, nullable tenureSource (history, link, or plan), and nullable allowance, sentToday, and resetsAt, plus the projected curve. A null tenureSource means the source is unverified; plan identifies the plan-start fallback, not a verified number age. Health history contains accepted evaluations only. Warm-up allowance and send counts remain on the current number detail. BanSafeIncident includes nullable closedAt, closedBy, and claimId. The withdrawal operation takes no request body and returns that incident type, with documented 400, 404, and 409 failures. Error bodies on these operations carry the same four fields on both documents: error, and optionally code, docs, and retryAfter. Only error is always present. Regenerate any client whose error type was pinned to { error, docs }; the added fields are optional, so a client that ignores them keeps working. See Errors. Daily allowance sends can return 429 bansafe_daily_allowance_reached, 503 bansafe_accounting_unavailable, or 409 bansafe_send_outcome_unknown. The first two carry retryAfter; never automatically retry an unknown outcome. The five public BanSafe webhook payload types are BanSafeHealthThresholdPayload, BanSafeEnforcementPayload, BanSafeActionPayload, BanSafeIncidentPayload, and BanSafeClaimPayload. Also, MessageFailedPayload includes the blocked_by_safety error class, optional code, and optional retryAfter. See Webhooks. These additions do not change the SDK release status above.

History sync configuration

When creating or updating a linked-device session directly, clients may send historySync with mode set to metadata_only or deliver and requestFull set to a boolean. Generated clients must treat this field as a session configuration object, not an opaque message payload. Generated clients for the native Messaging API expose business profile fields such as description, websites, and coverPhotoId, plus typed profile and cover-photo update requests. They also expose the catalog product mutation request, image-source union, compliance fields, and delete result. The 5 MiB cover and 16 MiB product-image limits apply to decoded image bytes. This does not change the SDK release status above. Generated clients also expose typed collection create and partial-update requests, collection mutation results, and zero-based collection reorder moves. Direct HTTPS requests remain the supported integration path. Generated clients also expose typed cart settings, product visibility changes, and product or collection appeal requests. Catalog creation has no request body. These additions do not change the SDK release status above. Generated clients also expose the complete merchant-compliance record used by the live read and replacement operations, including legal entity type, customer-care details, and grievance officer details. These additions do not change the SDK release status above. Generated clients also expose create, complete-replacement, and delete operations for WhatsApp Business App quick replies. They also expose the best-effort list response and quickReplyMode observation-policy field. events retains no content, cache keeps a bounded in-memory projection, and off disables observation. These additions do not change the SDK release status above. Generated clients also expose live Business App linked-account and feature eligibility reads. Linked-account responses omit embedded profile-picture bytes and return URL metadata. These additions do not change the SDK release status above. Generated Messaging API clients also expose typed addressMessage and flow send payloads and the nativeFlowResponse webhook object. The flow payload references a published Flow; Flow creation and publishing are separate from message sending. These additions do not change the SDK release status above. Browser call integrations receive participant joins, state changes, and departures through the call lifecycle connection. connectEvents() consumers can subscribe to participantJoined, participantState, and participantLeft. Changes missed during a disconnect are not replayed. Participant mute and video fields remain reserved and report false.

Feature availability

The feature availability endpoint accepts authenticated HTTP requests. Use HTTP when your installed SDK has no matching method. Use QuickLink to connect customer-owned Cloud API or linked-device numbers. Link configuration separates connectionPreference (cloud, linked, both) from connectionEnforcement (prefer, force). Use the HTTP API when your installed SDK does not expose these fields; this contract does not imply that a new SDK release has been published. Cloud history webhooks use a JSON kind and value payload. Consumers of history.sync must distinguish it from linked-device compressed chunks. Subscribe to contact.sync and message.echo for contact synchronization and Business app messages. QuickLink creation accepts an optional externalId for your own correlation and a safe per-link settings overlay. The reference is returned on the resulting session and native session lifecycle webhooks. Set success and failure callback URLs in the project’s QuickLink settings or override them for one link under settings. Check your installed SDK types before using these fields, or use the HTTP contract. Meta Cloud API onboarding methods require team beta access and an active project. An installed SDK method does not enable onboarding. See QuickLink for unavailable choices, withdrawal and pending-operation behavior. Test-number operations require the team’s beta enrollment, including calls made through an SDK. A client method does not grant access. See Sandbox access before creating or using simulated numbers.