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

Sendinblue Laravel Package

siterig/sendinblue

siterig/sendinblue provides a Laravel integration for the Sendinblue (now Brevo) API, simplifying configuration and common tasks such as sending transactional emails and managing contacts from your PHP application.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and verify it exists. The package is a Statamic v5 addon (it will not install cleanly against Statamic 4), so start with:

composer require siterig/sendinblue
php artisan vendor:publish --tag=sendinblue-config   # tag may differ; check the service provider

Then confirm the addon is actually registered — with zero stars and zero dependents, do not assume the package is wired correctly. Open vendor/siterig/sendinblue/src/ and read, in this order:

  1. ServiceProvider.php — what it registers, what it publishes, which events it listens to.
  2. The config file (config/sendinblue.php or similar) — this is the real public API of the package.
  3. The listener/job that calls Brevo — confirms whether it hooks SubmissionCreated, FormSubmitted, or something custom.

Configure the credentials. Almost certainly a Brevo API v3 key:

BREVO_API_KEY=xkeysib-...

First use case: contact form → one Brevo list. Point the config at a form handle and a list ID, map a couple of fields, submit the form locally, and look at the contact in Brevo. If it doesn't appear, jump straight to storage/logs/laravel.log — most low-traffic addons swallow API exceptions rather than surfacing them.

Implementation Patterns

Form-handle keyed config. Statamic forms live in resources/forms/*.yaml and are identified by handle (contact, newsletter). The cleanest pattern is one mapping block per form handle, so multiple forms can target different lists without conditional logic in your app code.

Explicit field mapping. Brevo contact attributes are uppercase, pre-defined in the Brevo UI, and case-sensitive. Map Statamic submission keys to Brevo attribute names rather than relying on identical naming:

'forms' => [
    'contact' => [
        'list_ids' => [3],
        'attributes' => [
            'email'     => 'EMAIL',
            'first_name'=> 'FIRSTNAME',
            'last_name' => 'LASTNAME',
            'company'   => 'COMPANY',
        ],
    ],
],

Any attribute you send must already exist on the Brevo account, or the API returns a 400 for the whole contact. Create FIRSTNAME, LASTNAME, COMPANY, etc. before wiring them up.

Double opt-in vs. single opt-in. For marketing lists, prefer Brevo's DOI flow (template ID + sender + redirect URL) over silently adding contacts. If the addon exposes a double_opt_in / template_id toggle, use it; if not, treat the addon as a "single opt-in only" tool and add consent handling yourself.

Consent and spam hygiene. Statamic's form validation and honeypot/reCAPTCHA run before the submission is created, so the addon only sees legitimate submissions — but it does not know about your consent checkbox. Guard in a listener or by only mapping forms that include a required consent field. Also decide what happens when the consent field is unchecked: the addon will still fire unless you gate it.

Deferring the API call. If the listener runs synchronously inside the request, a slow or failing Brevo API degrades your form response time. Two options: check whether the package dispatches a queued job (then ensure a worker is running in every environment, including staging), or bypass the package's listener and dispatch your own job from a SubmissionCreated listener using the package's client/mapping.

Per-environment behavior. Disable the integration outside production so local form testing doesn't pollute the Brevo list:

'enabled' => env('SENDINBLUE_ENABLED', app()->isProduction()),

If the addon doesn't offer a kill switch, wrap it: register nothing in local/testing via a conditional in AppServiceProvider, or point BREVO_API_KEY at a sandbox/test key.

Testing. Use Http::fake() around the Brevo endpoint and assert the payload from a submitted form:

Http::fake(['api.brevo.com/*' => Http::response(['id' => 1], 201)]);

$this->post('/!/forms/contact', [...])->assertSessionHasNoErrors();

Http::assertSent(fn ($req) =>
    $req['email'] === '[email protected]' &&
    in_array(3, $req['listIds'])
);

This is also the fastest way to discover what the package actually sends — the faked request body is the documentation.

Extension points. Because the addon's surface is thin, treat Statamic's own events as your extension points. A SubmissionCreated listener in app/Listeners/ lets you add tagging, custom attributes, or a secondary list without forking the package. If you need to change payload shape beyond config, fork the listener into your app rather than subclassing the vendor class.

Gotchas and Tips

Treat the source as the documentation. Zero stars, zero dependents, one recent release. Pin the exact version in composer.json ("siterig/sendinblue": "1.0.*" or a commit hash), read src/ before deploying, and be prepared to vendor a fork if the maintainer goes quiet. Check whether it ships tests at all — if not, write your own smoke test around the form submission.

Silent failures are the default failure mode. Many small Brevo addons catch the API exception, log it, and let the form succeed. Users see "thanks," no contact appears, and nobody notices for weeks. Add monitoring: log a warning on non-2xx, and consider an alert on repeated 400s. A 400 usually means an unknown attribute name; a 401 means a bad or revoked key; a 404 usually means a wrong list ID.

Brevo attribute names must be pre-created and uppercase. firstname will be rejected; FIRSTNAME will not. If your mapping looks right and contacts still fail, this is the first thing to check in the Brevo dashboard under Contacts → Settings → Contact attributes.

List IDs are integers, not names. A string list name, or an ID from a different Brevo account, fails silently or with a 404. Copy the numeric ID from the list URL in the Brevo UI.

updateEnabled determines duplicate behavior. If the addon sends updateEnabled: false (or omits it), a returning contact is not updated — new form submissions with a corrected name silently do nothing. If you need upsert semantics, verify the flag in the source and override it if necessary.

Statamic caching bites config changes. After editing the addon config or resources/forms/*.yaml, run:

php artisan config:clear
php artisan statamic:stache:clear

In production behind a config cache, php artisan config:cache during deploy is mandatory or your new mapping won't apply.

Field name mismatches. Statamic forms frequently use email, email_address, or mail. The addon maps whatever key you give it, so a typo produces a contact with an empty email or an outright 400. Confirm the actual submission payload by dumping SubmissionCreated's $event->submission->data() once.

Rate limits and batching. Brevo's API has per-second and per-day limits. If you're subscribing from a high-traffic form (or importing historical submissions), a synchronous per-submission call will hit them. Batch or queue when volume justifies it.

Double opt-in needs a template and sender that actually exist. DOI will fail if the template ID or sender is unverified in Brevo. Verify the sender domain before enabling it, or you'll get 400s that look like auth problems.

GDPR/consent is your responsibility, not the package's. Map the consent checkbox, store a timestamp of consent somewhere durable (a Statamic submission field is fine), and prefer DOI for anything marketing-related. The addon subscribes; it does not audit your lawful basis.

Check compatibility before upgrading Statamic. The package declares v5 support. A Statamic 5.x minor bump is usually safe, but with no dependents to surface breakage, run a quick form submission in staging after each Statamic or PHP upgrade — the API client and event signatures are the likely breakage points.

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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin