Download the PHP package haimanresources/laravel-whatsapp without Composer

On this page you can find all versions of the php package haimanresources/laravel-whatsapp. 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 laravel-whatsapp

Laravel WhatsApp

Drop-in WhatsApp Cloud API module for Laravel: outbound messages, signed inbound webhooks, conversation and message storage, delivery receipts, and the setup diagnostics that turn Meta's silent misconfigurations into a clear error.

Requirements

PHP 8.2+, Laravel 11 or 12.

Configuration

Migrations run from the package, so php artisan migrate works immediately. Publish them only to change the schema:

The app secret and the access token are not interchangeable. The token signs nothing and the secret sends nothing. Using the token where the secret belongs produces the most common failure in this integration: sending works perfectly and replies never arrive, because every inbound delivery fails signature verification and is rejected with a 401.

Setup, in the order that works

Getting WhatsApp delivering requires two separate subscriptions. Meta's dashboard shows the first as healthy while the second is missing, and reports no error anywhere — the integration simply never receives anything.

  1. Point Meta at your callback. WhatsApp → Configuration → Callback URL is https://your-app.test/webhook/whatsapp, verify token is your WHATSAPP_VERIFY_TOKEN. Saving it triggers a GET challenge this package answers automatically.
  2. Subscribe the messages field. A green tick on the field, not just a saved URL.
  3. Subscribe the app to the WhatsApp Business Account — the step that is easy to miss, because saving the callback URL looks like it finished setup:

  4. Verify:

    readiness reads back what Meta actually holds and exits non-zero if anything would stop inbound delivery, so it is safe to run in CI or at the end of a deploy.

Meta allows one callback URL per app. A staging deployment and production cannot share one app — whichever URL is registered wins and the other environment receives nothing. Use a separate Meta app per environment. whatsapp:readiness detects and names this case.

Sending

Numbers are normalised to Meta's wa_id format, so +234 801 234 5678, 234-801-234-5678 and 2348012345678 are equivalent.

Every send is recorded before the HTTP call and updated after it, so a timeout leaves a failed row carrying Meta's own error code rather than nothing at all. A failure throws — wrap calls you do not want to interrupt a request.

Outside the 24-hour customer service window Meta rejects free-form text; only an approved template will send.

Receiving

Inbound messages and receipts are stored automatically. React to them with events:

Event Fires when
MessageReceived a customer message is stored (once per message)
MessageStatusUpdated a receipt moves a message to delivered/read/failed
ConversationStarted a number messages you for the first time

Processing inline or on the queue

By default a delivery is parsed inline, before responding to Meta. That keeps the inbox correct with no queue worker running, and a failure returns non-2xx so Meta retries rather than dropping the event. Under high volume, hand it to the queue instead:

The trade is explicit: queueing returns to Meta faster, but a stopped worker means inbound messages sit unprocessed. whatsapp:readiness reports the unprocessed count, and whatsapp:reprocess-webhooks drains it.

Attaching conversations to your models

A conversation optionally belongs to any model — a Client, Tenant, User, or nothing:

owner_id is a string column, so UUID and auto-increment keys both work. An existing owner is never silently reassigned. A second owner messaging a number already bound to another is refused with OwnerConflictException: on a shared business number that is a tenant boundary, and the customer would otherwise see two owners' messages as one conversation. Transfer the conversation deliberately, or set whatsapp.owner_conflict to ignore to log and send instead.

Since an inbound reply carries only a phone number, bind ownership yourself on ConversationStarted:

The inbox

A complete Blade interface ships with the package at /whatsapp — no build step, no JavaScript framework in your app:

Its routes are named whatsapp.ui.*, so they cannot collide with an inbox your application already has.

Put your own auth middleware on it. The default is ['web'] only, because the package cannot know your guard — and these pages can message your customers.

Restyle it by publishing the views:

Tailwind and Alpine load from a CDN so the package works in any app; vendor those two files if your deployment forbids external assets.

Using it from TypeScript (React, Vue, Inertia, mobile)

The Blade UI is optional. A JSON API ships alongside it, with TypeScript definitions that mirror the responses exactly:

Or ignore the client and use the types with your own data layer — Inertia props, React Query, Pinia. Turn the Blade UI off entirely and keep only the API:

Endpoint Purpose
GET /conversations list; q, unread, archived, per_page
POST /conversations start many at once; 207 when some fail
GET /conversations/{id}/messages thread; after ISO cursor for polling
POST /conversations/{id}/messages reply; 422 with a code when refused
PATCH /conversations/{id} archive / opt-out
GET|POST /broadcasts list / create (draft unless send_now)
POST /broadcasts/{id}/send\|cancel run or stop a broadcast

Broadcasts

One message to many recipients, with per-recipient delivery tracking:

Three rules are enforced by the package rather than left to the caller, because getting any of them wrong risks the WhatsApp number itself:

Rule Behaviour
Opted-out contacts are never messaged Marked skipped before anything is sent
Free-form text only reaches the 24-hour window Cold recipients without a template are skipped, not failed
Bursts lower a number's quality rating Sends are paced at 30/minute (WHATSAPP_BROADCAST_PER_MINUTE)

Recipients are normalised and de-duplicated, so a pasted list with repeats and mixed formats cannot message anyone twice. Each recipient is its own queued job, so one bad number cannot stop the run, and a recipient already reached is never sent to twice — even if the job retries or an operator presses send again. Delivery receipts flow back into per-recipient status, so the broadcast page shows sent / delivered / read / failed / skipped as they happen.

Cancel mid-flight and everyone not yet reached is skipped.

This is not a group chat. The Cloud API has no group messaging; each recipient gets an individual thread and cannot see the others.

Opt-out

An inbound STOP (or unsubscribe, cancel, …) marks the conversation opted out and broadcasts skip it from then on; START reverses it. Honouring opt-out is a WhatsApp Business policy requirement, not a nicety. Configure the keywords or disable the automatic handling in config/whatsapp.php.

Reading conversations

No UI ships with the package — host apps differ too much. The models are the whole API.

Commands

Command Purpose
whatsapp:readiness Check config and what Meta has registered. Non-zero exit if inbound is broken.
whatsapp:subscribe Subscribe the app to the WABA, then verify it took effect.
whatsapp:reprocess-webhooks Replay stored envelopes after an outage or parsing fix.

Reliability

Customising the webhook route

The route registers itself at webhook/whatsapp. To control it yourself:

The route is public by necessity — Meta cannot authenticate. It is protected by signature verification and a rate limiter (whatsapp-webhook, 600/min per IP, configurable). A host app defining its own limiter of that name keeps it.

Testing against the package

Troubleshooting

Symptom Cause
Sending works, replies never arrive Run whatsapp:readiness. Usually no app subscribed to the WABA, or the callback points at another environment.
whatsapp.webhook.signature_failed in logs WHATSAPP_APP_SECRET wrong or empty — the app secret, not the access token.
Verification fails when saving the callback WHATSAPP_VERIFY_TOKEN differs from what you typed into Meta.
(#131047) Re-engagement message Outside the 24-hour window — send a template.
Webhooks arrive, inbox empty whatsapp:reprocess-webhooks, then check processing_error.
Broadcast shows everyone skipped No template, and the recipients are outside the 24-hour window. Add an approved template.
Broadcast sends very slowly By design — WHATSAPP_BROADCAST_PER_MINUTE paces it. Raise only if your number is on a higher tier.
No whatsapp/* routes Another package or your app registered webhook/whatsapp first, or whatsapp.webhook.enabled is false. Check php artisan route:list --name=whatsapp.

Contributing / publishing

Publishing to Packagist (needs credentials this repository does not carry):

  1. Push to github.com/HaimanResourcesConsulting/laravel-whatsapp.
  2. Submit the URL at https://packagist.org/packages/submit.
  3. Enable the GitHub service hook so new tags publish automatically.
  4. Tag releases with git tag v0.1.0 && git push --tags.

License

MIT. See LICENSE.md.


All versions of laravel-whatsapp with dependencies

PHP Build Version
Package Version
Requires php Version ^8.2
illuminate/bus Version ^11.0 || ^12.0 || ^13.0
illuminate/console Version ^11.0 || ^12.0 || ^13.0
illuminate/database Version ^11.0 || ^12.0 || ^13.0
illuminate/http Version ^11.0 || ^12.0 || ^13.0
illuminate/queue Version ^11.0 || ^12.0 || ^13.0
illuminate/support Version ^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 haimanresources/laravel-whatsapp contains the following files

Loading the files please wait ...