PHPackages                             padosoft/laravel-rebel-channel-twilio - 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-twilio

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

padosoft/laravel-rebel-channel-twilio
=====================================

Twilio provider for Laravel Rebel Channels: phone verification via Twilio Verify (SMS/WhatsApp/voice), message delivery, and signed delivery-status webhooks. Part of padosoft/laravel-rebel-\*.

v0.1.1(1mo ago)02↓90%MITPHPPHP ^8.3CI failing

Since Jun 3Pushed 1mo agoCompare

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

READMEChangelog (2)Dependencies (11)Versions (6)Used By (0)

Laravel Rebel — Twilio Channel
==============================

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

> Official documentation:

> **Send phone verifications through Twilio Verify, the Rebel way.** This package plugs [Twilio Verify](https://www.twilio.com/docs/verify) (SMS / WhatsApp / voice) into [`laravel-rebel-channels`](https://github.com/padosoft/laravel-rebel-channels) as a `VerificationProvider` — so you get Twilio'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) [![Twilio Verify](https://camo.githubusercontent.com/7e624d001bd003a07345c8bc64cb3d2efe9e25236a3342692729b1ca33988ba4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5477696c696f2d5665726966792d4632324634363f7374796c653d666c61742d737175617265266c6f676f3d7477696c696f266c6f676f436f6c6f723d7768697465)](https://camo.githubusercontent.com/7e624d001bd003a07345c8bc64cb3d2efe9e25236a3342692729b1ca33988ba4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5477696c696f2d5665726966792d4632324634363f7374796c653d666c61742d737175617265266c6f676f3d7477696c696f266c6f676f436f6c6f723d7768697465) [![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)
- [Why this package](#why-this-package)
- [Rebel + Twilio vs the alternatives](#rebel--twilio-vs-the-alternatives)
- [Twilio portal setup (step by step)](#twilio-portal-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)
- [Testing &amp; License](#testing--license)

---

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

[](#what-it-is)

A thin, well-tested **Twilio 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** (`TwilioVerifyGateway`) wraps the Twilio SDK, so the whole thing is unit-testable offline and has a real **live** test-suite for the actual API.

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**Twilio Verify**A Twilio product that sends and checks one-time codes for you — you never store or generate the OTP.**Verify Service**A Verify configuration (sender IDs, code length, channels). Identified by a SID starting with `VA`.**Account SID / Auth Token**Your Twilio account credentials (the SID starts with `AC`).**Channel**`sms`, `whatsapp` or `voice` (Twilio calls voice `call`).**Verification SID**The handle (`VE...`) for an in-flight verification.---

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

[](#why-this-package)

★WhatIn short★★★**Twilio Verify, fully wrapped**Start + check codes over SMS/WhatsApp/voice; you never handle the OTP yourself.★★★**Rebel guarantees for free**Inherits the Channels fraud guard (IRSF), rate limit, fallback and HMAC'd audit.★★**Never throws out**Any SDK/transport 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 Twilio; a separate live suite does.★★**Safe by default**No credentials → nothing registers, and no unauthenticated Twilio client is ever built.★**Explicit status mapping**Twilio Verify statuses are mapped deliberately (an unexpected status is a failure, not a fake "pending").---

Rebel + Twilio vs the alternatives
----------------------------------

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

Sending an OTP with Twilio, three ways:

Capability**Rebel + this package**ShopifyTwilio Verify SDK (direct)Raw Twilio SMS + your own OTPSend/check a code via Twilio✅❌✅➖ (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)✅❌❌❌Graceful failure → router fallback✅❌❌❌> Legend: ✅ built-in · ➖ partial / hosted-only · ❌ not available. Twilio Verify 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 Twilio as the sender, self-host it, fall back across vendors, nor configure its fraud controls — a black box, not a developer-facing verification library.

---

Twilio portal setup (step by step)
----------------------------------

[](#twilio-portal-setup-step-by-step)

1. **Create a Twilio account** at [twilio.com/try-twilio](https://www.twilio.com/try-twilio). The **free trial** gives you a small credit and a trial number — note that trial accounts can only send to **verified** caller IDs (add your test phone under *Phone Numbers → Verified Caller IDs*).
2. **Grab your credentials**: on the [Console](https://console.twilio.com) home page copy your **Account SID** (`AC...`) and **Auth Token**.
3. **Create a Verify Service**: go to **Verify → Services → Create new**, give it a friendly name (e.g. "MyApp Login"), choose the channels (SMS / WhatsApp / Voice), and copy the **Service SID** (`VA...`).
4. *(WhatsApp only)* enable the WhatsApp channel on the Verify Service and complete Twilio's WhatsApp sender onboarding.
5. Put the three values in your `.env` (see below). Done — the provider auto-registers.

> **Pricing:** Twilio Verify is billed per successful verification + the channel cost; the free trial credit is enough to test end-to-end. Always keep the Rebel **geo allowlist**(in `laravel-rebel-channels`) tight to avoid IRSF charges.

---

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

[](#installation)

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

Add your credentials to `.env`:

```
TWILIO_ACCOUNT_SID=ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWILIO_AUTH_TOKEN=your_auth_token
TWILIO_VERIFY_SERVICE_SID=VAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

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

---

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

[](#configuration)

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

KeyDefaultWhat it does`account_sid``env(TWILIO_ACCOUNT_SID)`Twilio Account SID (`AC...`).`auth_token``env(TWILIO_AUTH_TOKEN)`Twilio Auth Token.`verify_service_sid``env(TWILIO_VERIFY_SERVICE_SID)`Verify Service SID (`VA...`).`channels``['sms','whatsapp','voice']`Which Rebel channels this provider may handle.`register_provider``true`Auto-register into the Channels registry (when credentials exist).`webhook.enabled``true`Register the delivery-status callback endpoint.`webhook.validate_signature``true`Validate `X-Twilio-Signature` on the webhook.`webhook.path``rebel/twilio/status`The webhook route path.---

Usage
-----

[](#usage)

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 (Twilio Verify delivers it)
$start = $router->start(PhoneIdentifier::from('+39 333 1234567'), Channel::Sms, SecurityContext::fromRequest($request));

// Check what the user typed
$result = $router->check(PhoneIdentifier::from('+39 333 1234567'), $request->string('code'), $reference, SecurityContext::fromRequest($request));
if ($result->approved()) {
    // verified!
}
```

To force Twilio specifically, set it first in the Channels fallback order:

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

---

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

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

Twilio knows whether a message was actually **delivered**, **failed**, and exactly 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):

Twilio statusAudit `event_type``delivered``channel.verification.delivered``undelivered`, `failed``channel.verification.undelivered``queued`, `sent`, `accepted`, …`channel.verification.dispatched`Each event carries `channel` (from the payload, default `sms`), `provider: 'twilio'`, the HMAC'd recipient, and a `metadata` object:

```
{
  "message_status": "delivered",
  "price": 0.0075,
  "price_unit": "USD",
  "message_sid": "SMxxxxxxxx",
  "error_code": null
}
```

(Twilio quotes `Price` as a negative debit string; we store the **absolute** value so spend sums cleanly. `price`/`error_code` are `null` when absent.)

**Set the StatusCallback URL.** In the Twilio console, point the status callback at your app:

```
https:///rebel/twilio/status

```

- **Messaging**: set *StatusCallback* on the Messaging Service (or per message).
- **Verify**: set the status webhook on the Verify Service.

The endpoint is enabled by default (`REBEL_TWILIO_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** — Twilio posts server-to-server. Instead, when `webhook.validate_signature` is true (default), every request must carry a valid `X-Twilio-Signature` (HMAC-SHA1 of the full URL + POST params, keyed with your Auth Token); 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_TWILIO_WEBHOOK=true            # register the /rebel/twilio/status route
REBEL_TWILIO_WEBHOOK_VALIDATE=true   # verify X-Twilio-Signature
REBEL_TWILIO_WEBHOOK_PATH=rebel/twilio/status
```

> Build now, wire live later: the endpoint and its audit events exist today, so you can simulate Twilio callbacks (the test suite does exactly that) and the admin aggregates real delivered/cost data as soon as you set the StatusCallback URL in Twilio.

---

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

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

The offline suite uses a fake gateway. To exercise the **real** Twilio Verify API (`tests/Live`), opt in explicitly — it **sends a real message**:

```
# .env (or shell env)
REBEL_TWILIO_LIVE=1
TWILIO_TEST_PHONE=+39XXXXXXXXXX   # a verified number on trial accounts

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

Without `REBEL_TWILIO_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_TWILIO_LIVE=1` on a dedicated job.

---

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

[](#envexample)

```
TWILIO_ACCOUNT_SID=ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWILIO_AUTH_TOKEN=your_auth_token
TWILIO_VERIFY_SERVICE_SID=VAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
REBEL_TWILIO_REGISTER=true

REBEL_TWILIO_WEBHOOK=true
REBEL_TWILIO_WEBHOOK_VALIDATE=true
REBEL_TWILIO_WEBHOOK_PATH=rebel/twilio/status

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

---

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

[](#security-notes)

- **No unauthenticated client**: the Twilio client is only constructed when all three credentials are present.
- **No exception leakage**: SDK/transport errors are caught and returned as a generic `provider_error` — Twilio internals never bubble up to your app or logs.
- **Explicit status mapping**: only Twilio's `pending` is treated as a live challenge; any unexpected status fails closed.
- **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 + 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

37

—

LowBetter than 81% of packages

Maintenance91

Actively maintained with recent releases

Popularity2

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity42

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

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 (7 commits)")

---

Tags

laravelAuthenticationverifysmstwiliowhatsapppadosoftRebel

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

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

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

###  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)
