Major SDK releases: Node.js v6.0.0, PHP v5.0.0, Python v5.0.0
We’ve released the next major version of our three official SDKs. These are opt-in major releases with breaking changes — your existing v4.x/v5.x integrations are not affected unless you upgrade.
Most of the breaking changes come from an internal effort at Brevo to make our API endpoints, parameters and models more self-descriptive. The goal is to make the public surface easier to read at a glance — both for developers and for AI agents working against the Brevo API — so that names, shapes and required fields convey intent without needing to cross-reference external docs.
Concretely:
{ events: [...] })DateTime/datetime instead of string for dates, typed unions instead of generic maps)We’ve kept the previous major lines supported so you can adopt the new versions on your own timeline.
@getbrevo/brevo v6.0.0auth constructor option for custom AuthProvider injection (existing apiKey continues to work unchanged)getCompanies filter key, createBatchEvents payload shape, Balance endpoints, CRM types, model field removals/renamesgetbrevo/brevo-php v5.0.0GetCompaniesRequest::filters renamed, Event::createBatchEvents wrapper, Balance/CRM/Email Campaigns model changes, date fields tightened to DateTime, associations union flattenedbrevo-python v5.0.0get_companies keyword renamed, create_batch_events keyword change, Webhooks signature change, shape collapses (Union[str, List[str]], Dict[str, int]), 21 top-level imports removedBrevo (sync) and AsyncBrevoIf you’re not ready to migrate, pin to the previous major line — both lines will continue to receive wire-compatibility fixes.
Each SDK README includes an “Upgrading from v4.x / v5.x” guide with the full list of breaking changes and code examples.
Deprecation Notice: POST /contacts/batch
Effective: 30 October 2026
The Update Multiple Contacts endpoint (POST /contacts/batch) will be deprecated on 30 October 2026. This endpoint is being replaced by the newer and more scalable POST /v3/contacts/import API.
/v3/contacts/import.Contacts category attributes: valueStr field, and Ecommerce product search and alternative price
value (integer) field in category-type attribute enumerations now returns 0 for non-numeric values (e.g. language codes "en", "fr"). Previously these values may have been returned as distinct integers. Clients using value as a unique identifier for category enum items must migrate to the new valueStr field to correctly distinguish these entries.valueStr (string) field added to category-type attribute enumeration items. Always contains the original string representation of the value (e.g. "en", "fr", "1"). Use valueStr when the attribute value is non-numeric or when you need the exact string form alongside the numeric value field. valueStr is now a required field in the enumeration item schema.search query parameter for simultaneous search across SKU, name, and ID fields. Results are returned in priority order: exact SKU match > SKU prefix match > name match > ID match.alternativePrice filter parameters: alternativePrice[lte], alternativePrice[gte], alternativePrice[lt], alternativePrice[gt], alternativePrice[eq], alternativePrice[ne].alternativePrice (float) field on product objects, available in GET responses and supported in POST requests.unique_coupon_sent event. This event is triggered when a unique coupon code is sent to a contact from a coupon collection, enabling integrators to track coupon delivery, reconcile inventory, and sync coupon status into external systems.POST /events/batch) — The request body schema has changed. The array of events must now be wrapped in an object under an events key. Previously accepted: [{...}, {...}]. Now required: {"events": [{...}, {...}]}. Additionally, event_name and identifiers are now explicitly marked as required fields on each event object.POST /contacts) — New getId field (boolean, default false). When set to true alongside forceMerge: true, the response includes the id of the surviving contact after the merge. Useful when you need to reference the retained contact record immediately after creation.GET /loyalty/balance/programs/{pid}/transaction-history) — New loyaltySubscriptionId query parameter for filtering transaction history by a specific loyalty subscription.API specification overhaul: accuracy, completeness, and breaking corrections
This release reflects a major rework of the OpenAPI specification to bring it in line with actual API behavior. Some changes correct inaccuracies between the spec and the responses, some generated SDK types will change. See the breaking changes section before upgrading.
These are corrections to the spec that reflect reality but will require updates to code relying on the previously incorrect types.
GET /processes, GET /processes/{processId}) — Import info fields (invalid_emails, duplicate_contact_id, duplicate_ext_id, duplicate_email_id, duplicate_phone_id, duplicate_whatsapp_id, duplicate_landline_number_id) are now typed as string (URL to a CSV report) instead of integer. This corrects the type for all fields, not just duplicate_email_id which was previously patched.error, created_at, completed_at, and info.export (with total_records and file_size).GET /processes/{processId} 404 error code corrected from invalid_parameter to document_not_found.GET /account) — dateTimePreferences object removed from the response schema (including timezone, timeFormat, dateFormat). startDate, endDate, and users removed from the required fields list in plan objects.listAdditions → listAddition, hardBounces → hardBounce.GET /feeds, GET /feeds/{uuid}) — alias, isInternal, personalization, defaultAttr, and defaultContact fields removed from the response schema as they are not returned by the API.POST /webhooks/export) — messageId field corrected from integer to string.POST /senders/domains) — Domain name validation changed from a custom regex pattern to format: hostname.limit minimum on GET /processes and maxRetries minimum on feed endpoints raised from 0 to 1.GET /account — 400 error response now documented.400 error responses now documented on GET /corporate/groups/{id}, GET /corporate/groups, GET /corporate/admin-users, GET /corporate/ips.PUT /crm/objects/{object_type}/records) — Associations now support an action field (link or unlink), enabling removal of associations in the same upsert request. Added three illustrative request body examples.contactUpdated and contactDeleted added as supported event types for marketing webhooks.info and export_url fields now clearly scoped: info is only returned for completed IMPORTUSER processes; export_url is only returned for SEARCH_EXPORT_USERS, SEARCH_EXPORT_USERS_API, CAMPAIGN_USER_DETAILS, and EXPORT_WEBHOOK process types.username, password, token) now documented as conditionally returned based on authType. cache default corrected to true.id vs ext_id behavior, attribute key vs label guidance, and async processing details.GET /organization/invited/users, PUT /organization/user/invitation/revoke/{email}, PUT /organization/user/invitation/{action}/{email}, GET /organization/user/{email}/permissions.DELETE /corporate/subAccount/{id} now includes a description warning that deletion is permanent and unrecoverable.summary fields to several Senders, Domains, Webhooks, and Organization endpoints that previously had none.SDK bug fixes: Node.js v5.0.5, PHP v4.0.14, Python v4.0.11
duplicate_email_id is now typed as a string (URL to a CSV file) instead of an integer. The legacy in_process status value is now handled correctly across all SDKs.contact_properties and event_properties now accept boolean values in createEvent and createBatchEvents.attributes now accepts plain integers in createContact and updateContact. PHP users no longer need to cast integers to float.SDK updates: Node.js v5.0.3, PHP v4.0.11, Python v4.0.9
New endpoints, new fields, and API improvements across all three SDKs.
@getbrevo/brevo v5.0.3Added
client.event.getEvents() — retrieve a paginated list of custom events, filterable by contact_id, event_name, object_type, startDate, and endDate. Currently only supports custom events.client.event.createBatchEvents() — send multiple events in a single request. Returns a BatchAcceptedResponse with a confirmation message and queued event count.client.companies.deleteAnAttribute() — delete a CRM attribute by ID.PatchCrmAttributesIdRequest — update a CRM attribute’s display label and selectable option labels, scoped to companies or deals.GetProductDetails response now includes brand and description.CreateUpdateProductRequest and batch product upsert now accept optional brand and description fields.getActiveBalancesApi(), getContactBalances(), and getSubscriptionBalances() now accept an optional includeInternal parameter.getTransactionHistory() now supports filtering by status and transactionType.Improved
meta field on balance definition requests is now a typed object ({ isInternal?: boolean }) instead of a generic Record<string, unknown>.metaInfo size limit for products clarified: maximum 20,000 characters total.users field on plan verticals is now nullable (Item.Users | null).getbrevo/brevo-php v4.0.11Added
$client->event->getEvents() — retrieve a paginated list of custom events with filters for contact, event name, object type, and date range. Currently only supports custom events.$client->event->createBatchEvents() — track multiple contact interactions in a single request.PatchCrmAttributesIdRequest — update a CRM attribute’s display label and option labels.CreateUpdateProductRequest and batch product upsert now accept optional brand and description fields.getActiveBalancesApi(), getContactBalances(), and getSubscriptionBalances() now accept includeInternal.getTransactionHistory() now supports filtering by status and transactionType.Improved
meta field on balance definition requests is now a typed class instead of a generic array.metaInfo size limit for products clarified: maximum 20,000 characters total.users field on GetAccountResponsePlanVerticalsItem is now nullable.Fixed
createContact() no longer throws BrevoException: Failed to deserialize response: Syntax error on empty success responses.brevo-python v4.0.9Added
client.event.get_events() — retrieve a paginated list of custom events with filters for contact, event name, object type, and date range. Currently only supports custom events.client.event.create_batch_events() — track multiple contact interactions in a single request.CreateUpdateProductRequest and batch product upsert now accept optional brand and description fields.GetProductDetails response now includes brand and description.get_active_balances_api(), get_contact_balances(), and get_subscription_balances() now accept include_internal.get_transaction_history() now supports filtering by status and transaction_type.Improved
meta field on balance definition requests is now a typed model with an is_internal flag.metaInfo size limit for products clarified: maximum 20,000 characters total.users field on plan verticals is now nullable.Two new fields are now supported on the POST /products and POST /products/batch endpoints, as well as the GET /products/{id} response:
brand — Brand name of the product. String, max 128 characters. Example: "Adidas".description — Description of the product. String, max 3000 characters. Example: "Shoes for sports".metaInfo limit updated: The size limit for the metaInfo field has changed from 1000 KB to 20,000 characters (total across all keys and values). The maximum number of keys remains 20.
A new GET /events endpoint is available to retrieve events filtered by contact, name, object type, or date range.
Query parameters:
The response includes a count field for pagination and an events array sorted by event_date descending.
See Event endpoints for the full reference.
These are breaking changes to the POST /events/batch endpoint.
Response code changed: 204 → 202
Successful batch requests now return 202 Accepted instead of 204 No Content. The response body is no longer empty — it returns a JSON object:
Update any client code that checks for 204 on batch event responses.
Partial success status renamed: partialSuccess → partiallyQueued
The status field in the 207 partial success response body has been renamed from partialSuccess to partiallyQueued. Update any client code parsing this field.
Balance definitions and tier groups now support a meta object with an isInternal flag:
Internal balance definitions are excluded from member-facing balance reads by default. Pass includeInternal=true as a query parameter to include them.
The includeInternal query parameter is available on the following endpoints:
GET /loyalty/config/programs/{pid}/balance-definitionsGET /loyalty/balance/programs/{pid}/subscriptions/{cid}/balancesGET /loyalty/balance/programs/{pid}/balancesGET /loyalty/config/programs/{pid}/membersThe transaction history endpoint (GET /loyalty/balance/programs/{pid}/subscriptions/{cid}/transactions) now supports additional query parameters:
The offset parameter now represents a page number (not a record skip count).
SDK updates: Node.js v5.0.1, PHP v4.0.10, Python v4.0.7
Bug fixes, type corrections, and a deprecation across all three SDKs.
@getbrevo/brevo v5.0.1Fixed
GetCampaignStats: appleMppOpens and opensRate are now typed as number | null. The API returns null when no data is available for the campaign period.Order.products: the full set of product fields is now exposed — price, productId, variantId, quantity, and quantityFloat. Previously only quantity was available.GetAccountResponsePlanVerticalsItem.users: now typed as optional/nullable, matching API behavior on certain plan types.createContact(): no longer throws a JSON parse error on 204 No Content responses (returned when a contact already exists).Deprecated
transactionalSms.sendTransacSms() — use transactionalSms.sendTransacSmsAsync() instead. The synchronous variant adds latency by waiting for carrier acknowledgment.getbrevo/brevo-php v4.0.10Added
$client->event->createBatchEvents() to track multiple contact interactions in a single request.getEmailCampaign() accepts a new optional excludeHtmlContent flag to omit the HTML body from the response.Fixed
UpdateContactRequest and CreateContactRequest: boolean values in union-typed attribute maps now serialize correctly. Previously threw JsonException: Cannot serialize value of type boolean.Order::products: OrderProductsItem now exposes all product fields — price, productId, variantId, quantity, quantityFloat.GetCampaignStats: appleMppOpens and opensRate are now correctly typed as nullable (?int, ?float).Deprecated
sendTransacSms() — use sendAsyncTransactionalSms() instead.brevo-python v4.0.7Fixed
GetCampaignStats: apple_mpp_opens and opens_rate are now correctly typed as nullable.Order.products: all product fields are now accessible — price, product_id, variant_id, quantity, quantity_float.create_contact(): correctly handles 204 No Content responses without raising a deserialization error.Deprecated
transactional_sms.send_transac_sms() — use transactional_sms.send_transac_sms_async() instead.