curl --request POST \
--url https://brew.new/api/v1/automations/triggers/brew-events \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"event": "contact.unsubscribed",
"scope": "domain",
"domainId": "jd7f0c2a8w1x9m4n6p3q5r8s2t"
}
'import requests
url = "https://brew.new/api/v1/automations/triggers/brew-events"
payload = {
"event": "contact.unsubscribed",
"scope": "domain",
"domainId": "jd7f0c2a8w1x9m4n6p3q5r8s2t"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
event: 'contact.unsubscribed',
scope: 'domain',
domainId: 'jd7f0c2a8w1x9m4n6p3q5r8s2t'
})
};
fetch('https://brew.new/api/v1/automations/triggers/brew-events', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://brew.new/api/v1/automations/triggers/brew-events",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'event' => 'contact.unsubscribed',
'scope' => 'domain',
'domainId' => 'jd7f0c2a8w1x9m4n6p3q5r8s2t'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://brew.new/api/v1/automations/triggers/brew-events"
payload := strings.NewReader("{\n \"event\": \"contact.unsubscribed\",\n \"scope\": \"domain\",\n \"domainId\": \"jd7f0c2a8w1x9m4n6p3q5r8s2t\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://brew.new/api/v1/automations/triggers/brew-events")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"event\": \"contact.unsubscribed\",\n \"scope\": \"domain\",\n \"domainId\": \"jd7f0c2a8w1x9m4n6p3q5r8s2t\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://brew.new/api/v1/automations/triggers/brew-events")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"event\": \"contact.unsubscribed\",\n \"scope\": \"domain\",\n \"domainId\": \"jd7f0c2a8w1x9m4n6p3q5r8s2t\"\n}"
response = http.request(request)
puts response.read_bodyGet or create an unsubscribe trigger
Returns the brand’s trigger for one Brew event scope, creating it the first time. Brew events start automations from things that happen inside Brew. The first is contact.unsubscribed: a contact unsubscribed with an email’s unsubscribe link or their mail app’s one-click button (never a bounce, complaint, import or API edit).
Use when an automation should start when a contact unsubscribes, from one marketing domain’s list or from every email the brand sends.
Input { event: "contact.unsubscribed", scope: "domain", domainId } for one marketing domain’s list (ids from listDomains), or { event: "contact.unsubscribed", scope: "all" } for every email. An unsubscribe from all clicked in one of a domain’s emails also starts that domain’s trigger, while the contact was still on its list.
Returns 201 with the new trigger row, or 200 with the existing one (created: false). Brew owns its title and payload, so the row is immutable and never fires over the API. The contact has just opted out, so an automation on this trigger sends only a message they need (such as confirming the unsubscribe) from a transactional domain, or mail from another marketing domain they are still on; publish refuses a flow none of whose emails could reach them.
Errors 400 INVALID_REQUEST when domainId is missing for scope: "domain" or sent for scope: "all"; 404 DOMAIN_NOT_FOUND for an unknown or cross-brand domain; 422 DOMAIN_PURPOSE_NOT_ALLOWED for a transactional domain, which owns no list; 409 TRIGGER_LIMIT_REACHED when the brand already holds the maximum number of triggers.
See also createAutomation, fireTrigger, listDomains.
curl --request POST \
--url https://brew.new/api/v1/automations/triggers/brew-events \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"event": "contact.unsubscribed",
"scope": "domain",
"domainId": "jd7f0c2a8w1x9m4n6p3q5r8s2t"
}
'import requests
url = "https://brew.new/api/v1/automations/triggers/brew-events"
payload = {
"event": "contact.unsubscribed",
"scope": "domain",
"domainId": "jd7f0c2a8w1x9m4n6p3q5r8s2t"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
event: 'contact.unsubscribed',
scope: 'domain',
domainId: 'jd7f0c2a8w1x9m4n6p3q5r8s2t'
})
};
fetch('https://brew.new/api/v1/automations/triggers/brew-events', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://brew.new/api/v1/automations/triggers/brew-events",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'event' => 'contact.unsubscribed',
'scope' => 'domain',
'domainId' => 'jd7f0c2a8w1x9m4n6p3q5r8s2t'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://brew.new/api/v1/automations/triggers/brew-events"
payload := strings.NewReader("{\n \"event\": \"contact.unsubscribed\",\n \"scope\": \"domain\",\n \"domainId\": \"jd7f0c2a8w1x9m4n6p3q5r8s2t\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://brew.new/api/v1/automations/triggers/brew-events")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"event\": \"contact.unsubscribed\",\n \"scope\": \"domain\",\n \"domainId\": \"jd7f0c2a8w1x9m4n6p3q5r8s2t\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://brew.new/api/v1/automations/triggers/brew-events")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"event\": \"contact.unsubscribed\",\n \"scope\": \"domain\",\n \"domainId\": \"jd7f0c2a8w1x9m4n6p3q5r8s2t\"\n}"
response = http.request(request)
puts response.read_bodyAuthorizations
Send your Brew API key as Authorization: Bearer brew_xxx.
Headers
Optional idempotency key for safe retries. Reusing the same key with the same request body returns the original response for 24 hours.
1 - 100The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise 400 BRAND_ID_REQUIRED — there is no default brand); list ids with GET /v1/brands. Brand-scoped credentials may omit it, and sending a different brand returns 403 BRAND_SCOPE_MISMATCH. A brand outside your organization returns 404 BRAND_NOT_FOUND.
1 - 64Body
The Brew event. contact.unsubscribed: a contact unsubscribed with an email unsubscribe link or their mail app’s unsubscribe button.
contact.unsubscribed domain: unsubscribes from one marketing sending domain (pass domainId). all: unsubscribes from every email the brand sends.
domain, all The marketing domain (from GET /v1/domains) whose unsubscribe list this trigger watches. Required when scope is domain; omit for all.
1Response
The trigger already existed for this scope.
1 - 2561 - 120brew_api, clerk, stripe, shopify, stytch, supabase, workos, framer, revenuecat, custom, brew_event Show child attributes
Show child attributes
True when this call created the trigger; false when it already existed.
2000Show child attributes
Show child attributes
Was this page helpful?