Skip to content

Models

Three Eloquent models, all using the UsesWhatsAppConnection trait so they honor WHATSAPP_DB_CONNECTION + WHATSAPP_DB_PREFIX at runtime.

WaSession

Kstmostofa\LaravelWhatsApp\Models\WaSession — represents one paired session (Web) or one phone-number ID (Cloud).

ColumnTypeNotes
idstring PKsession ID — 'main', 'sales', etc.
backendstring'web' or 'cloud'
statusstring'qr' | 'authenticating' | 'ready' | 'disconnected'
phone_numberstringpaired number once known
push_namestringdisplay name from WhatsApp profile
last_qr_atdatetimewhen QR was last generated
ready_atdatetimewhen session reached ready
disconnected_atdatetimelast disconnect
metaarray (json)freeform — backend stores extras here

incrementing = false, keyType = 'string'.

Relations

php
$session->messages;   // hasMany WaMessage by session_id
$session->contacts;   // hasMany WaContact by session_id

Helpers

php
$session->isReady();   // status === 'ready'

WaMessage

Kstmostofa\LaravelWhatsApp\Models\WaMessage — one row per inbound or outbound message.

ColumnTypeNotes
idbigint PK
backendstring'web' or 'cloud'
session_idstring fknull for Cloud (no session concept)
wa_message_idstringupstream message ID (wamid or whatsapp-web.js id)
directionstring'inbound' or 'outbound'
chat_idstringconversation key — phone or …@c.us/…@g.us
from_idstringsender
to_idstringrecipient
typestringtext / image / video / audio / document / sticker / location / interactive / system
bodytexttext content or caption
payloadarray (json)full backend payload for round-tripping
statusstringsent / delivered / read / failed (Cloud-style)
ackintwhatsapp-web.js ack level (-1..4)
wa_timestampdatetimewhen WhatsApp says it was sent
deleted_atdatetimesoft-delete (when message was deleted)
deleted_for_everyonebooltrue if remote delete, false for local-only

Scopes

php
WaMessage::inbound()->latest()->take(50)->get();
WaMessage::outbound()->where('status', 'failed')->get();
WaMessage::forChat('9665XXX@c.us')->orderBy('id', 'desc')->paginate(50);

forChat($chatId) is the indexed range scan that powers the conversation UI — fast even at millions of rows.

Relations

php
$message->session;   // belongsTo WaSession

Ack levels reference

ValueConstant on Events\Web\MessageAckMeaningUI rendering
-1ACK_ERRORfailedred !
0ACK_PENDINGqueued client-sideclock
1ACK_SERVERreached WhatsApp serversingle check
2ACK_DEVICEdelivered to recipient devicedouble check (gray)
3ACK_READread by recipientdouble check (blue)
4ACK_PLAYEDvoice note playeddouble check (blue) + headphones icon

WaContact

Kstmostofa\LaravelWhatsApp\Models\WaContact — Web sidecar contacts (Cloud API has no contact list concept).

ColumnTypeNotes
idbigint PK
session_idstring fkwhich Web session this contact is from
wa_idstring9665XXX@c.us
namestringcontact's saved name
pushnamestringWhatsApp profile display name
numberstringE.164 if known
is_businessboolWhatsApp Business account?
is_my_contactboolin your phone's contacts?
is_blockedbool
last_seen_atdatetimebest-effort
metaarray (json)freeform

Relations

php
$contact->session;   // belongsTo WaSession

Custom connection / prefix

Set in env:

bash
WHATSAPP_DB_CONNECTION=whatsapp     # key from config/database.php
WHATSAPP_DB_PREFIX=app_              # prepended to wa_* table names

The UsesWhatsAppConnection trait reads both at runtime — no model rebuild needed. Implementation:

php
public function getConnectionName()
{
    $configured = config('laravel-whatsapp.database.connection');
    return $configured !== null && $configured !== ''
        ? $configured
        : parent::getConnectionName();
}

public function getTable()
{
    $base = $this->table ?? parent::getTable();
    $prefix = (string) config('laravel-whatsapp.database.prefix', '');
    return $prefix === '' ? $base : $prefix.$base;
}

Migrations also honor both — they call Schema::connection(config('laravel-whatsapp.database.connection'))->create($prefix.'wa_messages', …). Apply env values before running migrations or rename the tables manually.

Extending

Need extra columns? Two patterns:

Extend the published migration (recommended):

bash
php artisan vendor:publish --tag=laravel-whatsapp-migrations
# edit database/migrations/2024_*_create_wa_messages_table.php

Or subclass the model:

php
class MyMessage extends \Kstmostofa\LaravelWhatsApp\Models\WaMessage
{
    public function organization()
    {
        return $this->belongsTo(Organization::class);
    }
}

The package itself queries WaMessage::class directly though — your subclass is only visible to your code. For full swap-out, bind it in a service provider:

php
$this->app->bind(\Kstmostofa\LaravelWhatsApp\Models\WaMessage::class, \App\Models\MyMessage::class);

…but the package doesn't currently resolve through the container for model lookups, so most call sites won't pick it up. Filed under "future work" — open an issue if you need it.

Released under the MIT License.