curl --request POST \
--url https://brew.new/api/v1/automations/triggers/{triggerEventId}/fire \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"payload": {
"email": "jane@example.com",
"firstName": "Jane"
}
}
'import requests
url = "https://brew.new/api/v1/automations/triggers/{triggerEventId}/fire"
payload = { "payload": {
"email": "jane@example.com",
"firstName": "Jane"
} }
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({payload: {email: 'jane@example.com', firstName: 'Jane'}})
};
fetch('https://brew.new/api/v1/automations/triggers/{triggerEventId}/fire', 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/{triggerEventId}/fire",
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([
'payload' => [
'email' => 'jane@example.com',
'firstName' => 'Jane'
]
]),
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/{triggerEventId}/fire"
payload := strings.NewReader("{\n \"payload\": {\n \"email\": \"jane@example.com\",\n \"firstName\": \"Jane\"\n }\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/{triggerEventId}/fire")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"payload\": {\n \"email\": \"jane@example.com\",\n \"firstName\": \"Jane\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://brew.new/api/v1/automations/triggers/{triggerEventId}/fire")
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 \"payload\": {\n \"email\": \"jane@example.com\",\n \"firstName\": \"Jane\"\n }\n}"
response = http.request(request)
puts response.read_body{
"triggerInstanceId": "tin_4fZ2kQ9pLm7xR1tV8wYcD",
"triggerEventId": "user_signed_up",
"status": "replayed",
"automationRunIds": [
"jh7acthhe99pq4448xh83gn54x8eennb"
],
"publishedAutomations": [
{
"automationId": "M3nRk8LqW2xT5vBp9YcZd",
"name": "Welcome flow"
}
],
"counts": {
"automations": 1,
"skipped": 0
},
"warnings": [],
"receivedAt": "2026-04-08T12:34:56.789Z"
}Fire a trigger
Fires the trigger: validates the payload against the stored contract, upserts the contact it describes, then starts one run per published automation attached to the trigger.
Use when an event in your product should start every published automation attached to this trigger.
Input { payload }, validated against the trigger’s payloadSchema. Unknown fields are accepted and reported in warnings[]. The contact derived from the payload is upserted before the fan-out with the declared top-level scalar fields the fire sent; object and array fields stay template data, and a contract fallbackValue is never written onto the contact. A value the contact field’s type refuses is left out and reported as a FIELD_TYPE_MISMATCH warning (field, expectedType, actualType); the rest of the contact is written and the runs still start.
Returns 202 { triggerInstanceId, triggerEventId, status, automationRunIds[], notStarted[], publishedAutomations[], counts, warnings[], receivedAt }. Follow a run with getAutomationRun, the fire itself with getTriggerInstance. notStarted[] names each automation whose run failed to start and why, so a triggered fire with no runs explains itself. counts.skipped is the recipients a suppression already covered, so automations: 2, skipped: 2 means nothing was delivered.
Idempotency send a stable Idempotency-Key header on every retry. A repeat answers 200 with status: "replayed" and the ORIGINAL run ids; nothing fires twice.
Errors 400 INVALID_PAYLOAD when the payload does not satisfy the schema, or when email (or user.email) is not one plain address such as jane@example.com: a display name (Jane <jane@example.com>), a list or a line break is refused with details.errors[].code: "invalid_email", and no contact is written; 404 TRIGGER_EVENT_NOT_FOUND for an unknown or cross-brand id; 422 NO_PUBLISHED_AUTOMATION when nothing published listens for the trigger; 409 IDEMPOTENCY_CONFLICT when a key is reused with a different body.
See also checkTriggerReady, getTriggerInstance, listAutomationRuns.
curl --request POST \
--url https://brew.new/api/v1/automations/triggers/{triggerEventId}/fire \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"payload": {
"email": "jane@example.com",
"firstName": "Jane"
}
}
'import requests
url = "https://brew.new/api/v1/automations/triggers/{triggerEventId}/fire"
payload = { "payload": {
"email": "jane@example.com",
"firstName": "Jane"
} }
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({payload: {email: 'jane@example.com', firstName: 'Jane'}})
};
fetch('https://brew.new/api/v1/automations/triggers/{triggerEventId}/fire', 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/{triggerEventId}/fire",
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([
'payload' => [
'email' => 'jane@example.com',
'firstName' => 'Jane'
]
]),
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/{triggerEventId}/fire"
payload := strings.NewReader("{\n \"payload\": {\n \"email\": \"jane@example.com\",\n \"firstName\": \"Jane\"\n }\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/{triggerEventId}/fire")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"payload\": {\n \"email\": \"jane@example.com\",\n \"firstName\": \"Jane\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://brew.new/api/v1/automations/triggers/{triggerEventId}/fire")
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 \"payload\": {\n \"email\": \"jane@example.com\",\n \"firstName\": \"Jane\"\n }\n}"
response = http.request(request)
puts response.read_body{
"triggerInstanceId": "tin_4fZ2kQ9pLm7xR1tV8wYcD",
"triggerEventId": "user_signed_up",
"status": "replayed",
"automationRunIds": [
"jh7acthhe99pq4448xh83gn54x8eennb"
],
"publishedAutomations": [
{
"automationId": "M3nRk8LqW2xT5vBp9YcZd",
"name": "Welcome flow"
}
],
"counts": {
"automations": 1,
"skipped": 0
},
"warnings": [],
"receivedAt": "2026-04-08T12:34:56.789Z"
}Authorizations
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 - 64Path Parameters
Trigger id returned by POST /v1/automations/triggers. Custom triggers use tri_… ids; integration triggers use composite ids (e.g. clerk:org_…:brand_…:user.created, URL-encode the colons).
1 - 256"user_signed_up"
Body
Event payload — fields and types must match the trigger's payloadSchema. Unknown fields are accepted but reported as unexpected_key warnings.
Show child attributes
Show child attributes
Response
Idempotent replay: this Idempotency-Key already fired. The ids are the original run’s.
The persisted inbound row — GET /v1/automations/trigger-instances/{triggerInstanceId} for its match state.
1 - 256triggered = this call accepted and matched the event; automationRunIds lists the runs it started and notStarted any it could not. replayed = the same Idempotency-Key already fired; nothing ran twice.
triggered, replayed The runs this fire started — GET /v1/automations/runs/{automationRunId}.
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Matched automations whose run failed to start, each with the reason; one skipped on purpose (paused past its window, a suppressed contact) is not listed. A fire can answer triggered with no runs; this says why.
Show child attributes
Show child attributes
Was this page helpful?