Marketing & SalesDocumentedScanned

brevo

Brevo (formerly Sendinblue) email marketing API for managing contacts, lists, sending transactional emails.

Share:

Installation

npx clawhub@latest install brevo

View the full skill documentation and source below.

Documentation

Brevo Email Marketing API

Manage contacts, send emails, and automate marketing via Brevo's REST API.

Authentication

BREVO_KEY=$(cat ~/.config/brevo/api_key)

All requests require header: api-key: $BREVO_KEY

Base URL

Common Endpoints

Contacts

ActionMethodEndpoint
Create contactPOST/contacts
Get contactGET/contacts/{email}
Update contactPUT/contacts/{email}
Delete contactDELETE/contacts/{email}
List contactsGET/contacts?limit=50&offset=0
Get blacklistedGET/contacts?emailBlacklisted=true

Lists

ActionMethodEndpoint
Get all listsGET/contacts/lists
Create listPOST/contacts/lists
Get list contactsGET/contacts/lists/{listId}/contacts
Add to listPOST/contacts/lists/{listId}/contacts/add
Remove from listPOST/contacts/lists/{listId}/contacts/remove

Emails

ActionMethodEndpoint
Send transactionalPOST/smtp/email
Send campaignPOST/emailCampaigns
Get templatesGET/smtp/templates

Examples

Create/Update Contact

curl -X POST "" \
  -H "api-key: $BREVO_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "listIds": [10],
    "updateEnabled": true,
    "attributes": {
      "NOMBRE": "John",
      "APELLIDOS": "Doe"
    }
  }'

Get Contact Info

curl "" \
  -H "api-key: $BREVO_KEY"

Update Contact Attributes

curl -X PUT "" \
  -H "api-key: $BREVO_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "listIds": [10, 15],
    "attributes": {
      "CUSTOM_FIELD": "value"
    }
  }'

Send Transactional Email

curl -X POST "" \
  -H "api-key: $BREVO_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sender": {"name": "My App", "email": "noreply@example.com"},
    "to": [{"email": "user@example.com", "name": "John"}],
    "subject": "Welcome!",
    "htmlContent": "<p>Hello {{params.name}}</p>",
    "params": {"name": "John"}
  }'

Send with Template

curl -X POST "" \
  -H "api-key: $BREVO_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": [{"email": "user@example.com"}],
    "templateId": 34,
    "params": {
      "NOMBRE": "John",
      "FECHA": "2026-02-01"
    }
  }'

List All Contact Lists

curl "" \
  -H "api-key: $BREVO_KEY"

Add Contacts to List (Bulk)

curl -X POST "" \
  -H "api-key: $BREVO_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "emails": ["user1@example.com", "user2@example.com"]
  }'

Safe Import Pattern

When importing contacts, always respect unsubscribes:

import requests

BREVO_KEY = "your-api-key"
HEADERS = {'api-key': BREVO_KEY, 'Content-Type': 'application/json'}
BASE = ''

def get_blacklisted():
    """Get all unsubscribed/blacklisted emails"""
    blacklisted = set()
    offset = 0
    while True:
        r = requests.get(
            f'{BASE}/contacts?limit=100&offset={offset}&emailBlacklisted=true',
            headers=HEADERS
        )
        contacts = r.json().get('contacts', [])
        if not contacts:
            break
        for c in contacts:
            blacklisted.add(c['email'].lower())
        offset += 100
    return blacklisted

def safe_import(emails, list_id):
    """Import contacts respecting unsubscribes"""
    blacklisted = get_blacklisted()
    
    for email in emails:
        if email.lower() in blacklisted:
            print(f"Skipped (unsubscribed): {email}")
            continue
        
        r = requests.post(f'{BASE}/contacts', headers=HEADERS, json={
            'email': email,
            'listIds': [list_id],
            'updateEnabled': True
        })
        
        if r.status_code in [200, 201, 204]:
            print(f"Imported: {email}")
        else:
            print(f"Error: {email} - {r.text[:50]}")

Contact Attributes

Brevo uses custom attributes for contact data:

{
  "attributes": {
    "NOMBRE": "John",
    "APELLIDOS": "Doe",
    "FECHA_ALTA": "2026-01-15",
    "PLAN": "premium",
    "CUSTOM_FIELD": "any value"
  }
}

Create attributes in Brevo dashboard: Contacts → Settings → Contact attributes.

Response Codes

CodeMeaning
200Success (GET)
201Created (POST)
204Success, no content (PUT/DELETE)
400Bad request (check payload)
401Invalid API key
404Contact/resource not found

Best Practices

  • Always check blacklist before importing contacts

  • Use updateEnabled: true to update existing contacts instead of failing

  • Use templates for consistent transactional emails

  • Batch operations when adding many contacts to lists

  • Store list IDs in config, not hardcoded

  • Log imports for audit trail
  • Automations

    Brevo automations trigger on:

    • Contact added to list

    • Contact attribute updated

    • Email opened/clicked

    • Custom events via API


    Trigger automation manually:
    curl -X POST "" \
      -H "api-key: $BREVO_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "listIds": [10],
        "emailBlacklist": false,
        "updateExistingContacts": true,
        "emptyContactsAttributes": false,
        "jsonBody": [
          {"email": "user@example.com", "attributes": {"NOMBRE": "John"}}
        ]
      }'

    Useful Queries

    # Count contacts in list
    curl "" -H "api-key: $BREVO_KEY" | jq '.totalSubscribers'
    
    # Get recent contacts
    curl "" -H "api-key: $BREVO_KEY"
    
    # Check if email exists
    curl "" -H "api-key: $BREVO_KEY"
    
    # Get account info
    curl "" -H "api-key: $BREVO_KEY"