Connect Retool to Brevo (formerly Sendinblue) by creating a REST API Resource with Brevo's v3 API base URL and API key authentication. Use Brevo's REST API to build unified email and SMS marketing dashboards that manage contacts, view campaign analytics, send transactional messages, and monitor list health — giving your marketing ops team direct access to Brevo's multi-channel data without switching between tools.
| Fact | Value |
|---|---|
| Tool | Brevo (formerly Sendinblue) |
| Category | Marketing |
| Method | REST API Resource |
| Difficulty | Beginner |
| Time required | 20 minutes |
| Last updated | April 2026 |
Build a Brevo Email and SMS Marketing Operations Dashboard in Retool
Brevo (formerly Sendinblue) is distinctive among email marketing platforms in offering email campaigns, transactional email, and SMS marketing under a single API and subscription — a combination that makes it especially popular with businesses running multi-channel customer communication. While Brevo's built-in dashboard handles day-to-day operations, marketing and CRM teams often need to combine Brevo data with their customer database, support tickets, or order history for a complete picture of customer engagement.
Retool bridges this gap by giving your team direct query access to Brevo's v3 REST API. Build panels where ops teams can search contacts by email, view their campaign engagement history and SMS opt-in status, add or remove contacts from lists, send transactional emails triggered by internal events, and track campaign performance metrics across both email and SMS channels — all from a single Retool app that can also query your own database resources simultaneously.
Brevo's API uses simple API key authentication with the key sent as an 'api-key' request header. Retool's server-side proxy keeps the key secure. All major Brevo capabilities — contacts, lists, campaigns, transactional sending, and automation workflows — are accessible through the well-documented v3 API.
Integration method
Brevo connects to Retool through a REST API Resource using API key authentication passed as an 'api-key' header. All requests are proxied server-side through Retool, keeping your Brevo API key secure. You configure the base URL and authentication once at the resource level, then build individual queries for each Brevo operation — contact management, campaign analytics, transactional email triggers, and SMS management — using Brevo's v3 REST API.
Prerequisites
- A Brevo account (free plan includes API access with limited sending volume)
- A Brevo v3 API key (Settings → SMTP & API → API Keys → Generate a new API key)
- A Retool account with permission to create Resources
- Familiarity with Retool's query editor and basic Table component configuration
- Optional: a connected CRM or customer database in Retool for combined contact lookups
Step-by-step guide
Create a Brevo REST API Resource
Navigate to the Resources tab in your Retool instance and click Add Resource. Select REST API from the list of resource types. Name the resource 'Brevo API' — using the current brand name helps avoid confusion as the platform rebranded from Sendinblue to Brevo in 2023. In the Base URL field, enter https://api.brevo.com/v3. This is Brevo's current v3 REST API base URL. All endpoint paths will be appended to this URL. Ensure there is no trailing slash after '/v3'. Brevo authenticates API requests using a custom header named api-key. In the Headers section of the resource configuration, click Add Header. Set the header name to api-key (lowercase, with hyphen) and the value to your Brevo API key. Note the header name is 'api-key', not 'Authorization' — this is a Brevo-specific convention. For better security, store the API key as a configuration variable in Retool. Go to Settings → Configuration Variables, create a variable named BREVO_API_KEY, mark it as Secret, and paste your key. Then in the header value field, use {{ retoolContext.configVars.BREVO_API_KEY }} instead of the raw key. Brevo's API also accepts and returns JSON. Add a default header: Content-Type with value application/json. This ensures POST and PUT requests include the correct content type header. Click Save Changes to save the resource.
Pro tip: Brevo's API key is tied to the account, not to a specific user. Create a dedicated API key labeled 'Retool Integration' in Brevo's Settings → SMTP & API section so you can revoke it independently without affecting other integrations. Free plan users have API rate limits — check Brevo's documentation for current limits.
Expected result: The Brevo API REST resource is saved in Retool with the api-key authentication header and Content-Type header configured. The resource is available for queries across all apps in your workspace.
Query contacts and list management
Create queries to retrieve and manage Brevo contacts. In your Retool app, open the Code panel and click + to add a query. Create your first query named searchContacts: - Method: GET - Path: /contacts - URL parameters: - email: {{ textInput_email.value }} (for exact email lookup) - limit: 50 - offset: 0 For looking up a specific contact by email (the most common operation for support and CRM teams), create a query named getContactByEmail: - Method: GET - Path: /contacts/{{ encodeURIComponent(textInput_email.value) }} This returns the full contact profile including: email, firstName, lastName, emailBlacklisted (unsubscribed status), smsBlacklisted, listIds (which lists they belong to), and attributes (all custom attributes set for this contact). The attributes object contains any custom fields you've defined in Brevo for your contacts, such as company name, order count, or customer segment. Create a query named getAllLists: - Method: GET - Path: /contacts/lists - URL parameters: limit=50, offset=0 Bind getAllLists to a Dropdown component named dropdown_list so users can select a list for filtering or bulk actions. Set getAllLists to run on page load. Create a query named getContactsInList: - Method: GET - Path: /contacts/lists/{{ dropdown_list.value }}/contacts - URL parameters: limit=100, offset=0 Bind this to a Table component that shows all contacts in the selected list with their engagement status.
1// JavaScript transformer — format contact profile for display2const contact = data;3if (!contact || !contact.email) return {};45const attrs = contact.attributes || {};67return {8 email: contact.email,9 first_name: attrs.FIRSTNAME || 'N/A',10 last_name: attrs.LASTNAME || 'N/A',11 phone: attrs.SMS || 'N/A',12 email_subscribed: !contact.emailBlacklisted,13 sms_subscribed: !contact.smsBlacklisted,14 subscription_status: contact.emailBlacklisted15 ? 'Unsubscribed'16 : 'Subscribed',17 list_count: (contact.listIds || []).length,18 list_ids: (contact.listIds || []).join(', '),19 created_at: contact.createdAt20 ? new Date(contact.createdAt).toLocaleDateString()21 : 'N/A',22 modified_at: contact.modifiedAt23 ? new Date(contact.modifiedAt).toLocaleDateString()24 : 'N/A',25 // Include all custom attributes26 ...Object.fromEntries(27 Object.entries(attrs)28 .filter(([k]) => !['FIRSTNAME', 'LASTNAME', 'SMS'].includes(k))29 .map(([k, v]) => [k.toLowerCase(), v])30 )31};Pro tip: Brevo stores contact attributes in ALL_CAPS by convention (FIRSTNAME, LASTNAME, SMS). When reading custom attributes you've defined, they'll also be in uppercase. The transformer above normalizes them to lowercase for display — adjust the filter list based on your actual attribute names.
Expected result: The contact lookup query returns a full contact profile with subscription status, list memberships, and all custom attributes. The list dropdown populates with all available Brevo contact lists.
Fetch email campaign analytics and performance data
Create queries to retrieve campaign performance data. Create a query named getEmailCampaigns: - Method: GET - Path: /emailCampaigns - URL parameters: - status: sent (to retrieve only sent campaigns, not drafts) - limit: 50 - offset: 0 - sort: desc (newest first) This returns all sent email campaigns with their statistics. Each campaign object includes: name, subject, sendAtBestTime, statistics (with globalStats containing delivered, opened, clicked, unsubscribed, hardBounces, softBounces counts), and sentDate. Bind getEmailCampaigns to a Table component. Add a JavaScript transformer to calculate derived metrics: For individual campaign detail, create a query named getCampaignDetail: - Method: GET - Path: /emailCampaigns/{{ table_campaigns.selectedRow.id }} This returns the full campaign object including the HTML content, the list of recipients (list IDs), and complete statistics. When a campaign is selected in the table, getCampaignDetail runs automatically to populate a detail panel. For SMS campaign data, create getSMSCampaigns: - Method: GET - Path: /smsCampaigns - URL parameters: status=sent, limit=50 Bind both email and SMS campaign tables in separate Tab panels of your dashboard. Add a Chart component showing open rate and click rate trends across your last 20 email campaigns as a line chart — this helps identify whether email engagement is trending up or down.
1// JavaScript transformer — calculate campaign performance metrics2const campaigns = (data.campaigns || []);34return campaigns.map(campaign => {5 const stats = campaign.statistics?.globalStats || {};6 const delivered = parseInt(stats.delivered || 0);7 const opened = parseInt(stats.uniqueViews || 0);8 const clicked = parseInt(stats.clickers || 0);9 const unsubscribed = parseInt(stats.unsubscriptions || 0);1011 const openRate = delivered > 012 ? ((opened / delivered) * 100).toFixed(1)13 : '0';14 const clickRate = delivered > 015 ? ((clicked / delivered) * 100).toFixed(1)16 : '0';17 const unsubRate = delivered > 018 ? ((unsubscribed / delivered) * 100).toFixed(2)19 : '0';2021 return {22 id: campaign.id,23 name: campaign.name || 'Unnamed Campaign',24 subject: campaign.subject || 'N/A',25 sent_date: campaign.sentDate26 ? new Date(campaign.sentDate).toLocaleDateString('en-US', {27 year: 'numeric', month: 'short', day: 'numeric'28 })29 : 'N/A',30 delivered,31 opened,32 clicked,33 open_rate: `${openRate}%`,34 click_rate: `${clickRate}%`,35 unsub_rate: `${unsubRate}%`,36 performance: parseFloat(openRate) >= 25 ? 'High'37 : parseFloat(openRate) >= 15 ? 'Medium' : 'Low'38 };39});Pro tip: Brevo's campaign statistics use 'uniqueViews' for unique opens (not 'opens') and 'clickers' for unique clicks (not 'clicks'). The raw counts are in 'viewed' and 'clicks' respectively. Always use the unique metrics for open rate and click rate calculations as they're the industry standard.
Expected result: The campaigns table populates with all sent email campaigns, showing open rates and click rates calculated from Brevo's statistics. The performance column color-codes campaigns as High, Medium, or Low performers.
Trigger transactional emails and SMS from Retool actions
Add action capabilities to your Retool panel so marketing and support teams can trigger transactional communications directly from workflow tools without using Brevo's interface. Create a query named sendTransactionalEmail: - Method: POST - Path: /smtp/email - Body (JSON): Add a Form section to your Retool app with: - A Select component for email template (populated from getEmailTemplates query) - A Text Input for recipient email address - A JSON editor or Text Input for template parameter overrides (e.g., customer name, order details) - A 'Send Email' button that triggers sendTransactionalEmail For email template lookup, create getEmailTemplates: - Method: GET - Path: /smtp/templates - URL parameters: templateStatus=true, limit=50 For SMS, create sendSMS: - Method: POST - Path: /transactionalSMS/sms - Body: { sender, recipient (phone number), content } Add event handlers to both send queries: on success, show a Retool notification ('Email sent successfully') and log the send to your internal database. On failure, show the error message from the API response to help teams debug delivery issues. For complex transactional workflows that trigger communications based on database events — order confirmations, payment failures, support escalations — use Retool Workflows with a Resource Query block for the Brevo API call alongside your database resource, triggered by webhooks from your application.
1// POST body for sendTransactionalEmail query2// Method: POST, Path: /smtp/email3{4 "sender": {5 "name": "{{ textInput_senderName.value || 'Support Team' }}",6 "email": "{{ textInput_senderEmail.value || 'support@yourcompany.com' }}"7 },8 "to": [9 {10 "email": "{{ textInput_recipientEmail.value }}",11 "name": "{{ textInput_recipientName.value || '' }}"12 }13 ],14 "templateId": {{ select_template.value }},15 "params": {16 "FIRSTNAME": "{{ textInput_contactFirstName.value }}",17 "ORDER_ID": "{{ textInput_orderId.value }}",18 "CUSTOM_MESSAGE": "{{ textInput_customMessage.value }}"19 }20}Pro tip: Brevo's transactional email API uses template parameters in the 'params' object. These map to {{ params.PARAMETER_NAME }} placeholders in your Brevo email templates. Always match parameter names exactly as defined in the template — Brevo replaces missing parameters with empty strings rather than throwing an error.
Expected result: The send email form triggers a transactional email using the selected template and parameter values. A success notification confirms the send. The recipient receives the email with the correct template content and parameter substitutions.
Build list management and contact update operations
Add contact management capabilities to your Retool app — updating attributes, managing list memberships, and handling unsubscribes. Create a query named updateContact: - Method: PUT - Path: /contacts/{{ textInput_email.value }} - Body: { "attributes": { "FIRSTNAME": "{{ textInput_firstName.value }}", "LASTNAME": "{{ textInput_lastName.value }}" }, "listIds": [{{ multiSelect_lists.value }}] } Create a query named addContactToList: - Method: POST - Path: /contacts/lists/{{ dropdown_targetList.value }}/contacts/add - Body: { "emails": ["{{ textInput_email.value }}"] } Create a query named removeContactFromList: - Method: POST - Path: /contacts/lists/{{ dropdown_targetList.value }}/contacts/remove - Body: { "emails": ["{{ textInput_email.value }}"] } For unsubscribe management, create getBlacklist: - Method: GET - Path: /contacts - URL parameters: emailBlacklisted=true, limit=100 This returns all globally unsubscribed contacts. Add a Retool Table showing unsubscribed contacts with their unsubscribe date and reason. Include an option to resubscribe contacts (POST to /contacts with emailBlacklisted: false) for cases where contacts request to be re-added — always ensure this complies with your legal requirements and the contact's explicit re-opt-in. For bulk contact import, create addContactsBulk: - Method: POST - Path: /contacts/import - Body: structured JSON with contacts array For complex contact management workflows involving multiple systems — syncing Brevo contacts with your CRM, managing GDPR deletion requests, or automating list transitions based on customer lifecycle stages — RapidDev's team can help build a comprehensive contact operations center in Retool.
1// POST body for addContactsBulk — import multiple contacts at once2// Method: POST, Path: /contacts/import3{4 "fileBody": "EMAIL;FIRSTNAME;LASTNAME;SMS\n{{ bulkContactData.value }}",5 "listIds": [{{ dropdown_importList.value }}],6 "emailBlacklist": false,7 "smsBlacklist": false,8 "updateExistingContacts": true,9 "emptyContactsAttributes": false10}Pro tip: Brevo's bulk contact import uses a CSV-like format in the fileBody field, with semicolons as delimiters and a header row. The first column must always be EMAIL. Test with 2-3 contacts before running a large import to verify the format is correct.
Expected result: The contact update operations work correctly — adding and removing list memberships updates immediately in Brevo. The blacklist view shows all globally unsubscribed contacts with filtering by date range.
Common use cases
Build a contact lookup and communication history panel
Create a Retool app where your CRM or support team can search for any Brevo contact by email, view their full profile including list memberships and custom attributes, see their campaign engagement history (emails sent, opened, clicked), and check their SMS opt-in status. Add buttons to update contact attributes, add them to a list, or send a transactional email directly from the panel.
Build a contact profile panel with an email search input, a contact details section showing name, attributes, and email/SMS consent status, a list of all campaign emails received with open and click indicators, and action buttons to add the contact to a selected list or send a transactional email template.
Copy this prompt to try it in Retool
Email and SMS campaign performance comparison dashboard
Build a Retool dashboard that shows both email campaigns and SMS campaigns side by side, with their respective performance metrics — delivery rate, open rate, click rate for email; delivery rate and response rate for SMS. Add a date filter and Chart component comparing performance trends across both channels over the past quarter.
Create a multi-channel campaign dashboard with separate Table sections for email campaigns and SMS campaigns, each showing delivery, open/click metrics, and a unified Chart that compares email engagement rates vs SMS response rates over time so the marketing team can assess channel effectiveness.
Copy this prompt to try it in Retool
List health and unsubscribe management panel
Build an operational panel that shows all Brevo contact lists with their subscriber counts, recent growth rates, and unsubscribe rates. Provide tools to view all contacts who recently unsubscribed from a specific list, export that list for CRM updates, and bulk-add contacts from a CSV upload. Include a blacklist management view showing all globally blocked email addresses.
Build a list management dashboard that shows all contact lists with subscriber counts and 30-day growth trends, a drilldown view for unsubscribes from a selected list with reason and date, and a bulk contact import tool that takes a CSV of emails and attributes and adds them to a selected list via the Brevo API.
Copy this prompt to try it in Retool
Troubleshooting
API returns 401 Unauthorized on all queries
Cause: The api-key header is missing, incorrectly named, or contains an invalid API key. Brevo's header name is lowercase with a hyphen: 'api-key', not 'API-Key' or 'Authorization'.
Solution: Verify the header name in your Retool resource is exactly 'api-key' (lowercase, with hyphen). Check in Brevo's Settings → SMTP & API → API Keys that the key is still valid and not expired. If using a configuration variable, verify the variable name matches exactly. Test by pasting the raw key directly to confirm the resource configuration before switching to a config variable reference.
Contact lookup returns 404 Not Found for an email that exists in Brevo
Cause: The email address in the URL path must be URL-encoded. Special characters like '+' in email addresses will break the path if not encoded.
Solution: Use encodeURIComponent() around the email value in the path: /contacts/{{ encodeURIComponent(textInput_email.value) }}. This ensures characters like '+', '@', and '.' are properly encoded for the URL path. Verify the email exists in Brevo by searching from the Brevo interface first.
1// Correct path for contact lookup2// Path field value:3/contacts/{{ encodeURIComponent(textInput_email.value.trim().toLowerCase()) }}Transactional email send returns 400 Bad Request
Cause: The request body is missing required fields (sender.name, sender.email, to array, or templateId), or the template ID doesn't exist or is not active in your Brevo account.
Solution: Verify the request body includes all required fields: sender object with name and email, to array with at least one recipient object containing email, and either templateId (for template-based emails) or htmlContent and subject (for custom content). Check that the templateId corresponds to an active template in Brevo's Email → Templates section.
Campaign statistics show zeros even for campaigns sent weeks ago
Cause: The statistics may be in a nested structure that the transformer isn't accessing correctly, or the campaign object returned by the list endpoint includes less detail than the individual campaign endpoint.
Solution: In Retool's query preview, expand the raw response to find where statistics are nested. Brevo's campaign list endpoint returns statistics under campaign.statistics.globalStats. If you need more detailed per-link statistics, fetch individual campaigns using the GET /emailCampaigns/{id} endpoint. Verify that your transformer is accessing the correct path: data.campaigns[0].statistics.globalStats.
Best practices
- Store your Brevo API key as a Secret configuration variable in Retool — use the exact header name 'api-key' (lowercase with hyphen) when configuring the resource, as this is Brevo's required header name.
- Always URL-encode email addresses when using them in API path parameters using encodeURIComponent() to handle emails with special characters like '+' or '%'.
- Use the uniqueViews and clickers fields (not views and clicks) from Brevo's campaign statistics when calculating open and click rates — these represent unique engagement metrics, which are the industry standard.
- Set getAllLists and getEmailTemplates queries to run on page load so dropdown selectors are always populated. Set campaign analytics and contact queries to run on manual trigger.
- Combine Brevo contact data with your customer database in the same Retool app to create unified customer profiles — join on email address to see both Brevo engagement history and purchase or support history.
- Use Retool Workflows for transactional email triggers based on database events rather than triggering emails from Retool apps directly — Workflows provide better error handling, retry logic, and audit logging.
- Always add confirmation prompts before updating emailBlacklisted to false (resubscribing contacts) — resubscribing someone who has unsubscribed without their explicit consent may violate GDPR or CAN-SPAM regulations.
Alternatives
Mailchimp focuses on email marketing for broad audiences and has a native Retool connector, while Brevo combines transactional email, marketing email, and SMS in a single platform at lower cost.
SendGrid has a native connector in Retool and excels at high-volume transactional email delivery, while Brevo provides a more complete marketing suite including SMS and CRM features alongside email.
Twilio is the leading SMS and voice communications platform with a native Retool connector, while Brevo provides SMS as part of a broader marketing platform alongside email campaigns.
Frequently asked questions
Does Brevo (Sendinblue) have a native connector in Retool?
No, Brevo does not have a native connector in Retool. You connect it via a REST API Resource using the 'api-key' header for authentication. Despite the lack of a native connector, all core Brevo features — contacts, lists, email campaigns, SMS campaigns, transactional email, and automation — are accessible through the v3 REST API at api.brevo.com/v3.
Does the free Brevo plan include API access?
Yes, Brevo's free plan includes API access with a limit of 300 emails per day. For Retool dashboards that primarily read data (contacts, campaign analytics, list management) rather than send emails, the free plan API works fine. If your Retool integration needs to send transactional emails, the free plan's daily limit applies. Paid plans start at $25/month and increase sending limits significantly.
What's the difference between querying emailCampaigns and smtp/email in Brevo?
The /emailCampaigns endpoint manages bulk marketing campaigns — newsletters and promotional emails sent to subscriber lists. The /smtp/email endpoint handles transactional emails — individual personalized emails triggered by specific events like order confirmations, password resets, or support responses. In Retool, use /emailCampaigns for marketing reporting dashboards and /smtp/email for action buttons that send individual transactional messages.
Can I send SMS campaigns from Retool using Brevo's API?
Yes. Brevo's API includes both transactional SMS (/transactionalSMS/sms) and SMS campaign management (/smsCampaigns). From Retool, you can send individual transactional SMS messages to specific phone numbers and retrieve analytics for sent SMS campaigns. Ensure recipients' phone numbers include the country code (e.g., +15551234567 for US numbers) and verify that contacts have given SMS opt-in consent before sending.
How do I handle Brevo's rate limits in Retool?
Brevo's API rate limits vary by plan — typically 400 requests per minute on paid plans. For Retool dashboards with multiple queries loading simultaneously, stagger query execution using event handlers rather than running everything on page load. For bulk operations like importing thousands of contacts, use Brevo's bulk import endpoint (/contacts/import) rather than making individual contact create calls. If you hit rate limits, Brevo returns a 429 status code with a Retry-After header.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation