PHPackages                             ux2dev/link-mobility - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. ux2dev/link-mobility

ActiveLibrary

ux2dev/link-mobility
====================

PHP library for the LINK Mobility MessageHub API (SMS, Viber, Push, Voice/TTS, delivery reports, two-way callbacks)

00

Since Jul 18Compare

[ Source](https://github.com/ux2dev/link-mobility)[ Packagist](https://packagist.org/packages/ux2dev/link-mobility)[ RSS](/packages/ux2dev-link-mobility/feed)WikiDiscussions Synced today

READMEChangelogDependenciesVersions (1)Used By (0)

LINK Mobility MessageHub - PHP / Laravel client
===============================================

[](#link-mobility-messagehub---php--laravel-client)

A framework-agnostic PHP client for the [LINK Mobility MessageHub API](https://documentation.msghub.cloud/)with an optional, opinionated Laravel integration. Send SMS, Viber (text + templates), Push and Voice/TTS messages; query delivery status; manage Viber templates; and parse inbound callbacks (delivery reports, two-way/MO messages, template approvals) into typed objects - with optional Eloquent persistence.

- **Core** (`Ux2Dev\LinkMobility\`): no Laravel required, built on PSR-18 / PSR-17.
- **Laravel layer** (`Ux2Dev\LinkMobility\Laravel\`): facade, callback route, events, opt-in queued persistence, models, migrations, and Artisan commands.

Requirements
------------

[](#requirements)

- PHP `^8.1`, `ext-openssl`, `ext-json`
- A PSR-18 HTTP client + PSR-17 factories (e.g. `guzzlehttp/guzzle ^7`)

Installation
------------

[](#installation)

```
composer require ux2dev/link-mobility
```

For Laravel, publish the config (and optionally the migrations / routes):

```
php artisan vendor:publish --tag=link-mobility-config
php artisan vendor:publish --tag=link-mobility-migrations   # optional persistence
php artisan vendor:publish --tag=link-mobility-routes       # optional custom routes
```

Configuration
-------------

[](#configuration)

Set these in `.env`:

```
LINK_MOBILITY_ENV=production          # or "testing"
LINK_MOBILITY_API_KEY=your-api-key
LINK_MOBILITY_API_SECRET=your-api-secret
LINK_MOBILITY_SERVICE_ID=1            # optional default service_id
LINK_MOBILITY_SC=YourSender          # optional default sender / shortcode

# Optional webhook protection (see "Callbacks" below)
LINK_MOBILITY_WEBHOOK_SECRET=
LINK_MOBILITY_WEBHOOK_TOKEN=

# Optional persistence
LINK_MOBILITY_PERSIST=false
```

Authentication is automatic: every request is signed with `x-api-sign = HMAC-SHA512(rawJsonBody, api_secret)` and sent with your `x-api-key`.

Sending messages
----------------

[](#sending-messages)

### Laravel (facade)

[](#laravel-facade)

```
use Ux2Dev\LinkMobility\Laravel\Facades\LinkMobility;
use Ux2Dev\LinkMobility\Message\SmsMessage;

$result = LinkMobility::send(
    SmsMessage::to('359888123456')
        ->text('Hello from MessageHub')
        ->callbackUrl(route('link-mobility.callback'))
);

$result->smsId;      // "light-5b83e6df35fe41.14520017"
$result->requestId;
$result->isOk();     // meta.code === 200
```

### Framework-agnostic core

[](#framework-agnostic-core)

```
use GuzzleHttp\Client as Guzzle;
use GuzzleHttp\Psr7\HttpFactory;
use Ux2Dev\LinkMobility\Client;
use Ux2Dev\LinkMobility\Config\Config;
use Ux2Dev\LinkMobility\Enum\Environment;
use Ux2Dev\LinkMobility\Message\SmsMessage;

$factory = new HttpFactory();
$client = new Client(
    new Config('api-key', 'api-secret', Environment::Production, defaultServiceId: '1'),
    new Guzzle(),
    $factory,   // PSR-17 request factory
    $factory,   // PSR-17 stream factory
);

$result = $client->send(SmsMessage::to('359888123456')->text('Hi'));
```

### Channels

[](#channels)

```
use Ux2Dev\LinkMobility\Message\{SmsMessage, ViberMessage, PushMessage, TtsMessage};
use Ux2Dev\LinkMobility\Enum\Priority;

// SMS
SmsMessage::to('359888123456')->text('Hi')
    ->priority(Priority::High)->delay('+11 hours')->unique();

// Viber text (with SMS fallback)
ViberMessage::to('359888123456')->sc('ViberTest')->text('Viber message')
    ->ttl(120)->platform(1)->fallbackSms('SMS fallback');

// Viber template
ViberMessage::to('359888123456')->sc('ViberTest')
    ->template('6c929cef-29b4-4349-bc9d-2a07bdbb6e43', ['pin' => '123456'], 'bg')
    ->fallbackSms('Your code: 123456');

// Push
PushMessage::create()->sc('PushTest')
    ->title('Title')->body('Body')->uid('cloud.msghub.example_dfXXXXX')
    ->redirectUrl('https://example.com')->fallbackSms('SMS fallback');

// Voice / Text-to-Speech
TtsMessage::to('359888123456')->sc('VoiceTest')->text('Spoken message')
    ->fallbackSms('SMS fallback');
```

For Viber rich content (carousels, surveys, buttons) not yet modelled as typed builders, use `ViberMessage::rich([...])` to merge a structured array into the payload.

### Batch send &amp; delivery status

[](#batch-send--delivery-status)

```
$results = LinkMobility::sendMany($msgA, $msgB, $msgC);   // array

$dlr = LinkMobility::dlr('light-5b83e6df35fe41.14520017');
$dlr->status;        // DlrStatus enum (Delivered, Undelivered, ...)
$dlr->status?->isDelivered();
```

### Viber templates

[](#viber-templates)

```
$templates = LinkMobility::viberTemplates();
$templates->create([...]);   // POST /viber_templates/create
$templates->get([...]);      // POST /viber_templates/get
$templates->delete([...]);   // POST /viber_templates/delete
```

Callbacks (delivery reports, two-way messages, template approvals)
------------------------------------------------------------------

[](#callbacks-delivery-reports-two-way-messages-template-approvals)

Point your `callback_url` (and LINK Mobility's MO / template webhooks) at the package route: `POST /{prefix}/callback` (default prefix `link-mobility`, so `/link-mobility/callback`). The controller parses the payload, dispatches events, and - for MO - can return a synchronous reply.

### Webhook authentication

[](#webhook-authentication)

Verification is **opt-in and fail-closed**:

- Set `LINK_MOBILITY_WEBHOOK_SECRET` to require a valid `x-api-sign` HMAC-SHA512 over the raw body on **every** callback. Missing or invalid ⇒ `401`.
- Otherwise set `LINK_MOBILITY_WEBHOOK_TOKEN` and configure your callback URLs with `?token=`.
- With neither set, the endpoint is unauthenticated (dev only) - secure it before production.

### Events

[](#events)

EventFired for`DeliveryReportReceived`every DLR callback`MessageDelivered`DLR with status = delivered`MessageUndelivered`DLR in a final non-delivered state`InboundMessageReceived`MO / two-way inbound message`TemplateStatusChanged`Viber template approval/decline```
use Ux2Dev\LinkMobility\Laravel\Events\MessageDelivered;

Event::listen(MessageDelivered::class, function (MessageDelivered $e) {
    $e->report->smsId;
    $e->report->status;   // DlrStatus
});
```

### Two-way replies

[](#two-way-replies)

Bind an `InboundMessageHandler`; its return value becomes the synchronous reply LINK Mobility sends back to the sender (return `null` for no reply):

```
use Ux2Dev\LinkMobility\Callback\Contracts\InboundMessageHandler;
use Ux2Dev\LinkMobility\Callback\InboundMessage;

$this->app->bind(InboundMessageHandler::class, fn () => new class implements InboundMessageHandler {
    public function handle(InboundMessage $message): ?string
    {
        return "You said: {$message->text}";
    }
});
```

### Parsing callbacks without Laravel

[](#parsing-callbacks-without-laravel)

The parser is part of the framework-agnostic core:

```
use Ux2Dev\LinkMobility\Callback\CallbackParser;

$event = CallbackParser::parse($decodedJsonBody);
// => DeliveryReport | InboundMessage | TemplateStatusUpdate
```

Optional persistence
--------------------

[](#optional-persistence)

Ship-and-forget storage for callbacks. Publish + run the migrations, then enable it:

```
LINK_MOBILITY_PERSIST=true
```

When enabled, queued listeners write to four tables/models (`OutboundMessage`, `DeliveryReport`, `InboundMessage`, `ViberTemplate`). Delivery reports link back to outbound messages by `sms_id`. Everything is optional - the package is fully functional without the database.

Artisan commands
----------------

[](#artisan-commands)

```
php artisan link-mobility:status                 # show resolved config + base URL
php artisan link-mobility:send-test 359888123456 --text="Hello"
```

Exceptions
----------

[](#exceptions)

All extend `Ux2Dev\LinkMobility\Exception\LinkMobilityException`:

ExceptionMeaning`ApiException`Non-2xx HTTP or `meta.code >= 400` (exposes `metaCode`, `metaText`, `requestId`, `httpStatus`)`TransportException`PSR-18 client / network failure`SignatureException`Empty signing secret`ConfigurationException`Missing/invalid credentials`InvalidResponseException`Malformed JSON`UnrecognizedCallbackException`Callback payload not identifiable as DLR / MO / templateTesting &amp; static analysis
-----------------------------

[](#testing--static-analysis)

```
composer install
composer test      # Pest test suite
composer stan      # PHPStan (level max, via Larastan)
composer rector    # Rector - preview refactors (dry-run)
composer check     # stan + test
```

The shipped code under `src/` is analysed at **PHPStan level max** and is clean.

License
-------

[](#license)

MIT. See [LICENSE](LICENSE).

###  Health Score

9

—

LowBetter than 0% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity0

Limited adoption so far

Community2

Small or concentrated contributor base

Maturity11

Early-stage or recently created project

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/181749481?v=4)[ux2dev](/maintainers/ux2dev)[@ux2dev](https://github.com/ux2dev)

### Embed Badge

![Health badge](/badges/ux2dev-link-mobility/health.svg)

```
[![Health](https://phpackages.com/badges/ux2dev-link-mobility/health.svg)](https://phpackages.com/packages/ux2dev-link-mobility)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
