PHPackages                             kalindussasinindu/laravel-dcb-lk - 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. [Payment Processing](/categories/payments)
4. /
5. kalindussasinindu/laravel-dcb-lk

ActiveLibrary[Payment Processing](/categories/payments)

kalindussasinindu/laravel-dcb-lk
================================

Direct Carrier Billing for Sri Lanka (Ideamart &amp; mSpace) - OTP subscription verification, status polling, and webhooks, behind one driver interface.

v1.1.0(today)02↑2900%MITPHPPHP ^8.2CI passing

Since Aug 28Pushed todayCompare

[ Source](https://github.com/kalinduSsasinindu/laravel-dcb-lk)[ Packagist](https://packagist.org/packages/kalindussasinindu/laravel-dcb-lk)[ RSS](/packages/kalindussasinindu-laravel-dcb-lk/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (5)Versions (3)Used By (0)

laravel-dcb-lk
==============

[](#laravel-dcb-lk)

[![tests](https://github.com/kalinduSsasinindu/laravel-dcb-lk/actions/workflows/tests.yml/badge.svg)](https://github.com/kalinduSsasinindu/laravel-dcb-lk/actions/workflows/tests.yml)[![Latest Version](https://camo.githubusercontent.com/d80ab3f7dcf11816b8414be44d8921d6658f209d5b51cfc3a6bdff084535d1e5/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6b616c696e647573736173696e696e64752f6c61726176656c2d6463622d6c6b)](https://packagist.org/packages/kalindussasinindu/laravel-dcb-lk)[![License](https://camo.githubusercontent.com/d1214a610d41df6da05cdaacce13a69d6871d13153ac0d87c9c941de1bf11788/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6b616c696e647573736173696e696e64752f6c61726176656c2d6463622d6c6b)](LICENSE)

Direct Carrier Billing for Sri Lanka - a single Laravel driver interface over **Ideamart** and **mSpace** (both hSenid Mobile platforms), covering OTP subscription registration, status polling, and inbound webhooks.

This is an **unofficial**, community package - not published or endorsed by hSenid Mobile, Ideamart, or mSpace.

Why
---

[](#why)

Neither provider ships a real Composer/Laravel package - just a "sample app" per language on GitHub. This wraps both behind one interface, with the sharp edges (masked subscriber IDs, inconsistent phone number formats, an undocumented "INITIAL CHARGING PENDING" status, mSpace's OTP-is-root-level- but-subscription-is-nested URL layout) already handled.

Install
-------

[](#install)

```
composer require kalindussasinindu/laravel-dcb-lk
php artisan vendor:publish --tag=dcb-lk-config
```

Add your credentials to `.env`:

```
DCB_LK_DRIVER=ideamart

IDEAMART_APP_ID=
IDEAMART_PASSWORD=
IDEAMART_WEBHOOK_SECRET=

MSPACE_APP_ID=
MSPACE_PASSWORD=
MSPACE_WEBHOOK_SECRET=
```

See `config/dcb-lk.php` for every available option (SMS credentials, OTP metadata defaults, base URLs).

Usage
-----

[](#usage)

```
use DcbLk\Facades\DcbLk;
use DcbLk\Support\SubscriberId;

// Uses config('dcb-lk.default') - or DcbLk::driver('mspace') for a specific one.
$response = DcbLk::requestOtp(SubscriberId::fromPhone('0771234567'));

if ($response->successful()) {
    $referenceNo = $response->get('referenceNo');
}
```

```
$response = DcbLk::verifyOtp($referenceNo, $otpFromUser);

if ($response->successful()) {
    // Ideamart returns a masked tel:... id here - store it verbatim,
    // getStatus/send need that exact id, not the plain phone number.
    $subscriberId = $response->get('subscriberId');
}
```

```
$status = DcbLk::getStatus($subscriberId);

if ($status->successful()) {
    $subscriptionStatus = \DcbLk\Data\SubscriptionStatus::fromCarrierString(
        $status->get('subscriptionStatus')
    );

    if ($subscriptionStatus->isActive()) {
        // grant access
    }
}
```

### Webhooks

[](#webhooks)

Both carriers push subscription lifecycle changes to a URL you register on their portal. `WebhookPayload` verifies the shared secret and parses the payload - finding/updating your own subscriber record is up to you:

```
use DcbLk\Webhooks\WebhookPayload;
use Illuminate\Http\Request;

Route::post('/webhooks/ideamart', function (Request $request) {
    $payload = WebhookPayload::fromRequest(
        $request,
        config('dcb-lk.drivers.ideamart.webhook_secret'),
    );

    if (!$payload->verified) {
        return response()->json(['statusCode' => 'E1001', 'statusDetail' => 'UNAUTHORIZED'], 403);
    }

    $subscription = Subscription::whereIn('subscriber_id', $payload->lookupVariants())->first();

    if ($subscription && $payload->status) {
        // e.g. $payload->status->isActive() ? grant() : revoke();
    }

    return response()->json(['statusCode' => 'S1000', 'statusDetail' => 'SUCCESS']);
});
```

**You must set `IDEAMART_WEBHOOK_SECRET`/`MSPACE_WEBHOOK_SECRET` in `.env`and register the exact same value with the carrier's portal alongside your webhook URL.** `$payload->verified` fails closed: if the secret isn't configured, `verified` is always `false` rather than "verification skipped" - a webhook route is a public URL, and without a secret anyone who finds it can POST a forged `subscriberId`/`status` and have your app act on it as if it came from the carrier. Always check `$payload->verified`before touching your own data, as in the example above.

### Adding another provider

[](#adding-another-provider)

Ideamart and mSpace are the two built-in drivers, but the manager isn't closed for extension - register any other `CarrierDriver` (a different DCB gateway, an alternate/v2 implementation of an existing one, a test double) from your own `AppServiceProvider::boot()`, no fork required:

```
use DcbLk\Contracts\CarrierDriver;
use DcbLk\Facades\DcbLk;
use Illuminate\Contracts\Foundation\Application;

DcbLk::extend('dialog', function (Application $app, array $config) {
    return new DialogDriver($config); // implements CarrierDriver
});
```

Add a matching `dcb-lk.drivers.dialog` entry to your published config (or read your own env vars inside the closure instead) and set `DCB_LK_DRIVER=dialog` - or pass `'dialog'` explicitly to `DcbLk::driver()`. `extend()` can also override a built-in name, e.g. to swap in your own `IdeamartDriver` subclass without touching this package.

If your driver fits the same request/response shape as Ideamart/mSpace (`{statusCode, statusDetail, ...}` JSON over HTTP), extending `DcbLk\Drivers\AbstractCarrierDriver` gets you the shared HTTP/logging/ error-handling for free - implement just the URL-building methods, as `IdeamartDriver`/`MSpaceDriver` do. Otherwise implement `CarrierDriver`directly.

### Grace periods for a `PENDING`/`TEMPORARY_BLOCKED` status

[](#grace-periods-for-a-pendingtemporary_blocked-status)

Both of those mean "might resolve on its own" (a failed charge retry, a temporary hold), not "cut off now" - `BLOCKED`/`UNREGISTERED` are the permanent ones (`SubscriptionStatus::isTerminal()`). Whether to keep granting access for N days while a subscription sits in `PENDING` is a product decision your app owns - this package just tells you which bucket a status falls into, not what to do about it.

Testing
-------

[](#testing)

```
composer install
composer test
```

License
-------

[](#license)

MIT.

###  Health Score

41

—

FairBetter than 87% of packages

Maintenance100

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity47

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

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.

###  Release Activity

Cadence

Every ~0 days

Total

2

Last Release

0d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/174706336?v=4)[kalindu sasinindu](/maintainers/kalinduSsasinindu)[@kalinduSsasinindu](https://github.com/kalinduSsasinindu)

---

Top Contributors

[![kalinduSsasinindu](https://avatars.githubusercontent.com/u/174706336?v=4)](https://github.com/kalinduSsasinindu "kalinduSsasinindu (10 commits)")

---

Tags

laravelotpsubscriptioncarrier billingsri-lankadcbideamartmspacehsenid

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/kalindussasinindu-laravel-dcb-lk/health.svg)

```
[![Health](https://phpackages.com/badges/kalindussasinindu-laravel-dcb-lk/health.svg)](https://phpackages.com/packages/kalindussasinindu-laravel-dcb-lk)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3345.4M354](/packages/psalm-plugin-laravel)[laravel/mcp

Rapidly build MCP servers for your Laravel applications.

80427.1M252](/packages/laravel-mcp)[defstudio/telegraph

A laravel facade to interact with Telegram Bots

818355.4k3](/packages/defstudio-telegraph)[api-platform/laravel

API Platform support for Laravel

58190.1k21](/packages/api-platform-laravel)[forjedio/inertia-table

Backend-driven dynamic tables for Laravel + Inertia.js

272.0k](/packages/forjedio-inertia-table)

PHPackages © 2026

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