How to trigger Braze campaigns from your database
Send a Braze custom event when something becomes true in PostgreSQL or MySQL, like a declined card or a stalled trial, and let a campaign take it from there.
- PostgreSQL
- MySQL
- Braze
- how-to
- sql
- braze
Lifecycle campaigns start with an event: the card was declined, the trial is three days from ending and the account never activated, the customer hasn’t logged in for two weeks. When those moments only exist in your database, the campaign waits for an engineer to add a tracking call. Rowfire, which is open source, sends the event to Braze from a SQL query instead.
1. The moment, as a query
A trigger is one read-only SELECT on PostgreSQL, MySQL or MariaDB:
SELECT a.id AS account_id,
a.name AS account,
pa.invoice_no,
pa.amount,
pa.attempted_at
FROM payment_attempts pa
JOIN accounts a ON a.id = pa.account_id
WHERE pa.outcome = 'failed'
AND a.is_internal = false
The clock is attempted_at and the key is account_id. A rule decides how
often one account may get the event: once ever, once per day, week or month,
or every nth time. Once per account per week keeps a run of retries from
starting the campaign three times.
2. The Braze action
Connect Braze with a REST API key and your cluster’s base URL (Braze is
regional), then use the track_event action:
| field | value |
|---|---|
User ID (external_id) |
{{ account_id }} |
| Event name | payment_failed |
| Properties | { "invoice_no": "{{ invoice_no }}", "amount": "{{ amount }}" } |
Leave the event time blank and Rowfire uses the trigger’s clock. Each fired
row becomes a request of this shape to /users/track:
{
"events": [
{
"external_id": "5",
"name": "payment_failed",
"time": "2026-10-08T09:14:00+00:00",
"properties": { "invoice_no": "INV-5-LIVE", "amount": "49.00" }
}
]
}
3. The campaign
In Braze, create an action-based campaign or Canvas whose trigger is the
custom event payment_failed. From there it’s Braze’s: the message, the
delays, the exits. Rowfire’s job is to send the event once, at the right
moment, for the right user.
4. Check it before customers see it
A backtest replays the rule over past days and shows how many events it would have sent, with example rows. Shadow mode then renders each request against live data and records it without sending it, so nobody gets a campaign while you’re still checking. Promote the rule when the events look right. A new trigger starts at now, so switching it on doesn’t send an event for every old decline.
Good to know
Triggers are polled, within a minute by default: fine for campaigns and follow-ups, not for messages that must arrive instantly. The same trigger can also tell your team: one rule sends the Braze event, another posts to Slack or opens a Zendesk ticket.
For more, see push when a customer nears their quota, rescue trials that never activated and Rowfire vs reverse ETL.
Questions
Does this need a code change in our app?
No. Rowfire reads your database with a read-only query and sends the custom event to Braze's /users/track endpoint itself. Nothing in your application changes.
Which user does the event go to?
The one whose external_id you map from the row, usually your own customer or account id, for example {{ account_id }}.
Can it also update a profile attribute?
Yes. The Braze integration has a second action, update_attribute, which sets a custom attribute on the user from any column.
Isn't this what reverse ETL does?
Reverse ETL keeps attributes in sync with columns. A custom event says something just happened, once, which is what starts an action-based campaign. Many teams use both.