SDKs
WhatsApp in your language, frontend to backend
Handwritten SDKs for TypeScript, Python, Go, PHP, Rust and C#, each covering the same 439 API operations. Verify webhooks, retry without duplicates and mount the inbox in your frontend with a short-lived token.
- SDK languages
- 6
- Typed operations in each SDK
- 439
- Databases with storage adapters
- 9
- Idempotency-Key window
- 24 h
In your code
The same call in every language.
Each SDK is written by hand for its language, with the same resources, errors and retry rules. Retry a send with the same key and it goes out once.
import { MessagingClient } from "@polymorfa/sdk";
const messaging = new MessagingClient({
credential: { type: "apiKey", value: process.env.POLYMORFA_KEY! },
});
await messaging.messages.send(
"my-number",
{
conversation: { phoneNumber: "+15550001111" },
content: { text: "Your order has shipped." },
},
{ idempotencyKey: "order-1042-shipped" },
);import os
from polymorfa import AsyncMessagingClient, Credential, RequestOptions
credential = Credential("organization_api_key", os.environ["POLYMORFA_KEY"])
async def notify_shipped():
async with AsyncMessagingClient(credential) as client:
await client.messages.send(
"my-number",
{
"conversation": {"phoneNumber": "+15550001111"},
"content": {"text": "Your order has shipped."},
},
options=RequestOptions(idempotency_key="order-1042-shipped"),
)client, err := polymorfa.NewMessagingClient(polymorfa.Config{
Credential: polymorfa.Credential{
Kind: polymorfa.OrganizationAPIKey,
Value: os.Getenv("POLYMORFA_KEY"),
},
})
if err != nil {
return err
}
text := "Your order has shipped."
_, err = client.Messages().Send(ctx, "my-number", polymorfa.SendMessageRequest{
Conversation: polymorfa.ConversationReference{PhoneNumber: "+15550001111"},
Content: polymorfa.MessageContent{Text: &text},
}, polymorfa.RequestOptions{IdempotencyKey: "order-1042-shipped"})<?php
use Polymorfa\{Credential, MessagingClient, RequestOptions};
$client = new MessagingClient(Credential::organizationApiKey(getenv('POLYMORFA_KEY')));
$client->messages->send('my-number', [
'conversation' => ['phoneNumber' => '+15550001111'],
'content' => ['text' => 'Your order has shipped.'],
], new RequestOptions(idempotencyKey: 'order-1042-shipped'));use polymorfa_sdk::models::{ConversationReference, SendMessageRequest};
use polymorfa_sdk::{ClientOptions, Credential, MessagingClient, RequestOptions};
let key = std::env::var("POLYMORFA_KEY").expect("POLYMORFA_KEY");
let client = MessagingClient::new(Credential::organization_api_key(key)?, ClientOptions::default())?;
let request = SendMessageRequest::text(
ConversationReference::phone("+15550001111"),
"Your order has shipped.",
);
let options = RequestOptions {
idempotency_key: Some("order-1042-shipped".into()),
..Default::default()
};
client.messages().send("my-number", &request, options).await?;using Polymorfa.Sdk;
using var client = new MessagingClient(
Credential.OrganizationApiKey(Environment.GetEnvironmentVariable("POLYMORFA_KEY")!));
await client.Messages.SendAsync(
"my-number",
new SendMessageRequest(
new ConversationReference(PhoneNumber: "+15550001111"),
new TextContent("Your order has shipped.")),
new RequestOptions { IdempotencyKey = "order-1042-shipped" });curl https://api.polymorfa.com/messaging/my-number/messages/send \
-H "Authorization: Bearer $POLYMORFA_KEY" \
-H "Idempotency-Key: order-1042-shipped" \
-H "Content-Type: application/json" \
-d '{
"conversation": { "phoneNumber": "+15550001111" },
"content": { "text": "Your order has shipped." }
}'Frameworks
Fits the stack you already run.
Server code calls the API with your key. Frontend code gets a short-lived client token and the same components in every language.
TypeScript
@polymorfa/sdk- On your server
- Node
- Edge runtimes
- Next.js
- Express
- Hono
- In your frontend
- Browser
- React
- Web Components
Python
polymorfa-sdk- On your server
- FastAPI
- Django
- In your frontend
- Django templates
- HTMX
- Inertia
Go
github.com/polymorfa/sdks/packages/go- On your server
- net/http
- Gin
- Echo
- In your frontend
- templ
- HTMX
PHP
polymorfa/sdk- On your server
- Laravel
- Symfony
- In your frontend
- Blade
- Livewire
- Inertia
Rust
polymorfa-sdk- On your server
- Axum
- Actix
- In your frontend
- Leptos
- Yew
C#
Polymorfa.Sdk- On your server
- ASP.NET Core
- In your frontend
- Blazor WebAssembly
- MAUI
Frontend
Ship the inbox without exposing a key.
The SDKs refuse server credentials in browser and WebAssembly builds. Your server mints a client token for the signed-in user, limited to one number.
Production
Safe defaults in every SDK.
Signatures checked before parsing, retries that never duplicate a send, and typed errors that carry a code and request ID.
Your data
Keep WhatsApp data in your own database.
Store chats, messages and contacts where you choose. Media and history move straight between WhatsApp and your code, so they add no storage cost.
API surface
What the SDKs call for you.
Every SDK method maps to a documented REST route. The reference shows each one with a cURL example.
SDK methods
- POST
/messages.sendmessaging/ {number}/ messages/ send - POST
/clientTokens.mint, for browser codeplatform/ client-tokens - GET
/events.stream, resumes from a cursorplatform/ projects/ {project}/ events/ stream - GET
/chats.list, for stored historymessaging/ {number}/ chats - GET
/media.download, for stored mediamessaging/ media/ {id} - POST
/webhooks.test, sends a test deliveryplatform/ webhooks/ {id}/ tests
Typed webhook events
- Eventmessage.receivedSomeone wrote to the number
- Eventmessage.ackDelivered and read receipts
- Eventhistory.syncHistory arrived for a number
- Eventcall.receivedA WhatsApp call is ringing
- Eventsession.statusThe number connected or disconnected
- Eventcampaign.recipient_repliedA campaign recipient replied
Start with a free number
Your first real number is free. Add more numbers on Pay-As-You-Go.