Files
wehub-resource-sync 4ce4204b6c
CI / Lint (push) Failing after 2s
CI / Build (push) Has been skipped
SDK CI / PHP SDK (push) Failing after 1s
Split PHP SDK / PHP SDK tests (push) Failing after 1s
CI / Test (push) Failing after 1s
CI / Dashboard (push) Failing after 0s
SDK CI / JavaScript SDK (push) Failing after 0s
SDK CI / Python SDK (push) Failing after 2s
SDK CI / Java SDK (push) Failing after 1s
Split PHP SDK / Mirror sdk/php -> rmyndharis/openwa-php (push) Has been skipped
CI / Test (PostgreSQL migrations) (push) Failing after 7m47s
CI / Docker Build (push) Has been skipped
chore: import upstream snapshot with attribution
2026-07-13 12:24:08 +08:00

4.3 KiB

OpenWA Java SDK

Official Java client for the OpenWA WhatsApp API Gateway.

Hand-written against the exact API surface (paths, DTOs, response shapes) and unit-tested with a mock HTTP transport that asserts on the precise request URL, method, and body — so contract drift is caught at test time. Synchronous, Java 17+, one runtime dependency (Gson).

Install

Maven

<dependency>
  <groupId>com.rmyndharis</groupId>
  <artifactId>openwa</artifactId>
  <version>0.1.1</version>
</dependency>

Gradle

implementation 'com.rmyndharis:openwa:0.1.1'

Quickstart

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());

For full control over configuration (timeout, default headers, a custom transport), build a ClientConfig:

import com.rmyndharis.openwa.ClientConfig;
import java.time.Duration;

OpenWAClient client = new OpenWAClient(ClientConfig.builder()
    .baseUrl("https://wa.example.com")
    .apiKey("owa_k1_…")
    .timeout(Duration.ofSeconds(15))
    .build());

Resources

The client exposes the same fluent resource surface as the JavaScript, Python, and PHP SDKs:

sessions · messages · contacts · groups · webhooks · chats · labels · channels · catalog · status · templates · health · search, plus client.auth().

Operator-only modules (docker, metrics, infra, plugins, mcp) are intentionally not exposed; all user-facing resources are.

Error handling

Errors are a typed, unchecked hierarchy — branch with instanceof or on .status():

import com.rmyndharis.openwa.errors.OpenWAConflictError;
import com.rmyndharis.openwa.errors.OpenWANotFoundError;

try {
    client.messages.sendText("my-session", body);
} catch (OpenWAConflictError e) {
    // 409 — engine not ready
} catch (OpenWANotFoundError e) {
    // 404 — session or chat not found
}
Class HTTP Meaning
OpenWAAuthError 401 Missing or invalid API key
OpenWAForbiddenError 403 API key role insufficient
OpenWANotFoundError 404 Resource not found
OpenWAConflictError 409 Engine not ready
OpenWARateLimitError 429 Rate limited
OpenWANotImplementedError 501 Active engine does not support the call
OpenWAApiError Any other non-2xx (carries .status())
OpenWATimeoutError Request exceeded the configured timeout

All extend OpenWAError (a RuntimeException).

Reliability & security

  • Use HTTPS in production. The API key is sent as X-API-Key on every request and is bearer-equivalent — never send it over plaintext http:// outside local development.
  • No automatic retries. A failed request throws immediately; wrap calls in your own backoff if you need retries (especially for 429). Inject a custom HttpTransport for retry or observability middleware.
  • Redirects are never followed. A 3xx surfaces as an OpenWAApiError rather than being followed, so the API key is never re-sent to a redirect target.
  • Default per-request timeout is 30 s (configurable). Path segments (chat / message ids) are percent-encoded; a base-URL path prefix (e.g. behind a proxy at /v1) is preserved.

Development

cd sdk/java
mvn -B verify        # compile + run the full test suite

Tests inject a recording HttpTransport and assert on the exact path — so the regression that would ship a broken messages/text path (the real path is messages/send-text) can never recur silently.