diff --git a/README.md b/README.md
index 495566a..0c3fd86 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# Brevo PHP Library
-
+
[](https://buildwithfern.com?utm_source=github&utm_medium=github&utm_campaign=readme&utm_source=https%3A%2F%2Fgithub.com%2Fmourraille%2Ffern-sdk)
[](https://packagist.org/packages/getbrevo/brevo-php)
@@ -12,13 +12,15 @@ Official SDK for the Brevo API.
- [Documentation](#documentation)
- [Requirements](#requirements)
- [Installation](#installation)
-- [Migration From V1X](#migration-from-v1x)
+- [Upgrading from v4.x](#upgrading-from-v4x)
+- [Migration from v1.x](#migration-from-v1x)
- [Usage](#usage)
- [Exception Handling](#exception-handling)
- [Advanced](#advanced)
- [Custom Client](#custom-client)
- [Retries](#retries)
- [Timeouts](#timeouts)
+ - [Logging](#logging)
- [Contributing](#contributing)
## Documentation
@@ -35,9 +37,73 @@ This SDK requires PHP ^8.1.
composer require getbrevo/brevo-php
```
+## Upgrading from v4.x
+
+v5 is a major release. Most breaking changes come from an internal effort at Brevo to make endpoints, parameters and models more **self-descriptive** — so names, shapes and required fields convey intent without needing to cross-reference external docs (both for developers and for AI agents working against the Brevo API).
+
+v4.x remains supported. If you need to hold on v4 temporarily, pin it:
+
+```bash
+composer require getbrevo/brevo-php:^4.0
+```
+
+
+View v4 → v5 migration guide
+
+### Breaking changes
+
+**Companies — `GetCompaniesRequest::filters` renamed**
+- `filters` is renamed to `filtersAttributesName` to match the wire format.
+- Existing code passing `'filters' => ...` does not throw, but the filter is silently ignored server-side and the response is unfiltered. Audit every call site.
+
+**Events — `Event::createBatchEvents` payload shape changed**
+```php
+// v4
+$client->event->createBatchEvents($eventsArray);
+
+// v5
+use Brevo\Event\Requests\CreateBatchEventsRequest;
+
+$client->event->createBatchEvents(
+ new CreateBatchEventsRequest(['events' => $eventsArray])
+);
+```
+
+**Balance — `getActiveBalancesApi` response shape changed**
+- Return type changed from `?BalanceLimit` to `?GetLoyaltyBalanceProgramsPidActiveBalanceResponse`.
+
+**Balance — `getContactBalances` requires `balanceDefinitionId`**
+- `$request` no longer defaults to empty; `balanceDefinitionId` is required.
+
+**Balance — `BeginTransactionRequest::eventTime` type tightened**
+- Changed from `?string` to `?DateTime`. ISO strings now cause `TypeError`.
+
+**CRM — `Tasks::getAllTaskTypes` returns an array** (`?array` instead of `?GetCrmTasktypesResponse`).
+
+**Email campaigns — `utmIdActive` renamed**
+- `EmailCampaigns\GetEmailCampaignResponse::utmIdActive` renamed to `utmId` (wire key `utmIDActive` → `utmID`, type `?bool` → `?int`). Same change on `GetEmailCampaignsResponseCampaignsItem`.
+
+**Model fields removed**: `GetAccountResponse::dateTimePreferences`, `Webhook::channel`, `GetProcessResponseInfo::export`, `GetProcessResponse::error/createdAt/completedAt`, and several `ExternalFeeds` response fields.
+
+**Model field types tightened**:
+- `Process\GetProcessResponseInfoImport` count fields: `?int` → `?string` (now URLs to CSV reports) — affects `invalidEmails`, `duplicateContactId`, `duplicateExtId`, etc.
+- `Ecommerce\CreateUpdateProductResponse::id` and `CreateUpdateCategoryResponse::id`: `?int` → `?string`.
+- Several `string` date fields tightened to `?DateTime` (`Program::*`, `Reward::*`, `BalanceLimit::createdAt`/`updatedAt`).
+
+**Model fields renamed**: `ConversationsMessageAttachmentsItem::fileName` → `name`, `::inlineId` → `link`.
+
+**Custom objects — associations union flattened**: `UpsertrecordsRequestRecordsItemAssociationsItem` is now a single class with an `action: 'link' | 'unlink'` discriminator. Seven old variant classes have been deleted.
+
+### Added
+
+- New optional fields and filters across `contacts->createContact`, `contacts->updateContact`, `emailCampaigns->getEmailCampaigns`, `ecommerce->getProducts`, and several other endpoints.
+- Tier groups support upgrade and downgrade schedule fields.
+
+
+
## Migration from v1.x
-> **Warning**: The legacy v1.x SDK will continue to receive critical security updates but no new features. We recommend migrating to v4.x.
+> **Warning**: The legacy v1.x SDK will continue to receive critical security updates but no new features. We recommend migrating to v5.x.
View migration guide
@@ -65,7 +131,7 @@ $message->setTo([['email' => 'sarah.davis@example.com', 'name' => 'Sarah Davis']
$api->sendTransacEmail($message);
```
-**v4.x:**
+**v5.x:**
```php
use Brevo\Brevo;
use Brevo\TransactionalEmails\Requests\SendTransacEmailRequest;
@@ -166,17 +232,19 @@ $customClient = new \GuzzleHttp\Client([
'timeout' => 5.0,
]);
-$client = new Brevo(options: [
- 'client' => $customClient
-]);
+$client = new Brevo(
+ apiKey: 'xkeysib-xxx',
+ options: ['client' => $customClient],
+);
// Or using Symfony HttpClient:
// $customClient = (new \Symfony\Component\HttpClient\Psr18Client())
// ->withOptions(['timeout' => 5.0]);
//
-// $client = new Brevo(options: [
-// 'client' => $customClient
-// ]);
+// $client = new Brevo(
+// apiKey: 'xkeysib-xxx',
+// options: ['client' => $customClient],
+// );
```
### Retries
@@ -204,17 +272,54 @@ $response = $client->transactionalEmails->sendTransacEmail(
### Timeouts
-The SDK defaults to a 30 second timeout. Use the `timeout` option to configure this behavior.
+The SDK does not configure a default timeout. Unless you set one, the underlying HTTP client's default applies (Guzzle, for example, defaults to no timeout). Set an explicit `timeout` (in seconds) at the client or request level:
```php
+// Client-level
+$client = new Brevo('xkeysib-xxx', ['timeout' => 30.0]);
+
+// Request-level (overrides client setting)
$response = $client->transactionalEmails->sendTransacEmail(
...,
options: [
- 'timeout' => 3.0 // Override timeout at the request level
+ 'timeout' => 3.0
]
);
```
+> Timeout forwarding is supported for Guzzle and Symfony HttpClient. Other PSR-18 clients ignore the `timeout` option.
+
+### Logging
+
+The SDK does not ship a built-in logger. Because the `client` option accepts any PSR-18 HTTP client, you can plug in **any PSR-3 logger** (Monolog, Symfony Logger, Laravel's `Log` facade) by wrapping that client with logging middleware. This keeps the SDK lean and lets you reuse the logger your application already configures.
+
+```php
+use Brevo\Brevo;
+use GuzzleHttp\Client;
+use GuzzleHttp\HandlerStack;
+use GuzzleHttp\Middleware;
+use GuzzleHttp\MessageFormatter;
+use Monolog\Logger;
+use Monolog\Handler\StreamHandler;
+
+$logger = new Logger('brevo');
+$logger->pushHandler(new StreamHandler('php://stderr', Logger::DEBUG));
+
+$stack = HandlerStack::create();
+$stack->push(Middleware::log(
+ $logger,
+ new MessageFormatter('{method} {uri} → {code}')
+));
+
+$client = new Brevo('xkeysib-xxx', [
+ 'client' => new Client(['handler' => $stack, 'timeout' => 5.0]),
+]);
+```
+
+Logging happens at the HTTP layer, so each SDK call produces one log line per HTTP request — **including retries**, which the SDK performs internally.
+
+> **Warning**: The `api-key` header is sent on every request. If your message formatter includes request headers (`{req_headers}`), redact it before writing to disk or shipping to an external sink.
+
## Contributing
While we value open-source contributions to this SDK, this library is generated programmatically.