Connect Bubble to Brevo (formerly Sendinblue) using the API Connector with the `api-key` header (lowercase, hyphenated — not `Authorization: Bearer`). A single API key and one Bubble resource covers both transactional emails (POST /smtp/email) and marketing contact management (POST /contacts). Bubble's Private header checkbox keeps the key server-side. Free tier includes 300 emails/day with unlimited contacts.
| Fact | Value |
|---|---|
| Tool | Sendinblue |
| Category | Marketing |
| Method | Bubble API Connector |
| Difficulty | Beginner |
| Time required | 1 hour |
| Last updated | July 2026 |
Brevo (Sendinblue) + Bubble: Transactional Email and Contact Management
Brevo's biggest advantage over competitors is its unified scope: one API key, one integration, and you have both a transactional email system (sending confirmations, welcome emails, receipts) and a marketing contact management system (adding users to lists, segmenting audiences for campaigns). Most email platforms specialize in one or the other — SendGrid focuses on transactional, Mailchimp on marketing. Brevo does both from the same dashboard.
The Bubble integration is refreshingly simple once you know the one gotcha: the authentication header is named `api-key` in lowercase with a hyphen — not `Authorization: Bearer` as you'd expect from a modern REST API. This trips up almost everyone on first setup because using the wrong header name returns a 401 with no helpful explanation of what went wrong.
From Bubble's perspective, the security model is ideal: one Private shared header in the API Connector covers all Brevo calls. Every Bubble workflow that triggers an email or adds a contact goes through Bubble's servers, where the Private header is injected invisibly. The api-key never reaches the user's browser.
Brevo's free tier — 300 emails per day with unlimited contact storage — is generous enough to handle early-stage Bubble apps through their initial launch and user acquisition phase. You won't need to upgrade until your daily email volume consistently exceeds that threshold.
Note: Sendinblue rebranded to Brevo in 2023. Both names refer to the same platform. The URL slug for this page uses the older 'sendinblue' name because that's the search term most Bubble users still search for, but the platform, API endpoint, and all documentation now use 'Brevo'.
Integration method
Call Brevo's unified API at https://api.brevo.com/v3 using the non-standard `api-key` header (marked Private in API Connector) to send transactional emails and manage marketing contact lists from Bubble workflows.
Prerequisites
- A Brevo (formerly Sendinblue) account — the free tier at brevo.com is sufficient for initial setup
- A Brevo API key, generated at Settings → API Keys in your Brevo account dashboard
- A verified sender email address in Brevo (Settings → Senders & IP → Senders) — transactional emails must be sent from a verified domain or address
- The API Connector plugin installed in your Bubble app (Plugins tab → Add plugins → 'API Connector' by Bubble)
- The Brevo list ID for any marketing lists you plan to add contacts to (find it in Brevo → Contacts → Lists — the ID appears in the URL when viewing a list)
Step-by-step guide
Generate a Brevo API key and verify your sender email
Log into your Brevo account at app.brevo.com. Navigate to the top-right menu → Settings → API Keys (or go to app.brevo.com/settings/keys/api). Click 'Generate a new API key'. Enter a name like 'Bubble Integration' → click 'Generate'. Copy the API key — it starts with `xkeysib-` and is shown only once. Store it in a secure place (you can always generate a new one if lost, but you cannot view it again after closing the dialog). Important: Brevo's API uses a non-standard header name. The key goes in a header named exactly `api-key` (all lowercase, hyphen between 'api' and 'key'). This is not `Authorization: Bearer`, not `X-API-Key`, not `apikey`. The exact header name matters — any variation returns a 401 Unauthorized with a message that just says 'authentication failed' without identifying the header name as the problem. Before configuring Bubble, also verify your sender email. In Brevo → Settings → Senders & IP → Senders, click 'Add a new Sender'. Enter the name and email address you want transactional emails to appear from. Brevo sends a verification email to this address — click the confirmation link. Unverified sender addresses cause the transactional email API to return a 400 error: 'sender email is invalid'. This is a Brevo account setup requirement, not a Bubble issue.
1// Brevo API key format2// Key name in Brevo: 'Bubble Integration'3// Key value: xkeysib-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxx45// Correct Brevo API header:6// Header name: api-key7// Header value: xkeysib-... (your full key)89// WRONG headers (all return 401):10// Authorization: Bearer xkeysib-...11// X-API-Key: xkeysib-...12// apikey: xkeysib-...13// Api-Key: xkeysib-... (capitalization matters — must be lowercase 'api-key')Pro tip: Generate a separate API key for each environment (development, production) if your Bubble app has multiple versions. This lets you revoke development keys without affecting production, and you can audit which environment made which API calls in Brevo's API activity logs.
Expected result: Brevo account shows an active API key under Settings → API Keys. Your sender email address shows as 'Verified' under Settings → Senders & IP → Senders.
Configure the API Connector with the api-key header
In Bubble, click the Plugins tab → 'API Connector' (install if not already present: Plugins tab → Add plugins → 'API Connector' by Bubble). Click 'Add another API'. Name it 'Brevo'. In the Shared headers section, click '+ Add a shared header'. Enter: - Header name: `api-key` — type this exactly: lowercase 'api', hyphen, lowercase 'key'. Do not capitalize any letters. - Header value: your Brevo API key (the xkeysib-... string you generated in step 1) - Enable the **Private** checkbox: this is critical. Private ensures Bubble never sends this header value to the user's browser — it's applied server-side on every request. Leave the Authentication dropdown set to 'None'. Brevo's authentication is handled entirely by the `api-key` header; Bubble's built-in auth mechanisms are not needed. Set the base URL to: `https://api.brevo.com/v3` The shared header approach means both the transactional email call and the contact management call (which you'll add next) automatically include the `api-key` header without you needing to add it individually to each call. One Private header covers the entire Brevo integration.
1// API Connector: Brevo2{3 "api_name": "Brevo",4 "base_url": "https://api.brevo.com/v3",5 "authentication": "none",6 "shared_headers": [7 {8 "name": "api-key",9 "value": "xkeysib-YOUR_API_KEY",10 "private": true11 }12 ]13}Pro tip: After adding the shared header, verify the Private checkbox is checked by looking for a lock icon or 'Private' label on the header row. If Private is not checked, the api-key value will be visible in browser network traffic — a security risk that exposes your entire Brevo account.
Expected result: API Connector shows 'Brevo' with a single Private `api-key` shared header. The header value is masked in the editor. No authentication type is set. Base URL is https://api.brevo.com/v3.
Add the transactional email call (POST /smtp/email)
Inside the Brevo API configuration, click 'Add a call'. Name it 'Send Email'. Set method to POST, path to `/smtp/email`. Switch the Body format to JSON. Add the following body fields: `sender` — type: object with sub-fields: `name` (text, e.g., 'Your App Name') and `email` (text, e.g., 'noreply@yourapp.com'). The sender email must be the verified address from step 1. `to` — type: list of objects, each with `email` (text) and `name` (text). In Bubble's API Connector, lists of objects require careful configuration — set the 'to' parameter as a JSON array with a single object containing the dynamic email and name fields. `subject` — text, can be dynamic. `htmlContent` — text, can be dynamic. This is the full HTML email body. Alternatively, if you're using Brevo email templates, use `templateId` (integer) instead of `htmlContent` and pass `params` for template variable substitution. Click 'Initialize call'. Enter a real email address as the recipient (your own address for testing). Click Initialize. If you see HTTP 201 Created in the response, the configuration is correct. Check your email inbox — you should receive the test email. Alternative template-based approach: instead of htmlContent, use `templateId` (the integer ID from Brevo's Email Templates section) and `params` (an object with key-value pairs matching your template variables). Template-based emails are easier to maintain and allow non-developers to update email design in Brevo without changing Bubble workflows.
1// Brevo POST /smtp/email — call configuration2{3 "method": "POST",4 "path": "/smtp/email",5 "body": {6 "sender": {7 "name": "Your App Name",8 "email": "noreply@yourapp.com"9 },10 "to": [11 {12 "email": "<dynamic: recipient email>",13 "name": "<dynamic: recipient name>"14 }15 ],16 "subject": "<dynamic: email subject>",17 "htmlContent": "<dynamic: full HTML email body>"18 }19}2021// Template-based alternative (uses Brevo template editor):22{23 "sender": { "name": "Your App Name", "email": "noreply@yourapp.com" },24 "to": [{ "email": "<dynamic>", "name": "<dynamic>" }],25 "templateId": 42,26 "params": {27 "FIRSTNAME": "<dynamic: user first name>",28 "ORDER_ID": "<dynamic: order ID>"29 }30}Pro tip: For Bubble apps with multiple email types (welcome, reset password, order confirmation), create a separate API Connector call for each with different subject and body defaults, rather than building dynamic logic in one call. This makes debugging and testing each email type independently much easier.
Expected result: Initialize call returns HTTP 201 Created. A test email arrives at your inbox from the verified sender address. The API Connector shows 'Send Email' as a configured call under the Brevo resource.
Add the contact management call (POST /contacts)
Inside the Brevo API configuration, click 'Add a call'. Name it 'Add Contact'. Set method to POST, path to `/contacts`. Switch the Body format to JSON. Add these body fields: `email` — text, dynamic (the contact's email address). `attributes` — object with contact attribute keys matching Brevo's attribute names. Standard attributes are `FIRSTNAME` and `LASTNAME` (uppercase, as defined in Brevo → Contacts → Contact attributes). Add any custom attributes your Brevo account has defined. `listIds` — array of integers. Brevo list IDs are integers (e.g., `[5]` not `["5"]`). Find your list ID in Brevo → Contacts → Lists — the number in the URL when viewing a list (e.g., app.brevo.com/contact/list/id/5 → list ID is 5). Hardcode the specific list ID(s) for this call. `updateEnabled` — boolean, value: `true`. This is important: when set to true, if a contact with that email already exists in Brevo, the API updates their attributes rather than returning a conflict error. Without updateEnabled: true, re-submitting the same email returns a 400 error ('Contact already exists'), which would break your Bubble workflow on repeated signups or form submissions. Click 'Initialize call'. Enter a test email address and click Initialize. Successful response is HTTP 201 Created (new contact) or HTTP 204 No Content (existing contact updated). Check Brevo → Contacts to confirm the test contact appears with the correct attributes and list assignment.
1// Brevo POST /contacts — call configuration2{3 "method": "POST",4 "path": "/contacts",5 "body": {6 "email": "<dynamic: contact email>",7 "attributes": {8 "FIRSTNAME": "<dynamic: first name>",9 "LASTNAME": "<dynamic: last name>"10 },11 "listIds": [5],12 "updateEnabled": true13 }14}1516// Note: listIds must be an integer array, not strings17// [5] = correct18// ["5"] = incorrect (returns 400)19// List IDs visible in Brevo URL: app.brevo.com/contact/list/id/5Pro tip: To add contacts to different lists based on their signup context (e.g., list 5 for 'Blog Subscribers', list 8 for 'Trial Users'), create separate 'Add Contact' calls in the API Connector — one per list, each with the appropriate listId hardcoded. This avoids building dynamic list ID logic and makes workflow actions self-documenting.
Expected result: Initialize call returns HTTP 201 or 204. Test contact appears in Brevo → Contacts with FIRSTNAME and LASTNAME attributes set, and is a member of the specified list. Re-running Initialize with the same email updates the contact without error (due to updateEnabled: true).
Chain both calls in a Bubble workflow and test end-to-end
With both API calls configured, you can now use them in Bubble workflows. The most common pattern is chaining them on user signup. Go to your signup page or the page where users create accounts. In the workflow triggered by the signup button (or wherever your user creation workflow lives), add these actions after the user creation step: Action: 'Plugins → Brevo → Add Contact' - email: Current User's email - attributes.FIRSTNAME: Input_FirstName's value (or Current User's first name field) - attributes.LASTNAME: Input_LastName's value Action: 'Plugins → Brevo → Send Email' - to[0].email: Current User's email - to[0].name: Current User's first name - subject: 'Welcome to [Your App Name]!' - htmlContent: Build your welcome email HTML string using Bubble's dynamic text expressions (or use a Brevo templateId) Bubble API Connector actions run server-side sequentially. Both calls use the same Private `api-key` shared header automatically. Total time for both calls is typically under 2 seconds. Test end-to-end: create a new test user account in your Bubble app. Verify: (1) the test user appears in Brevo → Contacts with the correct attributes and list membership, and (2) a welcome email arrives in the test email inbox. Check Bubble's Logs tab → Workflow logs to see the API call status codes (201 for new contact, 204 for updated contact, both are successes). RapidDev's team has implemented Brevo email workflows in dozens of Bubble apps — from simple welcome sequences to complex multi-step drip campaigns. If you need help with advanced email automation or multi-list segmentation, book a free scoping call at rapidevelopers.com/contact.
1// Bubble workflow: 'User Signup' button clicked2// Action sequence:34// Action 1: Sign the user up5// (Bubble built-in: Sign the user up - email, password)67// Action 2: Add to Brevo contact list8// Plugin: Brevo - Add Contact9// email = Input_Email's value10// attributes.FIRSTNAME = Input_FirstName's value11// attributes.LASTNAME = Input_LastName's value12// listIds = [5] (hardcoded in the API call config)13// updateEnabled = true (hardcoded in the API call config)1415// Action 3: Send welcome email16// Plugin: Brevo - Send Email17// to[0].email = Input_Email's value18// to[0].name = Input_FirstName's value19// subject = "Welcome to My App!"20// htmlContent = "<h1>Hi " + Input_FirstName's value + ",</h1><p>Thanks for joining!</p>"Pro tip: Add error handling to the workflow by enabling Bubble's 'Stop on error' setting for the Brevo API call actions, and add a 'Show message' action at the end to confirm the signup completed. If the email send fails (e.g., verified sender issue), you want the user to still be signed up — consider making the email send action non-blocking by scheduling it as a separate Backend Workflow.
Expected result: Signing up a new user in Bubble creates a Brevo contact AND delivers a welcome email. Bubble's Logs tab shows the 'Add Contact' call returning 201 and the 'Send Email' call returning 201. The test inbox receives the welcome email within 30 seconds.
Common use cases
User Signup Welcome Email + Contact List Enrollment
When a user signs up in Bubble (via Bubble's built-in sign up action or a custom form), trigger a Brevo workflow: first POST /contacts to add the user to your welcome email list in Brevo, then POST /smtp/email to send a personalized welcome email using a Brevo template. The two calls chain in a single Bubble workflow in about 2 seconds total. The updateEnabled flag on the contacts call means re-registrations or email updates don't cause duplicate errors.
Build a Bubble signup page that, when a user creates an account, (1) adds their email and first name to Brevo list ID 5 and (2) sends a welcome email from noreply@yourapp.com with the subject 'Welcome to [App Name]' and a personalized HTML body including their first name.
Copy this prompt to try it in Bubble
Transactional Email Notifications
Use Brevo for all system-generated emails in your Bubble app: order confirmations, appointment reminders, password reset links, invoice delivery, and status updates. Each event in a Bubble workflow (e.g., 'Order placed', 'Appointment confirmed') triggers a POST /smtp/email call with the relevant data merged into the email body. Brevo handles delivery, bounce tracking, and open rate reporting.
Create a Bubble workflow that fires when an order's status changes to 'Shipped'. It should send a Brevo transactional email to the customer's email with the order number, estimated delivery date, and a tracking link. Use the customer's first name in the subject line.
Copy this prompt to try it in Bubble
Marketing Segmentation from Bubble User Actions
As users take key actions in your Bubble app (upgrading plans, completing onboarding, abandoning a cart), use Brevo's contact update endpoint to add them to specific Brevo lists or set contact attributes. This enables Brevo marketing campaigns to target users based on Bubble app behavior — without needing a separate CRM or third-party automation tool.
Build a Bubble workflow that fires when a user's subscription status changes to 'Trial Expired'. It should update the user's Brevo contact attributes to set SUBSCRIPTION_STATUS='trial_expired' and add them to Brevo list ID 12 (re-engagement campaign list).
Copy this prompt to try it in Bubble
Troubleshooting
API returns 401 Unauthorized on every call
Cause: The header name is wrong. Using `Authorization: Bearer`, `X-API-Key`, `apikey`, or a capitalized version of `api-key` all return 401. Brevo's API accepts only the exact lowercase hyphenated header name `api-key`. The 401 message does not identify the header name as the issue.
Solution: In Bubble's API Connector → Brevo → Shared headers, delete the current header and re-add it with the exact name `api-key` (all lowercase, hyphen between api and key). Confirm the value is the full API key string starting with `xkeysib-`. Also verify the Private checkbox is enabled.
Send Email call returns 400 with message 'sender email is invalid'
Cause: The sender email address in the call's `sender.email` field has not been verified in Brevo. Brevo requires all transactional email sender addresses to be verified through a domain or email verification process.
Solution: Go to Brevo → Settings → Senders & IP → Senders. Confirm the email address you're using in the `sender.email` field shows as 'Verified'. If not, click 'Add a new Sender', enter the address, and complete the verification email flow. Only then will transactional sends from that address succeed.
Add Contact call succeeds (200 or 204) in Initialize but Bubble workflow shows an error for existing contacts
Cause: Brevo returns HTTP 204 No Content (not 201) when updating an existing contact. Bubble's API Connector may interpret a 204 response as an error if the call's response handling expects a body. HTTP 204 has no response body by design.
Solution: In the API Connector's 'Add Contact' call settings, ensure 'updateEnabled' is set to `true` in the body. This prevents the 400 'Contact already exists' error. For the 204 response itself, Bubble treats it as a successful response in most workflow contexts — if you're seeing errors, check that the workflow action's conditional logic isn't expecting specific response body content from the 204.
Initialize call fails with 'There was an issue setting up your call' for the contacts endpoint
Cause: The Initialize call for a POST endpoint needs a complete, valid request body. If any required body field (like `email`) is missing or malformed during initialization, Brevo returns a 400 error that Bubble interprets as an initialization failure.
Solution: During Initialize, enter a real email address in the email test field and enter a real integer (like `5`) for the listIds field. Both fields must have valid test values for Brevo to accept the request and return a 201 or 204 that Bubble can use to detect the response structure.
Best practices
- Use the exact header name `api-key` (lowercase, hyphenated) — any capitalization variation returns 401 with no diagnostic information about the header name being wrong. Double-check this before any other troubleshooting.
- Always set `updateEnabled: true` in the POST /contacts body. Without it, adding a contact that already exists returns a 400 error. With updateEnabled, re-submissions safely update the contact's attributes instead of failing — making your workflow idempotent.
- Verify your sender email address in Brevo before testing transactional sends. An unverified sender returns 400 'sender email is invalid' — this is a Brevo account setup step, not a Bubble configuration issue.
- Store Brevo list IDs (integers) in a Bubble AppConfig data type rather than hardcoding them in multiple API calls. When you need to update a list ID (e.g., creating a new Brevo list for a campaign), you update one record instead of modifying multiple API Connector calls.
- Brevo list IDs are integers, not strings. Passing `["5"]` instead of `[5]` for the listIds parameter returns a 400 error. When referencing list IDs from Bubble's database in dynamic calls, ensure the field type is number and convert to integer if needed.
- Use Brevo email templates (templateId + params) instead of inline htmlContent for maintainability. Templates can be updated by non-technical team members in Brevo's email editor without touching Bubble workflows — reducing the need for code changes when email content needs updating.
- Keep the Welcome Email and Add Contact as two sequential actions in the same Bubble workflow rather than separate triggers. This ensures both happen atomically on signup — if the user cancels or the session expires between two separate triggers, the contact add or email send might not happen.
Alternatives
Mailchimp excels at marketing campaigns with advanced audience segmentation, A/B testing, and visual email templates — but handles transactional email separately through Mailchimp Transactional (formerly Mandrill), which requires an add-on. Brevo handles both with one API key. Choose Brevo if you want simplicity and a generous free tier; choose Mailchimp if you need advanced campaign analytics and have an established marketing workflow.
SendGrid is a transactional email specialist with superior deliverability infrastructure, detailed email analytics, and advanced features like email validation API and ISP reputation management. SendGrid does not offer marketing contact management under the same free tier. Choose Brevo for combined transactional + marketing needs at low cost; choose SendGrid for high-volume transactional email where deliverability and detailed bounce management are priorities.
HubSpot is a full CRM platform with email marketing as one component. HubSpot offers deeper contact lifecycle management, sales pipeline features, and more sophisticated marketing automation than Brevo. HubSpot's free tier is more limited on email sends. Choose Brevo if email is your primary need; choose HubSpot if you need a full CRM with email as part of a broader revenue operations workflow.
Frequently asked questions
Does Brevo work with Bubble's free plan?
Yes. The API Connector plugin and all API call actions work on Bubble's free plan. Brevo itself also has a free tier (300 emails/day, unlimited contacts). Both tools can be used together at zero cost for early-stage Bubble apps. You only need to upgrade either plan when volume or feature requirements exceed the free tier limits.
What is the difference between Sendinblue and Brevo?
Sendinblue rebranded to Brevo in May 2023. The platform, API, and all features are the same — only the brand name changed. The API endpoint is now api.brevo.com/v3 (though the old api.sendinblue.com endpoint still works for backward compatibility). The Bubble integration slug for this page uses 'sendinblue' because that's the search term most users still look for.
Why does my contact API call return 204 instead of 201?
HTTP 204 No Content is Brevo's response when a contact with that email already exists and updateEnabled is true — the contact was updated successfully. HTTP 201 Created is returned for brand new contacts. Both 201 and 204 indicate success. Bubble treats both as successful workflow actions. If your workflow is checking for a specific response body after the contacts call, note that 204 has no response body by design.
Can I use Brevo for SMS messages from Bubble?
Yes. Brevo's unified API includes SMS via POST /transactionalSMS/sms. Use the same `api-key` header in the shared header configuration. The request body needs a `sender` (11 characters max, letters and digits only), `recipient` (phone number in international format, e.g., +12025551234), and `content` (SMS message text). SMS requires a separate Brevo SMS credit balance — SMS credits are purchased separately from email plan allowances.
How do I use Brevo email templates instead of inline HTML?
In the Send Email API call body, replace `htmlContent` with `templateId` (integer — the template ID from Brevo → Email → Templates) and add a `params` object with key-value pairs matching your template's variables (e.g., `{ "FIRSTNAME": "Jane", "ORDER_ID": "12345" }`). Brevo substitutes the variables into the template at send time. This approach lets you update email design in Brevo without changing Bubble workflows.
What happens if I send more than 300 emails in a day on Brevo's free tier?
Brevo queues emails that exceed the daily sending limit until the next day when the limit resets — they are not permanently rejected, just delayed. If consistent daily volumes exceed 300, upgrade to Brevo's Starter plan which removes the daily cap and charges pay-per-email with no monthly minimum. For most early-stage Bubble apps, 300 emails/day is sufficient through the first several months of user growth.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation