Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Symfony Laravel Package

vonage/symfony

Symfony bundle that integrates the Vonage PHP SDK, wiring the client into Symfony's service container so you can send SMS, make voice calls, verify numbers, and use Vonage APIs with simple configuration and dependency injection.

View on GitHub
Deep Wiki
Context7

Getting Started

First, read the package name carefully. vonage/symfony is a Symfony bundle — its entire reason for existing is to register the Vonage PHP client as a service inside Symfony's DependencyInjection container via a VonageBundle class and a VonageExtension. As a Laravel developer, that contribution is worth zero in your app: Laravel does not read config/bundles.php, never calls Bundle::build(), and does not run Symfony compiler passes. Composer will happily install it (it only requires a handful of symfony/* components), but nothing will be wired up and you will have added a stale dependency tree for no benefit.

What you actually want is the underlying SDK, vonage/client — that is where all the real code lives, and the bundle is a thin ~3-file wrapper around it.

Where to look first, in order:

  1. The bundle's DependencyInjection/VonageExtension.php (or VonageExtension::load()) — this is the only part with any logic. It reads api_key, api_secret, signature_secret, application_id, private_key and configures a Vonage\Client service definition. That's the whole package.
  2. The vonage/client README — the credentials classes (Vonage\Client\Credentials\Basic, Vonage\Client\Credentials\Keypair), the Vonage\Client constructor, and the per-product entry points ($client->sms(), $client->messages(), $client->voice(), $client->verify2(), $client->numbers()).
  3. Your own config/services.php — this is where you will replicate the bundle's config in Laravel.

First use case (Laravel, no bundle):

composer require vonage/client guzzlehttp/guzzle
// config/services.php
'vonage' => [
    'key'        => env('VONAGE_KEY'),
    'secret'     => env('VONAGE_SECRET'),
    'from'       => env('VONAGE_SMS_FROM'),
    'app_id'     => env('VONAGE_APPLICATION_ID'),
    'private_key'=> env('VONAGE_PRIVATE_KEY_PATH'),
],
// app/Providers/VonageServiceProvider.php
public function register(): void
{
    $this->app->singleton(\Vonage\Client::class, function () {
        return new \Vonage\Client(
            new \Vonage\Client\Credentials\Basic(
                config('services.vonage.key'),
                config('services.vonage.secret'),
            )
        );
    });
}

Then app(\Vonage\Client::class)->sms()->send(new \Vonage\Messages\Channel\SMS\SMS(...)) — or, more idiomatically, inject it into a small SmsSender wrapper class.

Implementation Patterns

Wrap the SDK, don't sprinkle it. The single best pattern is a thin application-level service (App\Services\Vonage\SmsSender) that depends on Vonage\Client. This gives you one place to swap credentials, add logging, and fake in tests. The Symfony bundle's value proposition is exactly this — a container-managed singleton — and you get the same thing in ~15 lines of service provider code.

API key/secret vs. application identity. The Vonage client has two credential modes and the bundle exposes both:

  • Basic(key, secret) — SMS, Verify, Number Insight, Account APIs.
  • Keypair(privateKey, applicationId) — Messages API, Voice API, anything that needs JWT signing.

If you use both, register two named singletons (vonage.basic, vonage.keypair) rather than one, or construct a Keypair client and pass Basic credentials per call where the SDK allows it. Getting this wrong produces confusing 401 responses that look like bad credentials when it's actually the wrong credential type.

Config-driven construction, never env() at call time. Because you'll likely run php artisan config:cache in production, all env() calls must live inside config/*.php. The bundle does this correctly via Symfony parameters; mirror it.

Inject where you actually send. Prefer dispatching a queued job over sending synchronously in a request:

final class SendSms implements ShouldQueue
{
    use Queueable;

    public function __construct(public string $to, public string $text) {}

    public function handle(SmsSender $sms): void
    {
        $sms->send($this->to, $this->text);
    }
}

Vonage API calls are network-bound and rate-limited; making them inside a controller turns an HTTP 200 into a p99 latency spike.

Webhooks. Vonage's inbound webhooks (delivery receipts, inbound SMS, call events) need signature verification. Don't reuse the SDK's HTTP client for this; convert the Illuminate\Http\Request to PSR-7 and use the SDK's webhook factory / signature helper, or verify manually:

use Vonage\Webhook\Factory;
use Nyholm\Psr7\ServerRequest;

Route::post('/webhooks/vonage', function (Request $request) {
    $psr = new ServerRequest(
        $request->method(),
        $request->fullUrl(),
        $request->headers->all(),
        $request->getContent()
    );
    $event = Factory::createFromRequest($psr); // throws on invalid signature
    // dispatch a job to handle $event
    return response()->noContent();
});

Register that route in routes/api.php and exclude it from CSRF (API routes are exempt by default, but routes/web.php is not).

Testing. Bind a fake in the container rather than hitting the network:

$this->mock(\Vonage\Client::class, function ($mock) {
    $mock->shouldReceive('sms->send')->once();
});

Even better, define an interface (SmsGateway) around your wrapper and fake that, so tests never touch Vonage's object graph at all.

Gotchas and Tips

This package is effectively dead. Two stars, zero dependents, last release 2020-11-19. It targets symfony/http-kernel versions from that era and pins an old vonage/client. If you try to install it alongside a current vonage/client 4.x, Composer will very likely fail with a conflict, or silently downgrade your SDK. Before doing anything, run composer why-not vonage/symfony and read the constraint. In practice: install vonage/client directly and skip this package entirely. If you inherited it in a hybrid Symfony/Laravel repo, keep it in the Symfony app and give Laravel its own provider.

Do not install it in Laravel "just to try." It will not error — which is worse. The service provider you expect (vonage.client) simply won't exist, so app(\Vonage\Client::class) will autowire a client with no credentials and fail at the first API call with an opaque message. The failure mode is distant from the cause.

Private keys and env files. Multi-line PEM keys in .env are a classic time sink. Either store a base64-encoded key and decode in the provider, or reference a file path (storage/app/vonage.pem) and file_get_contents it. Never commit the key, and don't let the path be relative to the CWD — use storage_path().

Two different "secrets." The API secret (Basic auth) and the webhook signature secret are not interchangeable. The bundle's config exposes signature_secret separately; if you copy-paste from a tutorial you will end up verifying signatures with the API secret and get 100% rejection.

Error handling is coarse. The SDK throws Vonage\Client\Exception\Request (bad input), Vonage\Client\Exception\Server (Vonage-side 5xx), and Vonage\Client\Exception\ThrottleException-style responses via 429s. Catch Vonage\Client\Exception\Exception at the boundary of your wrapper, log the response body (which the SDK often buries), and map to your own domain exceptions. Do not let these bubble to Laravel's exception handler unmapped.

Rate limits and retries. Vonage enforces per-endpoint throughput. Use retry() on the queued job (public $backoff = [1, 5, 30]; public $tries = 3;) and treat 429 as retryable, 4xx as permanent. Don't blind-retry 400s — you'll burn quota on a malformed number.

Debugging HTTP. The client accepts a PSR-18/HTTP client (and Guzzle-based configuration) in its constructor. In local dev, inject a Guzzle stack with HandlerStack::create(new Middleware::log(...)) or ->withMiddleware logging so you can see the exact request/response. This is far faster than guessing at the SDK.

Extension point, if you're actually in Symfony. The only meaningful customization is subclassing VonageExtension to add config keys, or overriding the vonage.client service definition. Neither is worth doing — the SDK is one new away. For Laravel, your equivalent extension point is your own service provider and config file, which you fully control.

Version pinning. Since this package is unmaintained, pin vonage/client explicitly in composer.json and add a note in your README. If Vonage ships a breaking 5.x, an unpinned constraint will break you on a routine composer update, and the bundle is in no position to help.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource