Overview Install Files SecuritySummary This source did not publish a separate summary. Review SKILL.md before using the skill.
Brevo
Access the Brevo API with managed OAuth authentication. Send transactional emails, manage contacts and lists, create email campaigns, and work with templates.
Quick Start
# Get account info
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/brevo/v3/account')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Base URL
https://gateway.maton.ai/brevo/v3/{resource}
The gateway proxies requests to api.brevo.com and automatically injects your OAuth token.
Authentication
All requests require the Maton API key in the Authorization header:
Authorization: Bearer $MATON_API_KEY
Environment Variable: Set your API key as MATON_API_KEY:
export MATON_API_KEY="YOUR_API_KEY"
Getting Your API Key
Sign in or create an account at maton.ai
Go to maton.ai/settings
Copy your API key
Connection Management
Manage your Brevo OAuth connections at https://ctrl.maton.ai.
List Connections
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections?app=brevo&status=ACTIVE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Create Connection
python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'brevo'}).encode()
req = urllib.request.Request('https://ctrl.maton.ai/connections', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Get Connection python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
{
"connection": {
"connection_id": "b04dd695-d056-433b-baf9-0fb4eb3bde9e",
"status": "ACTIVE",
"creation_time": "2026-02-09T19:51:00.932629Z",
"last_updated_time": "2026-02-09T19:51:30.123456Z",
"url": "https://connect.maton.ai/?session_token=...",
"app": "brevo",
"metadata": {}
}
}
Open the returned url in a browser to complete OAuth authorization.
Delete Connection python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}', method='DELETE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Specifying Connection If you have multiple Brevo connections, specify which one to use with the Maton-Connection header:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/brevo/v3/account')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', 'b04dd695-d056-433b-baf9-0fb4eb3bde9e')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
If omitted, the gateway uses the default (oldest) active connection.
API Reference
Account
Get Account Info {
"email": "[email protected] ",
"firstName": "John",
"lastName": "Doe",
"companyName": "Acme Inc",
"relay": {
"enabled": true,
"data": {
"userName": "[email protected] ",
"relay": "smtp-relay.brevo.com",
"port": 587
}
}
}
Contacts
List Contacts
limit - Number of results per page (default: 50, max: 500)
offset - Index of first result (0-based)
modifiedSince - Filter by modification date (ISO 8601)
{
"contacts": [
{
"id": 1,
"email": "[email protected] ",
"emailBlacklisted": false,
"smsBlacklisted": false,
"createdAt": "2026-02-09T20:33:59.705+01:00",
"modifiedAt": "2026-02-09T20:35:19.529+01:00",
"listIds": [2],
"attributes": {
"FIRSTNAME": "John",
"LASTNAME": "Doe"
}
}
],
"count": 1
}
Get Contact GET /brevo/v3/contacts/{identifier}
The identifier can be email address, phone number, or contact ID.
identifierType - Type of identifier: email_id, phone_id, contact_id, ext_id
Create Contact POST /brevo/v3/contacts
Content-Type: application/json
{
"email": "[email protected] ",
"attributes": {
"FIRSTNAME": "Jane",
"LASTNAME": "Smith"
},
"listIds": [2],
"updateEnabled": false
}
Set updateEnabled: true to update the contact if it already exists.
Update Contact PUT /brevo/v3/contacts/{identifier}
Content-Type: application/json
{
"attributes": {
"FIRSTNAME": "Updated",
"LASTNAME": "Name"
}
}
Returns 204 No Content on success.
Delete Contact DELETE /brevo/v3/contacts/{identifier}
Returns 204 No Content on success.
Get Contact Campaign Stats GET /brevo/v3/contacts/{identifier}/campaignStats
Lists
List All Lists GET /brevo/v3/contacts/lists
{
"lists": [
{
"id": 2,
"name": "Newsletter Subscribers",
"folderId": 1,
"uniqueSubscribers": 150,
"totalBlacklisted": 2,
"totalSubscribers": 148
}
],
"count": 1
}
Get List GET /brevo/v3/contacts/lists/{listId}
Create List POST /brevo/v3/contacts/lists
Content-Type: application/json
{
"name": "New List",
"folderId": 1
}
Update List PUT /brevo/v3/contacts/lists/{listId}
Content-Type: application/json
{
"name": "Updated List Name"
}
Returns 204 No Content on success.
Delete List DELETE /brevo/v3/contacts/lists/{listId}
Returns 204 No Content on success.
Get Contacts in List GET /brevo/v3/contacts/lists/{listId}/contacts
Add Contacts to List
Remove Contacts from List POST /brevo/v3/contacts/lists/{listId}/contacts/remove
Content-Type: application/json
{
"emails": ["[email protected] "]
}
Folders
List Folders GET /brevo/v3/contacts/folders
{
"folders": [
{
"id": 1,
"name": "Marketing",
"uniqueSubscribers": 500,
"totalSubscribers": 480,
"totalBlacklisted": 20
}
],
"count": 1
}
Get Folder GET /brevo/v3/contacts/folders/{folderId}
Create Folder POST /brevo/v3/contacts/folders
Content-Type: application/json
{
"name": "New Folder"
}
Update Folder PUT /brevo/v3/contacts/folders/{folderId}
Content-Type: application/json
{
"name": "Renamed Folder"
}
Returns 204 No Content on success.
Delete Folder DELETE /brevo/v3/contacts/folders/{folderId}
Deletes folder and all lists within it. Returns 204 No Content on success.
Get Lists in Folder GET /brevo/v3/contacts/folders/{folderId}/lists
Attributes
List Attributes GET /brevo/v3/contacts/attributes
{
"attributes": [
{
"name": "FIRSTNAME",
"category": "normal",
"type": "text"
},
{
"name": "LASTNAME",
"category": "normal",
"type": "text"
}
]
}
Create Attribute POST /brevo/v3/contacts/attributes/{category}/{attributeName}
Content-Type: application/json
{
"type": "text"
}
Categories: normal, transactional, category, calculated, global
Update Attribute PUT /brevo/v3/contacts/attributes/{category}/{attributeName}
Content-Type: application/json
{
"value": "new value"
}
Delete Attribute DELETE /brevo/v3/contacts/attributes/{category}/{attributeName}
Transactional Emails
Send Email POST /brevo/v3/smtp/email
Content-Type: application/json
{
"sender": {
"name": "John Doe",
"email": "[email protected] "
},
"to": [
{
"email": "[email protected] ",
"name": "Jane Smith"
}
],
"subject": "Welcome!",
"htmlContent": "<html><body><h1>Hello!</h1><p>Welcome to our service.</p></body></html>"
}
cc - Carbon copy recipients
bcc - Blind carbon copy recipients
replyTo - Reply-to address
textContent - Plain text version
templateId - Use a template instead of htmlContent
params - Template parameters
attachment - File attachments
headers - Custom headers
tags - Email tags for tracking
scheduledAt - Schedule for later (ISO 8601)
Get Transactional Emails GET /brevo/v3/smtp/emails
email - Filter by recipient email
templateId - Filter by template
messageId - Filter by message ID
startDate - Start date (YYYY-MM-DD)
endDate - End date (YYYY-MM-DD)
limit - Results per page
offset - Starting index
Delete Scheduled Email DELETE /brevo/v3/smtp/email/{identifier}
The identifier can be a messageId or batchId.
Get Email Statistics GET /brevo/v3/smtp/statistics/events
limit - Results per page
offset - Starting index
startDate - Start date
endDate - End date
email - Filter by recipient
event - Filter by event type: delivered, opened, clicked, bounced, etc.
Email Templates
List Templates GET /brevo/v3/smtp/templates
{
"count": 1,
"templates": [
{
"id": 1,
"name": "Welcome Email",
"subject": "Welcome {{params.name}}!",
"isActive": true,
"sender": {
"name": "Company",
"email": "[email protected] "
},
"htmlContent": "<html>...</html>",
"createdAt": "2026-02-09 23:29:38",
"modifiedAt": "2026-02-09 23:29:38"
}
]
}
Get Template GET /brevo/v3/smtp/templates/{templateId}
Create Template POST /brevo/v3/smtp/templates
Content-Type: application/json
{
"sender": {
"name": "Company",
"email": "[email protected] "
},
"templateName": "Welcome Email",
"subject": "Welcome {{params.name}}!",
"htmlContent": "<html><body><h1>Hello {{params.name}}!</h1></body></html>"
}
Update Template PUT /brevo/v3/smtp/templates/{templateId}
Content-Type: application/json
{
"templateName": "Updated Template Name",
"subject": "New Subject"
}
Returns 204 No Content on success.
Delete Template DELETE /brevo/v3/smtp/templates/{templateId}
Returns 204 No Content on success.
Send Test Email POST /brevo/v3/smtp/templates/{templateId}/sendTest
Content-Type: application/json
{
"emailTo": ["[email protected] "]
}
Email Campaigns
List Campaigns GET /brevo/v3/emailCampaigns
type - Filter by type: classic, trigger
status - Filter by status: draft, sent, archive, queued, suspended, in_process
limit - Results per page
offset - Starting index
{
"count": 1,
"campaigns": [
{
"id": 2,
"name": "Monthly Newsletter",
"subject": "Our March Update",
"type": "classic",
"status": "draft",
"sender": {
"name": "Company",
"email": "[email protected] "
},
"createdAt": "2026-02-09T23:29:39.000Z"
}
]
}
Get Campaign GET /brevo/v3/emailCampaigns/{campaignId}
Create Campaign POST /brevo/v3/emailCampaigns
Content-Type: application/json
{
"name": "March Newsletter",
"subject": "Our March Update",
"sender": {
"name": "Company",
"email": "[email protected] "
},
"htmlContent": "<html><body><h1>March News</h1></body></html>",
"recipients": {
"listIds": [2]
}
}
Update Campaign PUT /brevo/v3/emailCampaigns/{campaignId}
Content-Type: application/json
{
"name": "Updated Campaign Name",
"subject": "Updated Subject"
}
Returns 204 No Content on success.
Delete Campaign DELETE /brevo/v3/emailCampaigns/{campaignId}
Returns 204 No Content on success.
Send Campaign Now POST /brevo/v3/emailCampaigns/{campaignId}/sendNow
Send Test Email POST /brevo/v3/emailCampaigns/{campaignId}/sendTest
Content-Type: application/json
{
"emailTo": ["[email protected] "]
}
Update Campaign Status PUT /brevo/v3/emailCampaigns/{campaignId}/status
Content-Type: application/json
{
"status": "suspended"
}
Senders
List Senders {
"senders": [
{
"id": 1,
"name": "Company",
"email": "[email protected] ",
"active": true,
"ips": []
}
]
}
Get Sender GET /brevo/v3/senders/{senderId}
Create Sender POST /brevo/v3/senders
Content-Type: application/json
{
"name": "Marketing",
"email": "[email protected] "
}
Update Sender PUT /brevo/v3/senders/{senderId}
Content-Type: application/json
{
"name": "Updated Name"
}
Delete Sender DELETE /brevo/v3/senders/{senderId}
Blocked Contacts
List Blocked Contacts GET /brevo/v3/smtp/blockedContacts
Unblock Contact DELETE /brevo/v3/smtp/blockedContacts/{email}
Blocked Domains
List Blocked Domains GET /brevo/v3/smtp/blockedDomains
Add Blocked Domain POST /brevo/v3/smtp/blockedDomains
Content-Type: application/json
{
"domain": "spam-domain.com"
}
Remove Blocked Domain DELETE /brevo/v3/smtp/blockedDomains/{domain}
Pagination Brevo uses offset-based pagination:
GET /brevo/v3/contacts?limit=50&offset=0
limit - Number of results per page (varies by endpoint, typically max 500)
offset - Starting index (0-based)
{
"contacts": [...],
"count": 150
}
To get the next page, increment offset by limit:
Page 1: offset=0&limit=50
Page 2: offset=50&limit=50
Page 3: offset=100&limit=50
Code Examples
JavaScript const response = await fetch(
'https://gateway.maton.ai/brevo/v3/contacts',
{
headers: {
'Authorization': `Bearer ${process.env.MATON_API_KEY}`
}
}
);
const data = await response.json();
console.log(data.contacts);
Python import os
import requests
response = requests.get(
'https://gateway.maton.ai/brevo/v3/contacts',
headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'}
)
data = response.json()
print(data['contacts'])
Python (Send Email) import os
import requests
response = requests.post(
'https://gateway.maton.ai/brevo/v3/smtp/email',
headers={
'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}',
'Content-Type': 'application/json'
},
json={
'sender': {'name': 'John', 'email': '[email protected] '},
'to': [{'email': '[email protected] ', 'name': 'Jane'}],
'subject': 'Hello!',
'htmlContent': '<html><body><h1>Hi Jane!</h1></body></html>'
}
)
result = response.json()
print(f"Sent! Message ID: {result['messageId']}")
Python (Create Contact and Add to List) import os
import requests
headers = {
'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}',
'Content-Type': 'application/json'
}
# Create contact
response = requests.post(
'https://gateway.maton.ai/brevo/v3/contacts',
headers=headers,
json={
'email': '[email protected] ',
'attributes': {'FIRSTNAME': 'New', 'LASTNAME': 'User'},
'listIds': [2]
}
)
contact = response.json()
print(f"Created contact ID: {contact['id']}")
Notes
All endpoints require the /v3/ prefix in the path
Attribute names must be in UPPERCASE
Contact identifiers can be email, phone, or ID
Sender email addresses must be verified in Brevo
Template parameters use {{params.name}} syntax
PUT and DELETE operations return 204 No Content on success
Rate limits: 300 calls/minute on free plans, higher on paid plans
IMPORTANT: When piping curl output to jq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environments
Error Handling Status Meaning 400 Missing Brevo connection or bad request 401 Invalid or missing Maton API key 404 Resource not found 429 Rate limited 4xx/5xx Passthrough error from Brevo API
Rate limit headers in response:
x-sib-ratelimit-limit - Request limit
x-sib-ratelimit-remaining - Remaining requests
x-sib-ratelimit-reset - Reset time
Troubleshooting: Invalid API Key When you receive an "Invalid API key" error, ALWAYS follow these steps before concluding there is an issue:
Check that the MATON_API_KEY environment variable is set:
Verify the API key is valid by listing connections:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Resources