rmyndharis/openwa

Official PHP SDK for OpenWA WhatsApp API Gateway

Maintainers

Package info

github.com/rmyndharis/openwa-php

pkg:composer/rmyndharis/openwa

Transparency log

Statistics

Installs: 269

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

0.5.0 2026-08-20 08:37 UTC

This package is auto-updated.

Last update: 2026-08-20 09:13:13 UTC


README

Official PHP SDK for the OpenWA WhatsApp API Gateway.

A synchronous client built on Guzzle, PSR-4 autoloaded.

Install

composer require rmyndharis/openwa

Requires PHP 8.1+ and Guzzle 7. The namespace is OpenWA\.

Usage

<?php
require 'vendor/autoload.php';

use OpenWA\Client;

$client = new Client([
    'baseUrl' => 'https://your-gateway.example.com',
    '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'];

For tests, inject a Guzzle client whose handler is a MockHandler — no network, no global state:

$client = new Client([
    'baseUrl'    => 'http://x',
    'apiKey'     => 'k',
    'httpClient' => $mockGuzzleClient,
]);

Messaging

Voice notes: pass 'ptt' => true to sendAudio to send a real WhatsApp voice note (PTT). Supply audio/ogg; codecs=opus audio for reliable playback; the server defaults the mimetype to that when ptt is set without one.

Errors

A non-2xx response throws a typed OpenWA\Exceptions\OpenWAApiException subclass — OpenWAAuthException (401), OpenWAForbiddenException (403), OpenWANotFoundException (404), OpenWAConflictException (409), OpenWARateLimitException (429), OpenWANotImplementedException (501), OpenWAServiceUnavailableException (503 — the only retryable one) — each exposing getStatus() and the parsed getBody(). A timeout throws OpenWATimeoutException.

use OpenWA\Exceptions\OpenWANotFoundException;

try {
    $client->sessions->get('missing');
} catch (OpenWANotFoundException $e) {
    echo $e->getStatus();  // 404
}

Notes

  • Use HTTPS in production — the API key is sent as X-API-Key and is bearer-equivalent.
  • The SDK does not retry, and never follows redirects (so the key is never re-sent to a redirect target). Path segments are percent-encoded; a base-URL path prefix (e.g. behind a reverse proxy) is preserved.
  • Escape hatch for endpoints the SDK does not wrap: $client->request($method, $path, $query, $body).

Releasing

Packagist installs this SDK from the mirror repository rmyndharis/openwa-php, not from the monorepo — Composer needs composer.json at a repository root and does not support subdirectories. Two workflows keep that mirror correct:

  • split-php-sdk.yml syncs the mirror's main on every push that touches sdk/php/**, which is what Packagist's dev-main follows.
  • php-sdk-release.yml cuts a versioned release by pushing a tag to the mirror. Packagist derives versions from that repository's tags, so a tag in this monorepo alone publishes nothing.

There is no version field in composer.json, and there should not be — Composer takes the version from the tag, and a hardcoded field drifts. The tag is the version.

Cutting a release:

  1. If the minor line changes, update extra.branch-alias.dev-main in composer.json (e.g. 0.1.x-dev0.2.x-dev) and land it on main. The release workflow refuses to publish when the alias does not match the tag.
  2. Tag that commit php-sdk-v<version> (e.g. php-sdk-v0.5.0) and push the tag. The SDK has its own version line — the monorepo's v* tags are the app version and never trigger an SDK release.
  3. The workflow runs the test suite, then tags the mirror <version> (no v prefix, matching the existing tags there). Packagist picks it up from its GitHub hook within a minute or two.

A released version is effectively immutable. Packagist caches a tag's contents, so moving one does not reliably reach anyone who already resolved it. The workflow refuses to overwrite an existing mirror tag — bump the version instead of re-tagging.

Requires the PHP_SDK_SPLIT_TOKEN secret, the same one the mirror workflow uses. Unlike the mirror workflow, which skips with a notice when the token is absent, the release fails: a release that silently publishes nothing looks exactly like one that worked.

License

MIT