Download the PHP package dineshstack/laravel-whatsapp-cost-control without Composer

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

Laravel WhatsApp Cost Control

WhatsApp Business Cloud API for Laravel — with the part nobody packages: cost control.

Sending a WhatsApp message is one HTTP call. Knowing what your messages cost, per country and per category, and stopping a marketing campaign before it burns the month's budget — that is the part every production integration ends up building by hand. This package is that part, extracted from a live system, plus the sending.

Tests


Why not just use an existing WhatsApp package?

Existing packages cover sending well. None of them answer, in production:

If you only need to fire messages, a lighter package is fine. This one is for when WhatsApp becomes a line item.


Requirements

PHP ^8.2
Laravel ^12.0 | ^13.0
A Meta WhatsApp Business account phone number ID, WABA ID, permanent token

Installation

Set the essentials in .env:

Fail-closed by default

Two settings block everything until you configure them, on purpose:

Sending

Every send goes through one funnel: country allowlist → budget check → 15-second-bounded HTTP call → audit log row → cost-ledger row. A blocked send returns the same shape as a failed one, with blocked => true distinguishing policy from outage.

When a send fails

Every result has success, status, body and message_id. A failed send adds why:

Case Extra keys
Meta refused it error_code (e.g. 132001), error_title, error_message
Blocked before Meta blocked: true, blocked_reason: country_not_allowed, budget_exhausted or recipient_suppressed
Meta did not answer unreachable: true — the message may still have been delivered, so do not retry blindly

Opt-outs

Every send checks opt-outs. Scope all blocks everything except AUTHENTICATION; scope marketing blocks MARKETING only. They are filled automatically when a customer replies a stop keyword (whatsapp.opt_out.stop_keywords), stops marketing messages inside WhatsApp (user_preferences webhook), or Meta refuses a send with 131050. Only a hash and the last four digits are stored. Changes dispatch WhatsAppRecipientSuppressed and WhatsAppRecipientRestored.

sendTemplate()'s opt-out check is scoped by the $category you pass it — pass 'MARKETING' for marketing sends so a marketing-scope opt-out is actually checked. Omit $category (or call isSuppressed() directly with none) and only an all-scope opt-out blocks the send; a marketing-scope opt-out on that recipient is silently not checked — isSuppressed() logs a warning when that happens so it is visible instead of just missed.

Cost tracking

At send time the package estimates cost from the rate card (country calling code × Meta category, effective-dated). When Meta's pricing webhooks arrive, the actual cost replaces the estimate. Messages with no configured rate surface in the cost summary as missing_rate — visibly unknown, never silently wrong.

Seed a starter rate card for one country with WHATSAPP_SEED_RATE_COUNTRY=971 (values are BSP-published estimates — verify against Meta's own rate card and correct via PUT .../rates).

Webhooks

Point Meta at the webhook URL (default /api/whatsapp/webhook). The GET verify handshake and HMAC-SHA256 signature validation are handled; payloads are queued so the endpoint answers inside Meta's 20-second window. Status updates fill in delivery state and actual costs on the ledger.

Subscribe your Meta app to messages, message_template_status_update, template_category_update and user_preferences. Template verdicts dispatch WhatsAppTemplateStatusChanged and recategorisations dispatch WhatsAppTemplateCategoryChanged; the package keeps no template state, so listen for these if you do. Meta redelivers webhooks, so both can fire more than once for the same verdict — listeners should be idempotent.

WhatsAppTemplateService::create() returns template_id, template_status and template_category — the category Meta assigned, which can differ from the one you asked for.

Admin API and permissions

Each admin endpoint checks one ability through $user->can(), so it works with plain Gates, spatie/laravel-permission, or any policy setup. By default reads need whatsapp.view and writes need whatsapp.manage; remap any ability in config('whatsapp.permissions') (the full list is Dineshstack\WhatsApp\Support\WhatsAppPermissions::DEFAULTS). Abilities you leave out keep their default. Middleware is yours:

Console

Provenance

Extracted from a production booking platform where it sends OTPs and transactional messages daily — the budget guard, rate card and ledger exist because that system needed them, not speculatively. Client-specific code was removed; the send funnel, cost logic and tests are the production versions.

Further reading

The incidents behind each design decision in this package, written up in order. Start with the first — it is the argument the rest of the package follows from.

  1. WhatsApp Cloud API sends you no invoice until it is too late — why the send response carries no price, why the pricing webhook carries no amount either, and the estimate-then-reconcile ledger that answers "what did this cost" at all. missing_rate over a silently wrong number.
  2. OTP pumping: the fraud that bills you for every code you send — the attacker never enters the code; the send is the transaction. Why rate limiting does not cap the loss and a fail-closed country allowlist does.
  3. Block the campaign at the cap. Never block the one-time code — the budget guard's category asymmetry. A broadcast overshooting is a cost problem; a refused OTP is a user who cannot log in.
  4. Verifying a WhatsApp webhook in Laravel: the three silent traps — PHP rewrites hub.mode to hub_mode before your code sees it, HMAC over re-encoded JSON rejects genuine payloads, and Meta's 20-second window forces the work into a queue.
  5. Random UUID keys fragment InnoDB. Ordered ones write clean — why the ledger and audit-log tables use Str::orderedUuid(). The tables most likely to get UUID keys are the highest-write tables in the system.

More production Laravel at dineshstack.com.

License

MIT. See LICENSE.

Security

Vulnerabilities: [email protected], not a public issue.

Author

Dinesh Wijethunga — dineshstack.com


All versions of laravel-whatsapp-cost-control with dependencies

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

Loading the files please wait ...