Skip to content

Configuration reference ​

Every env variable + every config key. Defaults in bold.

The published config file is config/laravel-whatsapp.php. Re-publish on upgrade if new keys are added (Laravel's mergeConfigFrom is shallow and won't merge nested keys into your existing copy):

bash
php artisan vendor:publish --tag=laravel-whatsapp-config --force

Cloud API ​

Env varDefaultPurpose
WHATSAPP_BASE_HOSTgraph.facebook.comMeta Graph API host
WHATSAPP_API_VERSIONv21.0Graph API version
WHATSAPP_PHONE_NUMBER_IDrequiredFrom WhatsApp → API Setup
WHATSAPP_BUSINESS_ACCOUNT_IDrequiredWABA ID
WHATSAPP_ACCESS_TOKENrequiredPermanent System User token
WHATSAPP_TIMEOUT30HTTP timeout to Meta in seconds

Multiple Cloud accounts ​

Additional phone numbers go in the accounts array of config/laravel-whatsapp.php, not in env-only settings. Each entry takes phone_number_id, and optionally business_account_id and access_token, which fall back to the default account's. See Cloud API → Multiple phone numbers.

Webhook receiver ​

Env varDefaultPurpose
WHATSAPP_WEBHOOK_ENABLEDtrueRegister the webhooks/whatsapp routes
WHATSAPP_WEBHOOK_ROUTEwebhooks/whatsappURL path (no leading slash)
WHATSAPP_VERIFY_TOKENrequiredRandom string — also enter in Meta's webhook config
WHATSAPP_APP_SECRETrequiredFrom Meta App Settings → Basic. HMAC-verifies every POST
WHATSAPP_VERIFY_SIGNATUREtrueSet false for local testing with ngrok
WHATSAPP_WEBHOOK_LOGfalseStore every verified delivery in wa_webhook_events for inspection and replay
WHATSAPP_WEBHOOK_LOG_RETENTION_DAYS14How long model:prune keeps logged deliveries

Middleware on the routes is ['api'] by default. Override in config/laravel-whatsapp.php → webhook.middleware.

Web sidecar ​

Env varDefaultPurpose
WHATSAPP_WEB_ENABLEDfalseToggle the Web backend on
WHATSAPP_WEB_HOST127.0.0.1Interface the sidecar binds to. See host details below
WHATSAPP_WEB_PORT3000Sidecar port (used for both bind + Laravel connection)
WHATSAPP_WEB_TOKENemptyShared bearer token for Laravel↔sidecar auth. Set in production
WHATSAPP_WEB_TIMEOUT60HTTP timeout (seconds) for sidecar calls

Sidecar process ​

Env varDefaultPurpose
WHATSAPP_WEB_SIDECAR_PATHvendor/kstmostofa/laravel-whatsapp/sidecarWhere the Node service lives
WHATSAPP_WEB_NODE_BINARYnodePath to Node binary
WHATSAPP_WEB_NPM_BINARYnpmPath to npm
WHATSAPP_WEB_SESSION_DIRstorage/app/whatsapp-sidecar/sessionsPersisted WhatsApp Web auth state
WHATSAPP_WEB_AUTO_START_SESSIONStrueAuto-start persisted session-* auth folders when the sidecar boots
WHATSAPP_WEB_PID_FILEstorage/app/whatsapp-sidecar/sidecar.pidPID file
WHATSAPP_WEB_LOG_FILEstorage/logs/whatsapp-sidecar.logstdout log
WHATSAPP_WEB_ERR_FILEstorage/logs/whatsapp-sidecar.err.logstderr log

Why 127.0.0.1? ​

Default = 127.0.0.1 because the sidecar runs on the same server as Laravel and is reached over loopback. The sidecar holds your WhatsApp session — exposing it on 0.0.0.0 without auth = anyone on the network can send messages from your account.

TopologyWHATSAPP_WEB_HOST
Laravel + sidecar same server (default)127.0.0.1
Sidecar on another machinesidecar machine's IP, e.g. 10.0.0.5 + STRONG WHATSAPP_WEB_TOKEN + firewall
Behind a reverse proxy on a subdomainhostname of the proxy + TLS

WHATSAPP_WEB_HOST is unrelated to your Laravel APP_URL. Don't set it to your public domain unless the sidecar is actually reachable there.

UI ​

