getbizapps/bizwachat-laravel-notification

Laravel notification channel and API client for Bizwachat public API.

Maintainers

Package info

github.com/getbizapps/bizwachat-laravel-notification

pkg:composer/getbizapps/bizwachat-laravel-notification

Statistics

Installs: 5

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

1.0.0 2026-05-20 12:09 UTC

This package is not auto-updated.

Last update: 2026-05-24 16:25:51 UTC


README

Laravel notification channel and API client for the Bizwachat public API.

What this package gives you

  • Native Laravel notification channel for Bizwachat delivery
  • Fluent builders for text, template, and media messages
  • Full access to the public API resources from openapi-3.yaml
  • Centralized exception handling with log entries in every catch block
  • Config-first defaults so developers can send messages with minimal code

Installation

composer require getbizapps/bizwachat-laravel-notification
php artisan vendor:publish --tag=bizwachat-notification-config

Environment

BIZWACHAT_BASE_URL=https://bizwachat.com
BIZWACHAT_SUBDOMAIN=your-subdomain
BIZWACHAT_API_TOKEN=your-public-api-token
BIZWACHAT_TIMEOUT=30
BIZWACHAT_CONNECT_TIMEOUT=10
BIZWACHAT_THROW_EXCEPTIONS=true
BIZWACHAT_LOG_CHANNEL=stack

Notification usage

<?php

namespace App\Notifications;

use BizwaChat\LaravelNotification\Channels\BizwaChatChannel;
use BizwaChat\LaravelNotification\Messages\TemplateMessage;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;

class WelcomeOnWhatsApp extends Notification
{
    use Queueable;

    public function via(object $notifiable): array
    {
        return [BizwaChatChannel::class];
    }

    public function toBizwaChat(object $notifiable): TemplateMessage
    {
        return TemplateMessage::make('welcome_message', 'en')
            ->headerTextParameter($notifiable->name)
            ->fields([
                $notifiable->name,
                'Bizwachat',
            ]);
    }
}

If your model already has a phone number field, the channel will automatically try phone, phone_number, and mobile. If you need explicit routing, define:

public function routeNotificationForBizwaChat(): array
{
    return [
        'phone_number' => $this->phone,
        'subdomain' => $this->tenant_subdomain,
        'from_phone_number_id' => $this->bizwachat_phone_number_id,
    ];
}

Direct API usage

use BizwaChat\LaravelNotification\Facades\BizwaChat;
use BizwaChat\LaravelNotification\Messages\ContactData;

BizwaChat::sendText('+15550001111', 'Hello from Bizwachat', [
    'contact' => ContactData::make()
        ->firstname('John')
        ->lastname('Doe')
        ->email('john@example.com')
        ->groups(['VIP Customers', 'Newsletter']),
]);

$templates = BizwaChat::templates()->list();
$contact = BizwaChat::contacts()->find(15);

Full API surface

The manager exposes the following resource clients:

  • contacts()
  • statuses()
  • sources()
  • groups()
  • templates()
  • templateBots()
  • messageBots()
  • messages()
  • request() / raw() for custom endpoints

Message builders

Simple message

use BizwaChat\LaravelNotification\Facades\BizwaChat;

BizwaChat::send(
    BizwaChat::simple('Order confirmed')->to('+15550001111')
);

Template message

use BizwaChat\LaravelNotification\Facades\BizwaChat;

BizwaChat::send(
    BizwaChat::template('order_confirmation', 'en')
        ->to('+15550001111')
        ->headerTextParameter('John')
        ->fields(['#1001', 'Confirmed'])
        ->button(0, 'https://example.com/orders/1001')
);

Template message from a saved whatsapp_templates record

If your saved template record looks like this:

  • template_name: bizcrmapp_marketing
  • language: en
  • header_data_format: IMAGE
  • header_params_count: 0
  • body_params_count: 0
  • footer_data: bizcrmapp.com
  • buttons_data: two static URL buttons
  • header_file_url: the WhatsApp-hosted image URL

then the package usage should stay minimal because this template has no dynamic body fields and no dynamic button variables:

use BizwaChat\LaravelNotification\Facades\BizwaChat;

