almarwa / whatsapp-gateway
Reusable WhatsApp Gateway client + self-service subscription flow for Laravel projects (c-wts.com / Ultramsg compatible).
Requires
- php: ^7.3|^8.0
- guzzlehttp/guzzle: ^7.0
- illuminate/database: ^8.0|^9.0|^10.0|^11.0
- illuminate/http: ^8.0|^9.0|^10.0|^11.0
- illuminate/support: ^8.0|^9.0|^10.0|^11.0
This package is not auto-updated.
Last update: 2026-05-04 10:36:12 UTC
README
Reusable Laravel package that provides:
- A clean PHP client for the c-wts.com REST gateway — drivers, DTOs, exceptions.
- A self-service public subscription flow (Landing → Register → QR + Status → Expired) ready to drop into any Laravel project.
- Local mirror of subscriptions in the
wa_subscriptionstable so customers can resume the flow without authenticating.
Target: Laravel 8 → 11, PHP 7.3+.
1. The two flows
Claim flow (default — works with the public c-wts.com API)
The customer signs up directly on c-wts.com, gets back instance_id and
access_token, then pastes them on your registration page. The package
verifies the credentials against the live gateway via GET /api/status and
saves a local row in wa_subscriptions.
This is what https://c-wts.com/docs exposes publicly.
Reseller flow (private API — for c-wts.com resellers only)
If you have a private reseller agreement with c-wts.com that lets you create instances on behalf of customers, switch the flow:
WHATSAPP_GATEWAY_FLOW=reseller WHATSAPP_GATEWAY_ADMIN_TOKEN=your_reseller_token WHATSAPP_GATEWAY_REGISTER_ENDPOINT=/api/reseller/register WHATSAPP_GATEWAY_RESTART_ENDPOINT=/api/instances/{instance}/restart WHATSAPP_GATEWAY_PACKAGES_ENDPOINT=/api/packages WHATSAPP_GATEWAY_UPGRADES_ENDPOINT=/api/instances/{instance}/upgrades
The customer fills the form, your server calls the private register endpoint,
and you get back {instance_id, access_token} — no manual paste required.
Default: claim.
2. Install
Option A — local path (recommended while iterating)
In the host project's composer.json:
{
"repositories": [
{
"type": "path",
"url": "packages/almarwa/whatsapp-gateway",
"options": { "symlink": true }
}
],
"require": {
"almarwa/whatsapp-gateway": "*"
}
}
Drop the package folder under packages/almarwa/whatsapp-gateway, then:
composer require almarwa/whatsapp-gateway:*
php artisan migrate
The service provider is auto-discovered. The WhatsappGateway facade is
auto-aliased.
Option B — private Git repo
Push this folder to its own repo and reference it from composer.json as a
vcs repository.
3. Configure
Publish the config (optional — defaults work):
php artisan vendor:publish --tag=whatsapp-gateway-config
.env defaults:
WHATSAPP_GATEWAY_DRIVER=cwts WHATSAPP_GATEWAY_FLOW=claim WHATSAPP_GATEWAY_BASE_URL=https://c-wts.com WHATSAPP_GATEWAY_VERIFY_SSL=false WHATSAPP_GATEWAY_SIGNUP_URL=https://c-wts.com/signup WHATSAPP_GATEWAY_LOGIN_URL=https://c-wts.com/login WHATSAPP_GATEWAY_ROUTE_PREFIX=whatsapp WHATSAPP_GATEWAY_SUPPORT_PHONE=0506499275 WHATSAPP_GATEWAY_HOME_URL=https://your-app.test WHATSAPP_GATEWAY_LOGO=/img/logo.svg
4. Routes
Auto-registered. With Mcamara/LaravelLocalization installed they're nested under the active locale and pick up the localization middleware automatically.
| URL | Name | Purpose |
|---|---|---|
GET /{locale}/whatsapp |
whatsapp-gateway.landing |
Landing + free package preview |
GET /{locale}/whatsapp/register |
whatsapp-gateway.register.show |
Form (info + paste credentials) |
POST /{locale}/whatsapp/register |
whatsapp-gateway.register |
Submit → verify → store |
GET /{locale}/whatsapp/connect/{token} |
whatsapp-gateway.connect |
QR + live status polling |
GET /{locale}/whatsapp/poll/{token} |
whatsapp-gateway.poll |
JSON: latest QR + status (AJAX) |
POST /{locale}/whatsapp/restart/{token} |
whatsapp-gateway.restart |
Re-pair (no-op if not exposed) |
GET /{locale}/whatsapp/expired/{token} |
whatsapp-gateway.expired |
Upgrade options + back-to-site |
Disable auto-routes:
'routes' => [ 'enabled' => false ],
5. Programmatic API
use Almarwa\WhatsappGateway\Facades\WhatsappGateway; use Almarwa\WhatsappGateway\DTOs\RegisterPayload; // claim flow — verify pasted credentials and store $payload = new RegisterPayload( name: 'عيادة المروة', phone: '0506499275', email: 'info@example.com', business: 'Al Marwa Clinic', packageId: 'free', ); $sub = WhatsappGateway::claim($payload, 'instance12345', 'access_token_here'); // reseller flow — create on c-wts.com on behalf of the customer $sub = WhatsappGateway::register($payload); // session ops $qr = WhatsappGateway::qr($sub); // base64 / url $status = WhatsappGateway::status($sub); // pending|connected|expired|... WhatsappGateway::send($sub, '+966501234567', 'مرحبا'); WhatsappGateway::restart($sub); // resume flow by URL token $sub = WhatsappGateway::findByToken($localToken);
6. Customizing the views
php artisan vendor:publish --tag=whatsapp-gateway-views
Override any of:
layout.blade.php— RTL/LTR aware HTML wrapperlanding.blade.php— promo + free package cardregister.blade.php— form (claim or reseller mode auto-detected)qr.blade.php— QR code + AJAX pollingexpired.blade.php— upgrade options
Branding (app name, support phone, logo, home URL) is read from
config/whatsapp-gateway.php#branding. Set it once per project — no template
edits required.
7. Drivers
| Driver | Class | Purpose |
|---|---|---|
cwts |
Almarwa\WhatsappGateway\Drivers\CwtsDriver |
Real REST gateway |
null |
Almarwa\WhatsappGateway\Drivers\NullDriver |
Tests / local dev |
To plug in a different gateway (Whapi, Baileys server, etc.) implement
Almarwa\WhatsappGateway\Contracts\GatewayDriver and register it under
config('whatsapp-gateway.drivers.<name>').
8. Public c-wts.com endpoints used
Documented at https://c-wts.com/docs:
| Method | Path | Params |
|---|---|---|
| GET | /api/status |
instance_id, access_token |
| GET | /api/qrcode |
instance_id, access_token |
| POST | /api/send |
instance_id, access_token, number, message |
Security: never expose
access_tokento the frontend. The package always proxies these calls server-side.
9. Database
Single table mirrors remote subscriptions for resumable flows:
wa_subscriptions
├── local_token (uuid, public token used in URLs)
├── name, phone, email, business
├── package_id, instance_id, token, remote_id
├── status, expires_at, dashboard_url
└── meta (json)
Customize the table name / connection in config('whatsapp-gateway.storage').
10. Reusing across Laravel projects
For each new project:
- Copy
packages/almarwa/whatsapp-gateway→ same path in the new repo. - Add the path repository + require in the new project's
composer.json. composer require almarwa/whatsapp-gateway:*php artisan migrate- Set the env vars.
Same code, same config keys, no edits.