thinwrap/notifications
thinwrap/notifications for PHP — unified facade over 35 notification providers across email, SMS, push, and chat. Stateless, BYO PSR-18 client, no vendor SDKs.
PHP constraints
- Runtime dependencies
- php-http/discovery, psr/http-client, psr/http-factory
- BYO HTTP client
- consumer-supplied PSR-18 client via php-http/discovery
- Provenance
- cosign-signed GitHub Release artifacts
- Minimum runtime
- PHP 8.2+
- PSR-17/PSR-18 discovery is auto-detected; consumers can also pass clients explicitly
30-second install
composer require thinwrap/notifications2-minute end-to-end example
Send an email through any supported provider via one normalized call. The example below uses SendGrid; switching providers means changing the provider ID and config — input and output shape stay identical.
<?php
use Thinwrap\Notifications\Facade\Email;
use Thinwrap\Notifications\Enum\NotificationsProviderId;
use Thinwrap\Notifications\Config\SendgridConfig;
$email = new Email(
NotificationsProviderId::Sendgrid,
new SendgridConfig(apiKey: getenv('SENDGRID_API_KEY'), from: 'you@example.com'),
);
$email->send([
'to' => 'user@example.com',
'subject' => 'Hello',
'text' => 'Hello world',
]);Same code works for all supported providers — swap the provider id case and config DTO. The supported-providers list below is auto-sourced from the catalog.
See the universal email snippet for the full copy-paste pattern.
Supported providers
| Provider | Channel | Auth | README |
|---|---|---|---|
sendgrid SendGrid | bearer | docs | |
ses AWS SES | aws-sig-v4 | docs | |
mailgun Mailgun | basic | docs | |
postmark Postmark | header | docs | |
resend Resend | bearer | docs | |
brevo Brevo (Sendinblue) | header | docs | |
mailersend MailerSend | bearer | docs | |
mailtrap Mailtrap | bearer | docs | |
sparkpost SparkPost | header | docs | |
scaleway Scaleway | header | docs | |
twilio Twilio | sms | basic | docs |
vonage Vonage | sms | query | docs |
plivo Plivo | sms | basic | docs |
sns AWS SNS | sms | aws-sig-v4 | docs |
messagebird MessageBird (Bird) | sms | header | docs |
infobip Infobip | sms | header | docs |
telnyx Telnyx | sms | bearer | docs |
sinch Sinch | sms | bearer | docs |
textmagic Textmagic | sms | header | docs |
d7networks D7 Networks | sms | bearer | docs |
fcm Firebase Cloud Messaging | push | rs256-jwt | docs |
apns Apple Push Notifications | push | es256-jwt | docs |
expo Expo Push | push | bearer | docs |
one-signal OneSignal | push | header | docs |
pusher-beams Pusher Beams | push | bearer | docs |
wonderpush WonderPush | push | bearer | docs |
slack Slack | chat | webhook-url | docs |
discord Discord | chat | webhook-url | docs |
ms-teams Microsoft Teams | chat | webhook-url | docs |
telegram Telegram | chat | webhook-url | docs |
whatsapp-business WhatsApp Business | chat | bearer | docs |
line LINE | chat | bearer | docs |
google-chat Google Chat | chat | webhook-url | docs |
rocket-chat Rocket.Chat | chat | webhook-url | docs |
mattermost Mattermost | chat | webhook-url | docs |
Migration paths
From sendgrid/sendgrid (or any vendor SDK)
Drop the vendor SDK; the wrapper produces the same outbound HTTP call via your PSR-18 client of choice. Vendor-specific fields stay accessible through _passthrough.
- use SendGrid\Mail\Mail;
- $sg = new \SendGrid(getenv('SENDGRID_API_KEY'));
- $sg->send($mail);
+ use Thinwrap\Notifications\Facade\Email;
+ use Thinwrap\Notifications\Enum\NotificationsProviderId;
+ use Thinwrap\Notifications\Config\SendgridConfig;
+ $email = new Email(NotificationsProviderId::Sendgrid, new SendgridConfig(apiKey: getenv('SENDGRID_API_KEY'), from: 'you@example.com'));
+ $email->send(['to' => 'user@example.com', 'subject' => 'Hi', 'text' => 'Hello world']);From hand-rolled cURL or Guzzle
Keep your PSR-18 client; replace the per-vendor request shape with one uniform call. The wrapper performs no automatic retry — compose your own from ConnectorError->providerCode and the rawRetry-After header on $e->cause.
Note: Novu has no native PHP package, so a Novu PHP migration path is not applicable.