OpenWA SDKs
Official client libraries for the OpenWA WhatsApp API Gateway.
All four SDKs are hand-written against the exact API surface (paths, DTOs,
response shapes) and unit-tested with mocked HTTP transports that assert on
the precise request URL, method, and body — so drift is caught at test time.
The wire types live in a dedicated module (types.ts / types.py / model/)
so they can later be regenerated by an OpenAPI codegen pass without touching the
hand-written resource methods.
| Language | Package | Notes |
|---|---|---|
| JavaScript / TypeScript | @rmyndharis/openwa |
dual ESM/CJS, bundled types |
| Python | rmyndharis-openwa |
sync (httpx), PEP 561 typed |
| PHP | rmyndharis/openwa |
sync (Guzzle, PHP 8.1+) |
| Java | com.rmyndharis:openwa |
sync (java.net.http + Gson, Java 17) |
Coverage
All three SDKs expose the same fluent resource surface:
| Resource | Methods |
|---|---|
sessions |
list, get, create, delete, start, stop, forceKill, getQrCode, requestPairingCode, stats |
messages |
list, sendText, sendImage/Video/Audio/Document/Sticker, sendLocation, sendContact, sendTemplate, reply, forward, react, delete, history, reactions, sendBulk, batchStatus, cancelBatch |
contacts |
list, get, check, profilePicture, phone, block, unblock |
groups |
list, get, create, add/remove/promote/demoteParticipants, setSubject, setDescription, leave, inviteCode, revokeInviteCode |
webhooks |
list, get, create, update, delete, test |
chats |
list, markRead, markUnread, delete, sendState |
labels |
list, get, forChat, addToChat, removeFromChat (WhatsApp Business) |
channels |
list, get, messages, subscribe, unsubscribe (Newsletters) |
catalog |
info, products, product, sendProduct, sendCatalog (WhatsApp Business) |
status |
list, fromContact, sendText, sendImage, sendVideo, delete (Stories) |
templates |
list, get, create, update, delete |
health |
check, live, ready |
⚠️ Endpoints requiring an
OPERATOR-level API key are noted in the inline docs. Operator-only modules (docker,metrics,infra,plugins,mcp) are intentionally not exposed in the SDK; all user-facing resources are.
JavaScript / TypeScript
npm install @rmyndharis/openwa
import { OpenWAClient } from '@rmyndharis/openwa';
const client = new OpenWAClient({
baseUrl: 'http://localhost:2785',
apiKey: 'owa_k1_…',
});
await client.sessions.start('my-session');
const result = await client.messages.sendText('my-session', {
chatId: '628123456789@c.us',
text: 'Hello from the OpenWA SDK!',
});
console.log(result.messageId);
Errors are typed — branch with instanceof:
import { OpenWANotFoundError, OpenWAConflictError } from '@rmyndharis/openwa';
try {
await client.messages.sendText(/* … */);
} catch (e) {
if (e instanceof OpenWAConflictError) {
/* engine not ready (409) */
}
}
Requires Node 18+ (uses the global
fetch). Pass a customfetchto the client constructor to intercept or observability-wrap requests.
Python
pip install rmyndharis-openwa
from openwa import OpenWAClient, OpenWANotFoundError
client = OpenWAClient(
base_url="http://localhost:2785",
api_key="owa_k1_…",
)
client.sessions.start("my-session")
result = client.messages.send_text("my-session", {
"chatId": "628123456789@c.us",
"text": "Hello from the OpenWA Python SDK!",
})
print(result["messageId"])
Pass transport=httpx.MockTransport(handler) for testing — no global
monkey-patching required.
PHP
composer require rmyndharis/openwa
<?php
use OpenWA\Client;
$client = new Client([
'baseUrl' => 'http://localhost:2785',
'apiKey' => 'owa_k1_…',
]);
$client->sessions->start('my-session');
$result = $client->messages->sendText('my-session', [
'chatId' => '628123456789@c.us',
'text' => 'Hello from the OpenWA PHP SDK!',
]);
echo $result['messageId'];
Requires PHP 8.1+ and Guzzle 7. For testing, inject a Guzzle client whose
handler is a MockHandler — no global state, no network.
Java
<dependency>
<groupId>com.rmyndharis</groupId>
<artifactId>openwa</artifactId>
<version>0.1.1</version>
</dependency>
import com.rmyndharis.openwa.OpenWAClient;
import com.rmyndharis.openwa.model.MessageResponse;
import com.rmyndharis.openwa.model.SendTextRequest;
OpenWAClient client = new OpenWAClient("http://localhost:2785", "owa_k1_…");
client.sessions.start("my-session");
MessageResponse result = client.messages.sendText("my-session",
SendTextRequest.builder()
.chatId("628123456789@c.us")
.text("Hello from the OpenWA Java SDK!")
.build());
System.out.println(result.messageId());
Requires Java 17+. Errors are a typed, unchecked hierarchy — branch with
instanceof OpenWANotFoundError / OpenWAConflictError. For testing, inject a
custom HttpTransport that records the request — no network. See
java/README.md for the full guide.
Reliability & security
- Use HTTPS in production. The API key is sent as
X-API-Keyon every request and is bearer-equivalent — never send it over plaintexthttp://outside local development. - No automatic retries. A failed request raises/throws immediately; wrap
calls in your own backoff if you need retries (especially for
429). The injectable transport (fetch/transport/httpClient) is the extension point for retry or observability middleware. - Redirects are never followed. A
3xxsurfaces to the caller rather than being followed, so the API key is never re-sent to a redirect target. - Default per-request timeout is 30s (configurable). Path segments (chat /
message ids) are percent-encoded; a base-URL path prefix (e.g. behind a proxy
at
/v1) is preserved.
Development
# JavaScript
cd sdk/javascript && npm test && npm run build && npm run smoke
# Python
cd sdk/python && python -m pytest -q
# PHP
cd sdk/php && composer install && ./vendor/bin/phpunit
# Java
cd sdk/java && mvn -B verify
Each test suite mocks the HTTP layer and asserts on the exact path, so the
regression that originally shipped a broken messages/text path (the real path
is messages/send-text) can never recur silently.