getbrevo/brevo-php
Official PHP SDK for the Brevo API (PHP 8.1+), installable via Composer. Covers email, CRM and events endpoints with built-in exception handling, custom clients, retries, timeouts and logging. Note v5 is a major release with breaking changes from v4.
v6.0.0 is a major release. The release notes specifically call out:
Before changing application code, read the package README authentication section and the v5 → v6 upgrade guide. Because the SDK was regenerated, confirm generated API class names, model constructors, method signatures, and return types against your installed v6 client.
Install v6
composer require getbrevo/brevo-php:^6.0.0
Configure credentials in Laravel
Add the key to config/services.php:
'brevo' => [
'api_key' => env('BREVO_API_KEY'),
],
Then configure the SDK:
use Brevo\Client\Configuration;
$config = Configuration::getDefaultConfiguration()
->setApiKey('api-key', config('services.brevo.api_key'));
First v6 Use Case: Read-Only Smoke Test Start with a simple read call after upgrading. This verifies authentication and generated client compatibility before touching write operations.
use Brevo\Client\Api\ContactsApi;
use GuzzleHttp\Client;
$api = new ContactsApi(new Client(), $config);
try {
$contacts = $api->getContacts();
// Inspect the v6 response shape before relying on it.
// print_r($contacts);
} catch (\Throwable $e) {
report($e);
throw $e;
}
Where to Look First in Code
vendor/getbrevo/brevo-php/lib/Api/ for generated API classes.vendor/getbrevo/brevo-php/lib/Model/ for request/response models.This is a PHP SDK, not a Laravel-native package, so you own the service bindings. Keep SDK construction in one place rather than creating API clients throughout your app.
// AppServiceProvider::register()
use Brevo\Client\Api\ContactsApi;
use Brevo\Client\Api\ConsentGroupsApi;
use Brevo\Client\Configuration;
use GuzzleHttp\Client;
$this->app->singleton(ContactsApi::class, function () {
$config = Configuration::getDefaultConfiguration()
->setApiKey('api-key', config('services.brevo.api_key'));
return new ContactsApi(new Client(), $config);
});
$this->app->singleton(ConsentGroupsApi::class, function () {
$config = Configuration::getDefaultConfiguration()
->setApiKey('api-key', config('services.brevo.api_key'));
return new ConsentGroupsApi(new Client(), $config);
});
Then inject the API classes:
public function __construct(
private ContactsApi $contactsApi,
private ConsentGroupsApi $consentGroupsApi,
) {}
For day-to-day Laravel work, avoid calling vendor API classes directly from controllers and jobs. Wrap them in an application service so v6 signature changes are isolated.
class BrevoContactService
{
public function __construct(private ContactsApi $contactsApi) {}
public function find(string $email): mixed
{
try {
return $this->contactsApi->getContact($email);
} catch (\Throwable $e) {
report($e);
throw $e;
}
}
}
Use consent groups for compliance tracking, not as a replacement for lists.
$group = new \Brevo\Client\Model\ConsentGroup([
'name' => 'Marketing Newsletter',
'description' => 'Consent for marketing emails',
'signupMode' => 'DOUBLE_OPTIN', // SINGLE_OPTIN or DOUBLE_OPTIN
]);
$created = $consentGroupsApi->createConsentGroup($group);
Before assigning contacts, validate group IDs:
$groups = $consentGroupsApi->getConsentGroups();
$validGroupIds = collect($groups->getData())->pluck('id')->all();
if (!in_array($groupId, $validGroupIds, true)) {
throw new \InvalidArgumentException('Invalid consent group ID');
}
Import contacts with both segmentation lists and consent groups where appropriate.
$import = new \Brevo\Client\Model\ImportContactsRequest([
'contacts' => [
['email' => '[email protected]', 'attributes' => ['AGE' => '30']],
['email' => '[email protected]', 'attributes' => ['AGE' => '25']],
],
'consentGroupIds' => [123, 456],
]);
$api->importContacts($import);
Validate group IDs and contact payloads before importing. Prefer queueing imports if they are part of a user-facing flow.
Wallet support is useful for pass installation URLs, but it requires Brevo dashboard setup and a valid contact identifier.
$url = $walletApi->getPassInstallUrl($passId, $contactId);
Verify that:
Use a controlled upgrade path:
^6.0.0.composer update getbrevo/brevo-php.vendor/getbrevo/brevo-php.Do not treat v6.0.0 as a drop-in patch. The release notes mention SDK regeneration and a v5 → v6 upgrade guide. Read the guide and test all SDK touchpoints. Pay attention to:
The README authentication section was updated. Confirm your configuration matches the v6 docs, especially the API key header name and configuration method.
Do not hardcode API keys. Use Laravel config and environment variables:
$config = Configuration::getDefaultConfiguration()
->setApiKey('api-key', config('services.brevo.api_key'));
Clear cached config after changing service configuration:
php artisan config:clear
After upgrading, inspect the generated API and model classes you use. If the SDK regenerated method signatures, your IDE and static analysis will often catch issues before runtime. Run:
composer dump-autoload
php artisan test
If using PHPStan/Larastan, run analysis after the upgrade to catch model-constructor and return-type mismatches.
These are not interchangeable:
Use both where needed: assign contacts to a list for targeting and to a consent group for compliance.
Be explicit about signupMode when creating consent groups:
$group = new \Brevo\Client\Model\ConsentGroup([
'name' => 'Newsletter',
'signupMode' => 'DOUBLE_OPTIN',
]);
A missing or invalid mode is a common cause of 400 Bad Request responses.
v5.0.1 fixed serialization of empty optional objects such as {} vs []. After upgrading to v6, re-test any payloads that rely on empty objects or optional attributes.
getPassInstallUrl can fail with 404 if the pass does not exist or wallet is not configured in Brevo. Check dashboard setup before debugging application code.
name and signupMode.vendor/getbrevo/brevo-php/lib/Model.Keep vendor SDK usage behind application services and interfaces. This makes it much easier to handle future Brevo SDK major releases without spreading changes across controllers, jobs, listeners, and commands.
How can I help you explore Laravel packages today?