Env varDefaultPurpose
WHATSAPP_UI_ENABLEDtrueRegister the UI routes (also needs livewire/flux installed)
WHATSAPP_UI_PREFIXwhatsappURL prefix — /whatsapp/* becomes /<prefix>/*
WHATSAPP_UI_DEFAULT_SESSIONmainDefault session ID used when ?session= isn't in the URL
WHATSAPP_UI_POLL_INTERVAL5swire:poll interval on the conversations and sessions pages
WHATSAPP_UI_TEMPLATES_CACHE_SECONDS600Cache the approved-template list in Compose. Cleared by template status webhooks
WHATSAPP_UI_CSS_MODEvitevite | standalone | none. See UI install paths
WHATSAPP_UI_CHAT_LIST_LIMIT50Max chats rendered in the conversations sidebar (0 = unlimited)
WHATSAPP_UI_MESSAGES_INITIAL50Messages loaded per chat on first open
WHATSAPP_UI_MESSAGES_PAGE_SIZE50Per "Load older messages" click
WHATSAPP_UI_CHATS_CACHE_SECONDS3Cache the sidecar chats list this long (poll absorber)
WHATSAPP_UI_CONTACTS_CACHE_SECONDS30Cache the sidecar contacts list this long

Middleware on UI routes is ['web'] by default — wrap in your own auth before production:

php
// config/laravel-whatsapp.php
'ui' => [
    'middleware' => ['web', 'auth', 'can:manage-whatsapp'],
    // …
],

Database ​

Env varDefaultPurpose
WHATSAPP_DB_CONNECTIONempty (uses app default)Key from config/database.php. Lets you isolate WA data on a separate DB
WHATSAPP_DB_PREFIXemptyPrepended to wa_sessions, wa_messages, wa_contacts

Models (WaSession, WaMessage, WaContact) use the UsesWhatsAppConnection trait — they read both keys at runtime, so changing them in .env is enough; no model rebuild.

Migrations also resolve the connection + prefix at migration time:

php
Schema::connection(config('laravel-whatsapp.database.connection'))
    ->create(config('laravel-whatsapp.database.prefix', '').'wa_sessions', …);

Example multi-DB setup in config/database.php:

php
'connections' => [
    'mysql' => […],                           // your main app DB
    'whatsapp' => [                           // dedicated for WA data
        'driver' => 'pgsql',
        'host' => env('WHATSAPP_DB_HOST'),
        'port' => env('WHATSAPP_DB_PORT', 5432),
        'database' => env('WHATSAPP_DB_DATABASE'),
        'username' => env('WHATSAPP_DB_USERNAME'),
        'password' => env('WHATSAPP_DB_PASSWORD'),
    ],
],

Drivers can differ — your app on MySQL, WhatsApp on Postgres, no problem.

Persistence ​

Env varDefaultPurpose
WHATSAPP_PERSIST_INCOMINGfalseAuto-write messages, ack updates and revokes to wa_messages
WHATSAPP_PERSIST_SESSIONSsame as WHATSAPP_PERSIST_INCOMINGTrack Web session status, pairing time and disconnects in wa_sessions

When true, the package registers PersistIncomingMessage as a listener for both Cloud and Web backends. Idempotent — re-delivered messages don't duplicate.

Media persistence ​

Env varDefaultPurpose
WHATSAPP_MEDIA_STOREfalseCopy media off WhatsApp to a disk before it expires (needs WHATSAPP_PERSIST_INCOMING=true)
WHATSAPP_MEDIA_DISKlocalFilesystem disk for the copies. Keep it private
WHATSAPP_MEDIA_PATHwhatsapp-mediaFolder on the disk
WHATSAPP_MEDIA_MAX_MB50Skip larger files. 0 for no limit
WHATSAPP_MEDIA_RETENTION_DAYSemptyDefault for whatsapp:media:prune. Empty keeps media forever

See Production → Media persistence.

Broadcasting ​

Env varDefaultPurpose
WHATSAPP_BROADCASTfalseMake Web events implement ShouldBroadcast
WHATSAPP_BROADCAST_PREFIXwhatsappChannel prefix, e.g. whatsapp.session.main
WHATSAPP_BROADCAST_CHANNELpublicpublic or private
WHATSAPP_BROADCAST_ABILITYmanage-whatsappGate ability that authorizes private channels. Empty to register your own
WHATSAPP_UI_POLL_INTERVAL_BROADCASTING60sSafety-net poll interval while broadcasting is on
WHATSAPP_UI_SCRIPTSemptyComma-separated script URLs for the UI layout, e.g. an Echo bundle in standalone CSS mode

When broadcasting is on, the Web events are pushed over your configured broadcaster (Reverb / Pusher / Ably) and the bundled UI updates from them instead of polling. See Production → Live updates.

Queue ​

Env varDefaultPurpose
WHATSAPP_QUEUE_CONNECTIONLaravel defaultQueue connection for the SendMessage and SendBulkMessage jobs
WHATSAPP_QUEUEdefaultQueue name

Bulk sending ​

Env varDefaultPurpose
WHATSAPP_BULK_CLOUD_PER_MINUTE1000Cloud messages per minute, per phone number
WHATSAPP_BULK_WEB_PER_MINUTE10Web messages per minute, per session
WHATSAPP_BULK_WEB_DELAY_MIN / _MAX3 / 10Random gap between Web sends, in seconds
WHATSAPP_BULK_RETRY_HOURS12How long a rate-limited job keeps retrying

See Bulk sending.

Full config file ​

After php artisan vendor:publish --tag=laravel-whatsapp-config, you'll have a fully-commented config/laravel-whatsapp.php in your project. Comments in there are the source of truth for every option.

Released under the MIT License.