BizwaChat::send(
        BizwaChat::template('bizcrmapp_marketing', 'en')
                ->to('+15550001111')
                ->headerImageUrl('https://scontent.whatsapp.net/v/t61.29466-34/555348183_1147308740158118_3156578834425398790_n.png?ccb=1-7&_nc_sid=8b1bef&_nc_ohc=bEQ-iApmfAAQ7kNvwHNG2gs&_nc_oc=AdqyBrCfIsIRnQQEAdNFeTZnZX5ro84xEDQF8wK3Ao6nzqrWOrNRDhke9V96cCXRmF4&_nc_zt=3&_nc_ht=scontent.whatsapp.net&edm=AH51TzQEAAAA&_nc_gid=KYRZ6mVxGzG2iXeRPvCb9Q&_nc_tpa=Q5bMBQHuEc1BU6sBiuF3ezRGuATYAzfFNK2ZpjjSvrsp5Qju4iwUeAIr3Z0e3wXC2tJFIP9qJ6U7yfyCRA&oh=01_Q5Aa4gFzD2Izp0vef3Jdk2jnLMeeClkMqOGGLcSq-oQ9STochQ&oe=6A2B8042')
);

The request payload generated by the package is:

{
    "phone_number": "+15550001111",
    "template_name": "bizcrmapp_marketing",
    "template_language": "en",
    "header_image_url": "https://scontent.whatsapp.net/v/t61.29466-34/555348183_1147308740158118_3156578834425398790_n.png?ccb=1-7&_nc_sid=8b1bef&_nc_ohc=bEQ-iApmfAAQ7kNvwHNG2gs&_nc_oc=AdqyBrCfIsIRnQQEAdNFeTZnZX5ro84xEDQF8wK3Ao6nzqrWOrNRDhke9V96cCXRmF4&_nc_zt=3&_nc_ht=scontent.whatsapp.net&edm=AH51TzQEAAAA&_nc_gid=KYRZ6mVxGzG2iXeRPvCb9Q&_nc_tpa=Q5bMBQHuEc1BU6sBiuF3ezRGuATYAzfFNK2ZpjjSvrsp5Qju4iwUeAIr3Z0e3wXC2tJFIP9qJ6U7yfyCRA&oh=01_Q5Aa4gFzD2Izp0vef3Jdk2jnLMeeClkMqOGGLcSq-oQ9STochQ&oe=6A2B8042"
}

Important mapping rules for templates like this:

  • header_data_format = IMAGE means you send header_image_url or header_image_file.
  • body_params_count = 0 means you do not send any field_1, field_2, or other body parameters.
  • Static URL buttons from buttons_data stay inside the approved WhatsApp template, so you do not send button_0 or button_1 unless the button itself contains a dynamic variable.
  • footer_data is already part of the approved template, so it is not sent again in the API payload.

Template message with image header and one body variable

If the saved template record looks like this:

  • template_name: campaign_launch_bizcrmwa
  • language: en
  • header_data_format: IMAGE
  • header_params_count: 0
  • body_params_count: 1
  • buttons_data: one static URL button
  • body_variable_value: [["Bhavik"]]

then the package call is:

use BizwaChat\LaravelNotification\Facades\BizwaChat;

BizwaChat::send(
        BizwaChat::template('campaign_launch_bizcrmwa', 'en')
                ->to('+15550001111')
                ->headerImageUrl('https://scontent.whatsapp.net/v/t61.29466-34/417302034_550415017882935_4035659379883741642_n.png?ccb=1-7&_nc_sid=8b1bef&_nc_ohc=voABktHdO20Q7kNvwHRduyz&_nc_oc=Adqx5gokS4hjKiw1soHtgMPfagoTkOvkAsmbljMbYwtMyORJgCuCmzzPpHcln_k8ATY&_nc_zt=3&_nc_ht=scontent.whatsapp.net&edm=AH51TzQEAAAA&_nc_gid=KYRZ6mVxGzG2iXeRPvCb9Q&_nc_tpa=Q5bMBQFi_9cKw0mNZ6x77kSqgK6TNPDBqQDriF1Wyihl_h9G_tCqKj8IGv1tZHPtSB2GrJsplXkKk4zGiQ&oh=01_Q5Aa4gGEwCYaYevvzzX05ccPzbT4ytR8O4_JaJUArnWXIX1rYQ&oe=6A2B6D7C')
                ->field(1, 'Bhavik')
);

The payload generated by the package is:

