Introduction
# Brevo Email Marketing API
Manage contacts, send emails, and automate marketing via Brevo's REST API.
## Authentication
```bash BREVO_KEY=$(cat ~/.config/brevo/api_key) ```
All requests require header: `api-key: $BREVO_KEY`
## Base URL
``` https://api.brevo.com/v3 ```
## Common Endpoints
### Contacts
| Action | Method | Endpoint | |--------|--------|----------| | Create contact | POST | `/contacts` | | Get contact | GET | `/contacts/{email}` | | Update contact | PUT | `/contacts/{email}` | | Delete contact | DELETE | `/contacts/{email}` | | List contacts | GET | `/contacts?limit=50&offset=0` | | Get blacklisted | GET | `/contacts?emailBlacklisted=true` |
### Lists
| Action | Method | Endpoint | |--------|--------|----------| | Get all lists | GET | `/contacts/lists` | | Create list | POST | `/contacts/lists` | | Get list contacts | GET | `/contacts/lists/{listId}/contacts` | | Add to list | POST | `/contacts/lists/{listId}/contacts/add` | | Remove from list | POST | `/contacts/lists/{listId}/contacts/remove` |
### Emails
| Action | Method | Endpoint | |--------|--------|----------| | Send transactional | POST | `/smtp/email` | | Send campaign | POST | `/emailCampaigns` | | Get templates | GET | `/smtp/templates` |
## Examples
### Create/Update Contact
```bash curl -X POST "https://api.brevo.com/v3/contacts" \ -H "api-key: $BREVO_KEY" \ -H "Content-Type: application/json" \ -d '{ "email": "[email protected]", "listIds": [10], "updateEnabled": true, "attributes": { "NOMBRE": "John", "APELLIDOS": "Doe" } }' ```
### Get Contact Info
```bash curl "https://api.brevo.com/v3/contacts/[email protected]" \ -H "api-key: $BREVO_KEY" ```
### Update Contact Attributes
```bash curl -X PUT "https://api.brevo.com/v3/contacts/[email protected]" \ -H "api-key: $BREVO_KEY" \ -H "Content-Type: application/json" \ -d '{ "listIds": [10, 15], "attributes": { "CUSTOM_FIELD": "value" } }' ```
### Send Transactional Email
```bash curl -X POST "https://api.brevo.com/v3/smtp/email" \ -H "api-key: $BREVO_KEY" \ -H "Content-Type: application/json" \ -d '{ "sender": {"name": "My App", "email": "[email protected]"}, "to": [{"email": "[email protected]", "name": "John"}], "subject": "Welcome!", "htmlContent": "<p>Hello {{params.name}}</p>", "params": {"name": "John"} }' ```
### Send with Template
```bash curl -X POST "https://api.brevo.com/v3/smtp/email" \ -H "api-key: $BREVO_KEY" \ -H "Content-Type: application/json" \ -d '{ "to": [{"email": "[email protected]"}], "templateId": 34, "params": { "NOMBRE": "John", "FECHA": "2026-02-01" } }' ```
### List All Contact Lists
```bash curl "https://api.brevo.com/v3/contacts/lists?limit=50" \ -H "api-key: $BREVO_KEY" ```
### Add Contacts to List (Bulk)
```bash curl -X POST "https://api.brevo.com/v3/contacts/lists/10/contacts/add" \ -H "api-key: $BREVO_KEY" \ -H "Content-Type: application/json" \ -d '{ "emails": ["[email protected]", "[email protected]"] }' ```
## Safe Import Pattern
When importing contacts, **always respect unsubscribes**:
```python import requests
BREVO_KEY = "your-api-key" HEADERS = {'api-key': BREVO_KEY, 'Content-Type': 'application/json'} BASE = 'https://api.brevo.com/v3'
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:
```json { "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
| Code | Meaning | |------|---------| | 200 | Success (GET) | | 201 | Created (POST) | | 204 | Success, no content (PUT/DELETE) | | 400 | Bad request (check payload) | | 401 | Invalid API key | | 404 | Contact/resource not found |
## Best Practices
1. **Always check blacklist** before importing contacts 2. **Use `updateEnabled: true`** to update existing contacts instead of failing 3. **Use templates** for consistent transactional emails 4. **Batch operations** when adding many contacts to lists 5. **Store list IDs** in config, not hardcoded 6. **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: ```bash curl -X POST "https://api.brevo.com/v3/contacts/import" \ -H "api-key: $BREVO_KEY" \ -H "Content-Type: application/json" \ -d '{ "listIds": [10], "emailBlacklist": false, "updateExistingContacts": true, "emptyContactsAttributes": false, "jsonBody": [ {"email": "[email protected]", "attributes": {"NOMBRE": "John"}} ] }' ```
## Useful Queries
```bash # Count contacts in list curl "https://api.brevo.com/v3/contacts/lists/10" -H "api-key: $BREVO_KEY" | jq '.totalSubscribers'
# Get recent contacts curl "https://api.brevo.com/v3/contacts?limit=10&sort=desc" -H "api-key: $BREVO_KEY"
# Check if email exists curl "https://api.brevo.com/v3/contacts/[email protected]" -H "api-key: $BREVO_KEY"
# Get account info curl "https://api.brevo.com/v3/account" -H "api-key: $BREVO_KEY" ```