PHPackages                             padosoft/laravel-rebel-channel-bird - 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. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. padosoft/laravel-rebel-channel-bird

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

padosoft/laravel-rebel-channel-bird
===================================

Bird (formerly MessageBird) provider for Laravel Rebel Channels: phone verification via the Bird Verify API (SMS), plain SMS delivery, and signed delivery-status webhooks. Part of padosoft/laravel-rebel-\*.

v0.1.0(1mo ago)02[1 PRs](https://github.com/padosoft/laravel-rebel-channel-bird/pulls)MITPHPPHP ^8.3CI passing

Since Jun 4Pushed 1mo agoCompare

[ Source](https://github.com/padosoft/laravel-rebel-channel-bird)[ Packagist](https://packagist.org/packages/padosoft/laravel-rebel-channel-bird)[ Docs](https://github.com/padosoft/laravel-rebel-channel-bird)[ RSS](/packages/padosoft-laravel-rebel-channel-bird/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (1)Dependencies (10)Versions (3)Used By (0)

Laravel Rebel — Bird Channel
============================

[](#laravel-rebel--bird-channel)

> Official documentation:

> **Send phone verifications through Bird (formerly MessageBird), the Rebel way.** This package plugs the [Bird Verify API](https://docs.bird.com/api/verify-api) (SMS OTP) and Bird SMS delivery into [`laravel-rebel-channels`](https://github.com/padosoft/laravel-rebel-channels) as a `VerificationProvider` + `MessageDeliveryChannel` — so you get Bird's global delivery *plus* Rebel's fraud guard, rate limiting, fallback and audit on top. Part of the `padosoft/laravel-rebel-*` suite.

 [![Laravel Rebel](resources/screenshoots/Laravel-Rebel-banner.png)](resources/screenshoots/Laravel-Rebel-banner.png)

 [![Laravel 12|13](https://camo.githubusercontent.com/9e9b743bcbf97a29fe735334a4a8e906d05d60310969905af6607cef8da30138/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d313225323025374325323031332d4646324432303f7374796c653d666c61742d737175617265266c6f676f3d6c61726176656c266c6f676f436f6c6f723d7768697465)](https://camo.githubusercontent.com/9e9b743bcbf97a29fe735334a4a8e906d05d60310969905af6607cef8da30138/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d313225323025374325323031332d4646324432303f7374796c653d666c61742d737175617265266c6f676f3d6c61726176656c266c6f676f436f6c6f723d7768697465) [![PHP 8.3+](https://camo.githubusercontent.com/6aa777dd33ef43fbef727d8187b578003a61e5dc41bbc958b0938c996cdc92f2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e33253230253743253230382e34253230253743253230382e352d3737374242343f7374796c653d666c61742d737175617265266c6f676f3d706870266c6f676f436f6c6f723d7768697465)](https://camo.githubusercontent.com/6aa777dd33ef43fbef727d8187b578003a61e5dc41bbc958b0938c996cdc92f2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e33253230253743253230382e34253230253743253230382e352d3737374242343f7374796c653d666c61742d737175617265266c6f676f3d706870266c6f676f436f6c6f723d7768697465) [![PHPStan max](https://camo.githubusercontent.com/4b9a3c97d76534abb905e64bd9e5bb9f13fe68e962071e0ccbbe7b629112f11c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6d61782d3241364644423f7374796c653d666c61742d737175617265)](https://camo.githubusercontent.com/4b9a3c97d76534abb905e64bd9e5bb9f13fe68e962071e0ccbbe7b629112f11c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6d61782d3241364644423f7374796c653d666c61742d737175617265) [![Pest 4](https://camo.githubusercontent.com/9b9da1d7d243a7465ab338e9374e47300a7fe2e26b5c291e7e3c95b53153789a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f74657374732d50657374253230342d3232433535453f7374796c653d666c61742d737175617265)](https://camo.githubusercontent.com/9b9da1d7d243a7465ab338e9374e47300a7fe2e26b5c291e7e3c95b53153789a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f74657374732d50657374253230342d3232433535453f7374796c653d666c61742d737175617265) [![Bird Verify](https://camo.githubusercontent.com/b69fa8bda176196ddc11a693baef306393922eec3d5073cc9d8876e6432ab793/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f426972642d5665726966792d3234383146353f7374796c653d666c61742d737175617265)](https://camo.githubusercontent.com/b69fa8bda176196ddc11a693baef306393922eec3d5073cc9d8876e6432ab793/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f426972642d5665726966792d3234383146353f7374796c653d666c61742d737175617265) [![MIT](https://camo.githubusercontent.com/ac049ef4e7a0b7196b09add6ac2d4f180e544c0ac779c2b2ac2fd2723a209579/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75653f7374796c653d666c61742d737175617265)](https://camo.githubusercontent.com/ac049ef4e7a0b7196b09add6ac2d4f180e544c0ac779c2b2ac2fd2723a209579/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75653f7374796c653d666c61742d737175617265)

---

Table of contents
-----------------

[](#table-of-contents)

- [What it is](#what-it-is)
- [Quick glossary](#quick-glossary)
- [How it works (step by step)](#how-it-works-step-by-step)
- [Why this package](#why-this-package)
- [Rebel + Bird vs the alternatives](#rebel--bird-vs-the-alternatives)
- [Bird dashboard setup (step by step)](#bird-dashboard-setup-step-by-step)
- [Installation](#installation)
- [Configuration](#configuration)
- [Usage](#usage)
- [Delivery receipts (status webhook)](#delivery-receipts-status-webhook)
- [Live tests against the real API](#live-tests-against-the-real-api)
- [`.env.example`](#envexample)
- [Security notes](#security-notes)
- [🔋 Vibe coding with batteries included](#-vibe-coding-with-batteries-included)
- [Testing &amp; License](#testing--license)

---

What it is
----------

[](#what-it-is)

A thin, well-tested **Bird Verify** provider for Rebel Channels. You don't call it directly — you call the Channels `VerificationRouter`, and it routes through this provider (with Rebel's bot gate, IRSF defences, per-number rate limit, fallback and audit around it).

A small **gateway seam** (`BirdGateway`) wraps Bird's REST API (Verify + Messaging) over Laravel's HTTP client, so the whole thing is unit-testable offline and has a real **live** test-suite for the actual API. The same provider also implements `MessageDeliveryChannel`, so you can send a plain SMS through Bird with one call.

Depends on [`padosoft/laravel-rebel-core`](https://github.com/padosoft/laravel-rebel-core)and [`padosoft/laravel-rebel-channels`](https://github.com/padosoft/laravel-rebel-channels).

---

Quick glossary
--------------

[](#quick-glossary)

TermIn plain words**Bird / MessageBird**A global CPaaS (SMS / voice / WhatsApp). "Bird" is the current brand; the REST API is the former "MessageBird" one.**Bird Verify**A Bird product that sends and checks one-time codes for you — you never store or generate the OTP.**Access key**Your Bird API credential (Developers → API access). `test_…` keys hit the sandbox.**Originator**The sender id shown to the recipient: an alphanumeric name (≤11 chars) or a number you own.**Verify id**The handle Bird returns for an in-flight verification — you pass it back when checking the code.**OTP**One-Time Password — the short numeric code the user types in to prove they own the number.---

How it works (step by step)
---------------------------

[](#how-it-works-step-by-step)

```
 user types phone               your app                 Rebel Channels            Bird Verify API
 ───────────────►  VerificationRouter::start()  ──►  BirdVerifyProvider::start  ──►  POST /verify
                                                                                       │ sends SMS OTP
                          ◄── VerificationResult::started(reference = verify id) ──────┘

 user types code               your app                 Rebel Channels            Bird Verify API
 ───────────────►  VerificationRouter::check()  ──►  BirdVerifyProvider::check  ──►  GET /verify/{id}?token=…
                          ◄── VerificationResult::approve()  /  ::deny() ─────────────┘

 Bird, later  ──►  POST /rebel/bird/status (signed)  ──►  BirdStatusController  ──►  audit: delivered / cost

```

1. **Start** — you call the router; the provider calls Bird Verify, which sends the OTP and returns a **verify id**. The router hands you that id as the `reference` (store it in the session).
2. **Check** — you call the router with the code the user typed and the saved reference; the provider asks Bird whether the token matches and returns approve / deny.
3. **Receipt** — separately, Bird calls your **status webhook** when the SMS is actually delivered (or fails), and the package records an audit event with the cost so the admin panel shows real numbers.

---

Why this package
----------------

[](#why-this-package)

★WhatIn short★★★**Bird Verify, fully wrapped**Start + check codes over SMS; you never handle the OTP yourself.★★★**Rebel guarantees for free**Inherits the Channels fraud guard (IRSF), rate limit, fallback and HMAC'd audit.★★**Plain SMS too**Implements `MessageDeliveryChannel`, so `send()` delivers any SMS through Bird.★★**Never throws out**Any transport/API error becomes a clean `provider_error`, so the router can fall back to another provider.★★**Offline-testable**A gateway seam + fake means your tests don't hit Bird; a separate live suite does.★★**Safe by default**No access key → nothing registers, and no authenticated client is ever built.★**Explicit status mapping**Bird statuses are mapped deliberately (an unexpected status is a failure, not a fake "pending").---

Rebel + Bird vs the alternatives
--------------------------------

[](#rebel--bird-vs-the-alternatives)

Sending an OTP with Bird, four ways:

Capability**Rebel + this package**ShopifyBird Verify SDK (direct)Raw Bird SMS + your own OTPSend/check a code via Bird✅❌✅➖ (you build OTP logic)You never store/generate the OTP✅✅✅❌Anti toll-fraud / IRSF guard✅❌❌❌Per-number rate limit + bot gate✅➖❌❌**Provider fallback** to another vendor✅❌❌❌Signed, phone-bound reference (anti replay)✅❌❌❌Unified audit trail (number HMAC'd)✅❌❌❌Delivery receipts + cost into the admin panel✅❌➖➖Graceful failure → router fallback✅❌❌❌> Legend: ✅ built-in · ➖ partial / hosted-only · ❌ not available. Bird is excellent at delivery; this package keeps all of that and adds the Rebel fraud/routing/audit layer around it. Shopify is a closed, hosted commerce platform: it sends its own customer OTPs but lets you neither pick Bird as the sender, self-host it, fall back across vendors, nor configure its fraud controls — a black box, not a developer-facing verification library.

---

Bird dashboard setup (step by step)
-----------------------------------

[](#bird-dashboard-setup-step-by-step)

1. **Create a Bird account** at [bird.com](https://bird.com). The free/sandbox tier gives you a `test_…` access key to integrate without spending credit.
2. **Grab your access key**: in the Bird dashboard go to **Developers → API access** and copy your **live** access key (or a `test_…` key for the sandbox).
3. **Pick an originator**: an alphanumeric sender id (e.g. "MyApp", max 11 chars) or a phone number you've purchased/verified in Bird. Some countries require a registered sender id.
4. *(Optional, for receipts)* **Create a webhook subscription** for delivery status reports pointing at `https:///rebel/bird/status`, and copy the **signing key** Bird shows you.
5. Put the values in your `.env` (see below). Done — the provider auto-registers.

> **Pricing:** Bird Verify is billed per verification + the channel cost. Always keep the Rebel **geo allowlist** (in `laravel-rebel-channels`) tight to avoid IRSF charges.

---

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

[](#installation)

```
composer require padosoft/laravel-rebel-channel-bird
php artisan vendor:publish --tag="rebel-channel-bird-config"
```

Add your credentials to `.env`:

```
BIRD_ACCESS_KEY=your_live_access_key
BIRD_ORIGINATOR=MyApp
```

That's it — the provider registers itself into the Channels router under the key `bird`.

---

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

[](#configuration)

File `config/rebel-channel-bird.php`:

KeyDefaultWhat it does`access_key``env(BIRD_ACCESS_KEY)`Bird API access key. **Required** for the provider to register.`workspace_id``env(BIRD_WORKSPACE_ID)`Reserved for Bird's newer Channels API (not used by the legacy Verify/Messaging endpoints).`originator``env(BIRD_ORIGINATOR, 'Code')`Sender id shown to the recipient (alphanumeric ≤11 chars, or a number you own).`channels``['sms']`Which Rebel channels this provider may handle.`register_provider``true`Auto-register into the Channels registry (when the access key exists).`webhook.enabled``true`Register the delivery-status webhook endpoint.`webhook.validate_signature``true`Validate the `MessageBird-Signature` header on the webhook.`webhook.signing_key``env(BIRD_WEBHOOK_SIGNING_KEY)`The signing key of your Bird webhook subscription.`webhook.path``rebel/bird/status`The webhook route path.---

Usage
-----

[](#usage)

### Verify a phone number (the common case)

[](#verify-a-phone-number-the-common-case)

You typically don't touch this package directly — you use the Channels router:

```
use Padosoft\Rebel\Channels\Enums\Channel;
use Padosoft\Rebel\Channels\Routing\VerificationRouter;
use Padosoft\Rebel\Core\Context\SecurityContext;
use Padosoft\Rebel\Core\Identifiers\PhoneIdentifier;

$router = app(VerificationRouter::class);

// Send a code (Bird Verify delivers it)
$start = $router->start(
    PhoneIdentifier::from('+39 333 1234567'),
    Channel::Sms,
    SecurityContext::fromRequest($request),
);

// Persist $start->reference (the Bird verify id) in the session for the check step.
session(['bird_ref' => $start->reference]);
```

```
// Later — check what the user typed
$result = $router->check(
    PhoneIdentifier::from('+39 333 1234567'),
    $request->string('code'),
    session('bird_ref'),
    SecurityContext::fromRequest($request),
);

if ($result->approved()) {
    // verified!
}
```

### Force Bird specifically

[](#force-bird-specifically)

```
// config/rebel-channels.php
'providers' => ['bird'],
```

### Send a plain SMS (delivery channel)

[](#send-a-plain-sms-delivery-channel)

The provider also implements `MessageDeliveryChannel`, so you can send any SMS through Bird:

```
use Padosoft\Rebel\Channel\Bird\Contracts\BirdGateway;
use Padosoft\Rebel\Channel\Bird\Verification\BirdVerifyProvider;
use Padosoft\Rebel\Channels\Enums\Channel;
use Padosoft\Rebel\Core\Context\SecurityContext;
use Padosoft\Rebel\Core\Identifiers\PhoneIdentifier;

$provider = new BirdVerifyProvider(app(BirdGateway::class));

$delivery = $provider->send(
    PhoneIdentifier::from('+39 333 1234567'),
    'Your order has shipped!',
    Channel::Sms,
    SecurityContext::fromRequest($request),
);

if ($delivery->accepted()) {
    // queued/sent by Bird; $delivery->reference is the Bird message id.
}
```

### Handle an outage gracefully

[](#handle-an-outage-gracefully)

```
$start = $router->start($phone, Channel::Sms, $context);

if ($start->failed() && $start->reason === 'provider_error') {
    // Bird was unreachable — the router will have tried any next provider first;
    // here you can show a friendly "try again" message.
}
```

---

Delivery receipts (status webhook)
----------------------------------

[](#delivery-receipts-status-webhook)

Bird knows whether a message was actually **delivered**, **failed**, and how much it **cost** — but only it knows, unless you let it call you back. This package ships a delivery-status webhook that turns those callbacks into Rebel audit events, so the admin panel's **Channel Performance** can show real delivered / failed rates and spend per channel.

**What it records.** On each callback the endpoint writes one audit event (recipient number stored only as a keyed HMAC, never in clear):

Bird statusAudit `event_type``delivered``channel.verification.delivered``delivery_failed`, `failed`, `expired``channel.verification.undelivered``sent`, `buffered`, `scheduled`, …`channel.verification.dispatched`Each event carries `channel: 'sms'`, `provider: 'bird'`, the HMAC'd recipient, and a `metadata`object:

```
{
  "message_status": "delivered",
  "price": 0.045,
  "price_unit": "EUR",
  "message_sid": "message-xxxxxxxx",
  "error_code": null
}
```

(Bird may quote `price` as a flat number or nested under `price.amount`/`price.currency`; we store the **absolute** value so spend sums cleanly. `price`/`error_code` are `null` when absent.)

**Set the webhook URL.** In the Bird dashboard, create a delivery-status webhook subscription pointing at your app:

```
https:///rebel/bird/status

```

The endpoint is enabled by default (`REBEL_BIRD_WEBHOOK=true`); set it to `false` to drop the route. The path is configurable via `webhook.path`.

**Signature validation.** The route has **no auth middleware** — Bird posts server-to-server. Instead, when `webhook.validate_signature` is true (default), every request must carry a valid `MessageBird-Signature` (HMAC-SHA256 of `timestamp + URL + sha256(body)`, base64-encoded, keyed with your subscription's signing key) plus a `MessageBird-Request-Timestamp`; a missing or forged signature is rejected with **403** and nothing is recorded. A malformed or empty payload is acknowledged with **204** and recorded as nothing, so a junk callback never 500s.

```
REBEL_BIRD_WEBHOOK=true             # register the /rebel/bird/status route
REBEL_BIRD_WEBHOOK_VALIDATE=true    # verify MessageBird-Signature
BIRD_WEBHOOK_SIGNING_KEY=...        # from your webhook subscription
REBEL_BIRD_WEBHOOK_PATH=rebel/bird/status
```

> Build now, wire live later: the endpoint and its audit events exist today, so you can simulate Bird callbacks (the test suite does exactly that) and the admin aggregates real delivered/cost data as soon as you point a Bird webhook subscription at it.

---

Live tests against the real API
-------------------------------

[](#live-tests-against-the-real-api)

The offline suite fakes the gateway (`Http::fake()` for the REST gateway, `FakeBirdGateway` for the provider). To exercise the **real** Bird Verify API (`tests/Live`), opt in explicitly — it **sends a real message**:

```
# .env (or shell env)
REBEL_BIRD_LIVE=1
BIRD_ACCESS_KEY=your_live_access_key
BIRD_ORIGINATOR=MyApp
BIRD_TEST_PHONE=+39XXXXXXXXXX

vendor/bin/pest --group=live
```

Without `REBEL_BIRD_LIVE=1` or with any credential missing, the live tests **self-skip**, so `composer test` and external PRs never trigger a send. In CI, supply the values as **secrets** and set `REBEL_BIRD_LIVE=1` on a dedicated job.

---

`.env.example`
--------------

[](#envexample)

```
BIRD_ACCESS_KEY=your_live_access_key
BIRD_ORIGINATOR=MyApp
BIRD_WORKSPACE_ID=
REBEL_BIRD_REGISTER=true

REBEL_BIRD_WEBHOOK=true
REBEL_BIRD_WEBHOOK_VALIDATE=true
BIRD_WEBHOOK_SIGNING_KEY=your_webhook_signing_key
REBEL_BIRD_WEBHOOK_PATH=rebel/bird/status

# Live tests (opt-in: SENDS A REAL MESSAGE)
REBEL_BIRD_LIVE=0
BIRD_TEST_PHONE=+391234567890
```

---

Security notes
--------------

[](#security-notes)

- **No unauthenticated client**: the Bird gateway is only constructed when `access_key` is present.
- **No exception leakage**: transport/API errors are caught and returned as a generic `provider_error` — Bird internals never bubble up to your app or logs.
- **Explicit status mapping**: only Bird's `sent` is treated as a live challenge; any unexpected status fails closed.
- **No PII in clear**: the recipient number is stored only as a keyed HMAC in the audit trail; OTPs are never logged.
- **Keep IRSF defences on**: pair this with the Channels geo allowlist / per-prefix cap to avoid premium-rate fraud charges.

---

🔋 Vibe coding with batteries included
-------------------------------------

[](#-vibe-coding-with-batteries-included)

This package ships **AI batteries** — so you (and your AI agent) can extend it correctly on the first try:

- **`CLAUDE.md`** — a concise AI working guide (purpose, conventions, architecture, how to extend, Definition of Done). Plain Markdown, so Claude Code, Cursor, Copilot and Codex all read it.
- **`AGENTS.md`** — the agent/workflow contract (branch → PR → CI → tag/release, the gates).
- **`.claude/skills/`** — invocable skills (at least `rebel-package-dev`) encoding the suite's TDD loop, the **PHPStan-level-max** recipes, the security/telemetry rules, and the release discipline.

Open the repo in your AI editor and just start — the rules, guardrails and extension recipes come with it. PRs that follow the shipped `CLAUDE.md` pass CI (PHPStan max + Pest + Pint) and review the first time around.

Testing &amp; License
---------------------

[](#testing--license)

```
composer test      # Pest (provider + gateway + webhook + Channels integration; live suite self-skips)
composer phpstan   # static analysis, level max
composer pint      # code style
```

**License:** MIT — see [LICENSE](LICENSE). Part of the [`padosoft/laravel-rebel`](https://github.com/padosoft) suite.

###  Health Score

36

—

LowBetter than 79% of packages

Maintenance91

Actively maintained with recent releases

Popularity2

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity40

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

Unknown

Total

1

Last Release

51d ago

### Community

Maintainers

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

---

Top Contributors

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

---

Tags

laravelAuthenticationverifysmspadosoftmessagebirdbirdRebel

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/padosoft-laravel-rebel-channel-bird/health.svg)

```
[![Health](https://phpackages.com/badges/padosoft-laravel-rebel-channel-bird/health.svg)](https://phpackages.com/packages/padosoft-laravel-rebel-channel-bird)
```

###  Alternatives

[defstudio/telegraph

A laravel facade to interact with Telegram Bots

813336.8k3](/packages/defstudio-telegraph)[harris21/laravel-fuse

Circuit breaker for Laravel queue jobs. Protect your workers from cascading failures.

45955.7k](/packages/harris21-laravel-fuse)[rawilk/profile-filament-plugin

Profile &amp; MFA starter kit for filament.

3914.8k](/packages/rawilk-profile-filament-plugin)[masterix21/laravel-licensing

Laravel licensing package with polymorphic assignment to any model, activation keys, expirations/renewals, and seat control via LicenseUsage. Supports offline verification with public-key–signed tokens, a CLI to generate/rotate/revoke keys, and an extensible architecture via config and contracts.

1613.3k4](/packages/masterix21-laravel-licensing)[simplestats-io/laravel-client

Server-side analytics for Laravel that follows the full funnel from visit to registration to payment, attributed to the channel that drove it. Revenue, MRR, churn and ad-spend profit (ROAS/CAC) per channel. GDPR compliant, ad-blocker proof.

5022.6k](/packages/simplestats-io-laravel-client)

PHPackages © 2026

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