{
    "phone_number": "+15550001111",
    "template_name": "campaign_launch_bizcrmwa",
    "template_language": "en",
    "header_image_url": "https://scontent.whatsapp.net/v/t61.29466-34/417302034_550415017882935_4035659379883741642_n.png?ccb=1-7&_nc_sid=8b1bef&_nc_ohc=voABktHdO20Q7kNvwHRduyz&_nc_oc=Adqx5gokS4hjKiw1soHtgMPfagoTkOvkAsmbljMbYwtMyORJgCuCmzzPpHcln_k8ATY&_nc_zt=3&_nc_ht=scontent.whatsapp.net&edm=AH51TzQEAAAA&_nc_gid=KYRZ6mVxGzG2iXeRPvCb9Q&_nc_tpa=Q5bMBQFi_9cKw0mNZ6x77kSqgK6TNPDBqQDriF1Wyihl_h9G_tCqKj8IGv1tZHPtSB2GrJsplXkKk4zGiQ&oh=01_Q5Aa4gGEwCYaYevvzzX05ccPzbT4ytR8O4_JaJUArnWXIX1rYQ&oe=6A2B6D7C",
    "field_1": "Bhavik"
}

Mapping rules for this case:

  • body_params_count = 1 means send exactly one body placeholder as field_1.
  • The static website button from buttons_data is already part of the approved template, so there is still no button_0 in the request payload.
  • The footer text is part of the template approval record and is not sent again.

Utility template with static text header and five body variables

If the saved template record looks like this:

  • template_name: bizcrm_subscription_order
  • language: en_US
  • category: UTILITY
  • header_data_format: TEXT
  • header_data_text: Assistance with Your BizCRM WhatsApp Setup
  • header_params_count: 0
  • body_params_count: 5
  • buttons_data: one static PHONE_NUMBER button
  • body_variable_value: [["Bhavik","successfully","Starter","Monthly","Dec 10, 2024"]]

then the package call is:

use BizwaChat\LaravelNotification\Facades\BizwaChat;

BizwaChat::send(
        BizwaChat::template('bizcrm_subscription_order', 'en_US')
                ->to('+15550001111')
                ->fields([
                        'Bhavik',
                        'successfully',
                        'Starter',
                        'Monthly',
                        'Dec 10, 2024',
                ])
);

The payload generated by the package is:

{
    "phone_number": "+15550001111",
    "template_name": "bizcrm_subscription_order",
        "template_language": "en_US",
    "field_1": "Bhavik",
    "field_2": "successfully",
    "field_3": "Starter",
    "field_4": "Monthly",
    "field_5": "Dec 10, 2024"
}

Mapping rules for this case:

  • header_data_format = TEXT with header_params_count = 0 means the header text is already fixed in the approved template, so you do not send header_field_1.
  • body_params_count = 5 means send exactly field_1 through field_5.
  • The PHONE_NUMBER button is static, so you do not send any button_0 value.
  • The footer text is part of the approved template and is not sent again.

Document header template with a dynamic URL button variable

For a document-header template with these characteristics:

  • template_name: invoice_share_with_portal
  • language: en
  • header_data_format: DOCUMENT
  • header_params_count: 0
  • body_params_count: 2
  • buttons_data: one dynamic URL button like https://portal.example.com/invoices/{{1}}

the package call is:

use BizwaChat\LaravelNotification\Facades\BizwaChat;

BizwaChat::send(
        BizwaChat::template('invoice_share_with_portal', 'en')
                ->to('+15550001111')
                ->headerDocumentUrl('https://cdn.example.com/invoices/INV-1001.pdf', 'Invoice_INV-1001.pdf')
                ->fields([
                        'Bhavik',
                        'INV-1001',
                ])
                ->button(0, 'INV-1001')
);

The payload generated by the package is:

{
    "phone_number": "+15550001111",
    "template_name": "invoice_share_with_portal",
    "template_language": "en",
    "header_document_url": "https://cdn.example.com/invoices/INV-1001.pdf",
    "header_document_name": "Invoice_INV-1001.pdf",
    "field_1": "Bhavik",
    "field_2": "INV-1001",
    "button_0": "INV-1001"
}

Mapping rules for this case:

  • header_data_format = DOCUMENT means send header_document_url or header_document_file.
  • header_document_name is optional but useful for display when the header is a document.
  • body_params_count = 2 means send field_1 and field_2.
  • A dynamic URL button variable becomes button_0, button_1, and so on, based on the button index in the approved template.

Media message

use BizwaChat\LaravelNotification\Messages\MediaMessage;

BizwaChat::send(
    MediaMessage::image('https://cdn.example.com/product.jpg')
        ->to('+15550001111')
        ->caption('Latest catalog')
);

Logging and exceptions

  • Every transport, route-resolution, dispatch, and notification catch block writes a structured log entry.
  • Set BIZWACHAT_LOG_CHANNEL to a dedicated channel if you want package-specific log routing.
  • Leave BIZWACHAT_THROW_EXCEPTIONS=true for fail-fast behavior.
  • Set BIZWACHAT_THROW_EXCEPTIONS=false to receive failed ApiResponse objects instead of thrown exceptions.