Download the PHP package denlopes/waha-laravel-sdk without Composer

On this page you can find all versions of the php package denlopes/waha-laravel-sdk. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package waha-laravel-sdk

WAHA Laravel SDK

A Laravel client for WAHA, the self-hosted WhatsApp HTTP API. It talks to one or more WAHA servers through typed, injectable services and a small fluent layer for chat, message, and human-like sending.

What's in the box:

Table of contents

Requirements

Installation

Package discovery registers the service provider and the Waha facade. Publish the config and migrations:

Then set your WAHA URL and API key in .env:

That's enough to start sending. If you run the conversation limiters on Redis, install the phpredis extension and set WAHA_CONVERSATIONS_LIMITER_DRIVER=redis. Predis won't work for that driver.

Local development

When working on the package alongside an application, register it as a Composer path repository:

Quick start

The Waha facade is the fastest way in. Send a text message:

Send an image:

Reply to an inbound message:

Send like a human, with pacing and quotas handled for you:

List sessions through a service:

The facade resolves to DenLopes\Waha\Client. Prefer constructor injection? Inject Client instead:

The second argument picks the session. Omit it to use waha.default_session.

Chat

Lookups:

Send methods — sendMessage, sendImage, sendFile, sendVoice, sendVideo, sendPoll, sendLocation, sendContactVcard, sendList, sendLinkCustomPreview, and forward — each return a Message.

State-changing actions return $this for chaining: startTyping(), stopTyping(), react(), star(), markRead(), pinMessage(), unpinMessage(), archive(), unarchive(), markUnread(), clearMessages(), and delete().

Message

A Message is returned by every send* method and by message() / find():

Message exposes get() (the raw MessageData), refresh(), markRead(), react(), star(), pin(), unpin(), update(), forward(), delete(), and toArray() / toJson().

Conversations (anti-ban)

Conversation wraps a Chat and sends messages the way WAHA recommends to avoid being flagged as spam:

Or build one from an existing chat and drive the lower-level steps yourself:

The behavior is driven by the waha.conversations config block. Transport mechanics (thinking, typing, pauses, delay skew) stay on the Pacing value object. Quotas live on per-stage TierConfig objects, one for cold, warm, and reply. Pacing::tier(ContactStage::Cold) returns the tier for a stage.

Each send() gates the message through a fixed pipeline before anything goes out:

  1. The delivery circuit breaker, if enabled. When a session's recent failure rate clears the threshold, send() throws CircuitBreakerOpenException.
  2. Stage resolution. A replyTo makes it a reply; a contact that has messaged you before is warm; anything else is cold. withStage() forces a stage.
  3. Cold link policy. Cold sends disable link previews, and can reject URLs with ColdMessageContainsUrlException.
  4. Reachout guard. Cold sends check the session's capping and timelock and throw ReachoutQuotaExhaustedException or ReachoutTimelockActiveException.
  5. Per-chat and per-session quotas for the stage, then the cooldown wait.

Pacing state is stored in Laravel's cache by default, so the cooldown and window cap are shared across conversations targeting the same chat, even in different workers. Each send() also takes a Cache::lock() scoped to that chat, so concurrent sends serialize instead of racing on the shared state. The lock time-to-live is computed from the message and pacing policy, so it grows with longer messages rather than using a fixed timeout. How long a worker waits for the lock is separate, controlled by lock_wait_seconds. Set cache_store and cache_prefix in waha.conversations to pick the cache store and key namespace. Call reset() to clear the state.

Inbound webhooks feed the model too. A 1:1 inbound message marks the contact warm, and message acks record delivery successes and failures for the circuit breaker. Both are handled by the package's webhook listener and no-op when the matching feature is disabled.

When these sends run inside a queue job, keep the worker timeout above the longest possible delay. The thinking and typing pauses are synchronous usleep() calls, so a very long message can block a worker for a minute or more. A queue:work --timeout=120 is a safer floor than the default 30 seconds.

Sessions

A session name is wrapped in a Session value object so it can't be confused with a chat ID, message ID, or phone number.

Most service methods accept ?Session $session = null and fall back to the configured default when omitted.

Services

Below the fluent layer, each WAHA API area has its own injectable service. Services follow a consistent naming convention: list*, get*, create*, update*, delete*, send*, set*.

The full service list is in Coverage.

DTOs

The Data serializer walks public constructor-promoted properties, skips null values (WAHA treats an omitted key as "leave unchanged"), and recursively serializes nested DTOs, backed enums, and arrays. It also provides safe extraction helpers — string(), arrayValue(), intValue(), boolValue() — used by fromArray() mappers to degrade gracefully on unexpected payloads.

Configuration

All settings come from config/waha.php and the environment, read through Laravel's config() helper.

Config key Env var Default Description
waha.base_url WAHA_BASE_URL http://localhost:3000 Base URL of the WAHA server.
waha.api_key WAHA_API_KEY (none) Secret sent via the X-Api-Key header.
waha.default_session WAHA_DEFAULT_SESSION default Session used when none is given explicitly.
waha.timeout WAHA_TIMEOUT 30 HTTP request timeout, in seconds.
waha.connect_timeout WAHA_CONNECT_TIMEOUT 5 TCP connection timeout, in seconds.
waha.retry_attempts WAHA_RETRY_ATTEMPTS 3 Retries for transient failures and connection errors on idempotent methods.
waha.retry_delay_ms WAHA_RETRY_DELAY_MS 200 Initial retry backoff in ms (exponential, with jitter).

Multi-host and webhook settings live in their own sections below.

Multi-host

Define waha.hosts to talk to more than one WAHA server. When empty, the single-host keys above are used as the primary host.

Host selection is abstracted behind HostRegistry, ApiKeyProvider, and SessionRouter contracts. Hosts are normalized into an immutable HostConfig value object, and the mode string is represented by the ApiKeyMode enum (ADMIN_FALLBACK / STRICT_SESSION_KEY).

DB-backed hosts

Set WAHA_REGISTRY_DRIVER=db to read hosts from the waha_hosts table instead of config. Run php artisan migrate, then seed the table. Each host is keyed by a unique key and can define per-session API keys.

Session → host pinning

Set WAHA_ROUTING_DRIVER=pin to resolve the host from the waha_session_pins table (session name → host key), falling back to default_host when unknown.

This is how each tenant gets its own WhatsApp number — and, as it grows, its own WAHA host — without hardcoding that mapping in the SDK.

Logging

The package merges two dedicated channels into the host application's logging config: waha (request/response lifecycle) and wahaError (failures). Override them in your own config/logging.php if you want different drivers, paths, or levels.

Webhooks

When enabled (the default), the service provider registers a stateless route for inbound WAHA deliveries. It verifies the request, parses it into a typed Webhook, then dispatches it.

Route

Default endpoint: POST /webhooks/waha. Configure it with waha.webhooks.route.prefix (WAHA_WEBHOOKS_ROUTE_PREFIX) and waha.webhooks.route.middleware.

Verification

The controller checks, in order:

  1. HMAC signatureX-Webhook-Hmac over the raw body using waha.webhooks.secret (WAHA_WEBHOOK_SECRET). The algorithm comes from X-Webhook-Hmac-Algorithm and defaults to sha512.
  2. Timestamp freshnessX-Webhook-Timestamp against waha.webhooks.max_clock_skew_ms.
  3. Replay de-duplicationX-Webhook-Request-Id via the cache for waha.webhooks.replay.ttl_seconds.

Set WAHA_WEBHOOKS_REQUIRE_HMAC=false to accept unauthenticated deliveries (not recommended outside development).

Handling

Two extension points:

Handlers implement DenLopes\Waha\Webhooks\Contracts\WebhookHandler.

The package also registers its own listener for inbound messages and message acks. It marks contacts warm and feeds the delivery circuit breaker, and no-ops when those features are disabled. See Conversations (anti-ban).

Processing mode

Parsing

Webhook::fromArray() maps payload to the most specific DTO for the event (e.g. MessageData for message). Unrecognized events keep their raw array.

Storage

Set WAHA_WEBHOOKS_STORE_ENABLED=true to persist verified deliveries to the waha_webhook_events table.

Errors

Every failure is thrown as a subclass of DenLopes\Waha\Exceptions\WahaException, so you can catch the base type for "any WAHA problem" or a specific subtype for targeted handling. API/HTTP failures share ApiException as their base.

Exception Trigger
ApiException Base for API/HTTP errors
AuthenticationException 401/403
CredentialsException Missing/invalid API key (extends AuthenticationException)
SessionNotFoundException 404 on a session-scoped endpoint
NoDataException 404 on a non-session resource
RateLimitException 429
RequestException 400/422
ServerException 5xx
ConnectionException Connection failure or timeout
IntegrationException JSON decode failures and unclassified failures
NotImplementedException 501 endpoint not implemented by the engine
UnknownHostException Requested host is not configured
WebhookException Webhook verification or dispatch failure
ConversationThrottledException Per-chat window cap reached
SessionRateLimitedException Per-session stage quota reached
ColdFanoutThrottledException Cold unique-target budget exhausted
ReachoutQuotaExhaustedException WhatsApp reachout capping exhausted
ReachoutTimelockActiveException WhatsApp reachout timelock active
ColdMessageContainsUrlException Cold message rejected for containing a URL
CircuitBreakerOpenException Delivery circuit breaker open

Each exception carries a structured context() array (HTTP method, endpoint, status, and a response body snippet) for logging and diagnostics.

Architecture

Request layer

DenLopes\Waha\Http\HttpClient (bound to DenLopes\Waha\Contracts\HttpClient) is the only place that talks HTTP. It:

SendsRequests is the trait consumed by every service. It injects the HTTP client through the constructor and provides send() and download() helpers that normalize failures into domain exceptions.

The HTTP client records its last request and response in DebugStore, which is useful for troubleshooting:

Coverage

The service layer covers every area exposed by the WAHA OpenAPI document:

Service Area
SessionService Session lifecycle and info
PairingService QR, code, passkey pairing, screenshots
ProfileService Profile name/status/picture
MessagingService Sending messages and reactions
ChatsService Chats, messages, pinning, archiving
GroupsService Group management and settings
ContactsService Contacts and number checks
LidsService LID ↔ phone number mappings
LabelsService Labels (WhatsApp Business)
ChannelsService Channels/newsletters
StatusService Status (stories)
PresenceService Presence management
CallsService Call rejection
EventsService Event (RSVP) messages
MediaService Media conversion
ApiKeysService API key management
AppsService Built-in apps and the MCP endpoint
ObservabilityService Ping, health, server, debugging

Testing

The package uses Orchestra Testbench, so the suite runs standalone — no host Laravel application required.

WahaTestCase extends Orchestra\Testbench\TestCase and registers WahaServiceProvider via getPackageProviders(), so Laravel-booted tests run against an in-memory application.


All versions of waha-laravel-sdk with dependencies

PHP Build Version
Package Version
Requires php Version ^8.3
guzzlehttp/guzzle Version ^7.5 || ^8.0
laravel/framework Version ^10.0 || ^11.0 || ^12.0 || ^13.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package denlopes/waha-laravel-sdk contains the following files

Loading the files please wait ...