Contacts & lists
The examples use the BREVO_API_KEY and BREVO_BASE variables from the
quickstart.
Contacts
curl -s -X POST "$BREVO_BASE/contacts" -H "api-key: $BREVO_API_KEY" \
-H "content-type: application/json" -d '{
"email": "jane@example.com",
"attributes": { "FIRSTNAME": "Jane", "LASTNAME": "Martin" },
"listIds": [3],
"updateEnabled": true
}'
POST /contactscreates a contact (201 {"id": 12}). It needs at leastemail,ext_idor theSMSattribute, otherwise400 missing_parameter. If the email orext_idis already known:400 duplicate_parameter, unless"updateEnabled": true(update,204). An unknown list inlistIdsorunlinkListIdsreturns404 document_not_found.GET/PUT/DELETE /contacts/{identifier}: the identifier is detected automatically (email, numeric id, phone, otherwiseext_id) or forced with?identifierType=email_id|contact_id|ext_id|phone_id|whatsapp_id|landline_number_id. A digits-only value is read as a contact id: for a phone number, passidentifierType=phone_idor the+prefix. Unknown contact:404 document_not_found.PUTandDELETEreturn204.GET /contacts:limit(default 50, max 1000) /offset,sort(descby default, on creation date),modifiedSince,createdSince,listIds,ids, andfilter:equals(FIRSTNAME,"Jane"),lessThan(AGE,30),greaterThan(AGE,30). OnEMAIL,SMSandEXT_ID, onlyequalsis applied. Response{"contacts": [...], "count": 42}.POST /contacts/batch: up to 100 updates in one request ({"contacts": [...]}, above that400 out_of_range). Each item is matched byid,email,ext_idorsms;attributes.EMAILchanges its address. Returns204.
Adding a contact back to a list it had unsubscribed from resubscribes it.
Attributes
GET /contacts/attributes lists the built-in attributes (FIRSTNAME, LASTNAME, SMS,
WHATSAPP, LANDLINE_NUMBER) and yours. Create one with
POST /contacts/attributes/{category}/{name} (category normal, category,
transactional, calculated or global), update or delete it on the same path with
PUT / DELETE. A category attribute requires enumeration
([{"value": 1, "label": "Gold"}]).
Values are converted to their type, as Brevo does:
| Type | Stored as |
|---|---|
float |
number ("31,5" → 31.5) |
boolean |
boolean (true/false, 1/0 accepted) |
date |
YYYY-MM-DD |
category |
the enumeration label (numeric value or label accepted) |
multiple-choice |
array of strings (array or comma-separated list) |
text |
text |
A value that does not match the type returns 400 invalid_parameter. A null value clears
the attribute.
Lists and folders
A list always belongs to a folder (POST /contacts/folders {name} then
POST /contacts/lists {name, folderId}, each returns 201 {"id"}). Deleting a folder
deletes its lists. GET /contacts/folders and GET /contacts/lists are paginated (limit
default 10, max 50); GET /contacts/lists/{id}/contacts accepts limit up to 500 and
modifiedSince.
POST /contacts/lists/{id}/contacts/add (and /remove) accepts emails, ids or extIds
(150 max, above that 400 out_of_range) and returns 201 with per-contact detail:
{ "contacts": { "success": ["jane@example.com"], "failure": ["unknown@example.com"], "total": 2 } }
/remove also accepts {"all": true} to empty the list; the response then carries a
processId.
Import & export
POST /contacts/import:jsonBody([{"email", "attributes"}]),fileBody(CSV with;or,, first line = attribute names,EMAILcolumn) orfileUrl;listIdsornewList({"listName", "folderId"}). Options:updateExistingContacts(defaulttrue),emptyContactsAttributes(an empty cell clears the attribute),emailBlacklist,smsBlacklist,notifyUrl. Returns202 {"processId"}; follow it withGET /processes/{id}(invalid addresses and duplicates ininfo.import.invalid_emailsandinfo.import.duplicate_email_id, comma-separated).POST /contacts/export:customContactFilteris required, withactionForContacts(allContactsby default,subscribed,unsubscribed,unsubscribedPerList) andlistId(required forunsubscribedPerList);exportAttributespicks the columns,notifyUrlreceives the result. Returns202 {"processId"}. The completed process exposesexport_url, a signed link to the CSV (;separator, columnsCONTACT_ID,EMAIL, then the attributes).
Double opt-in
POST /contacts/doubleOptinConfirmation expects email, includeListIds, templateId and
redirectionUrl (http or https), plus optional excludeListIds and attributes. It
sends template templateId with a confirmation link ({{ doubleoptin }} variable, valid
30 days; if the template lacks it, the link is appended to the message). Returns 201, or
204 if the contact already exists. The contact is created (or updated), added to
includeListIds and removed from excludeListIds only on click, then redirected to
redirectionUrl.