Onboarding with events
Send moments from your product (a signup, a first project, a trial ending) to Kula as events, and flows turn them into emails.
This guide builds a trial onboarding: a welcome email at signup, a nudge two days later for users who have not created a project, and a reminder before the trial ends.
You need: a verified domain and an API key with sending access from Settings › API keys. It is enough to send events, and safer to store in your app.
Send an event when a user signs up
Call POST /v1/events from your backend when a user signs up. If the address is not yet a contact, Kula creates it with the name and attributes you send.
curl https://api.kulamail.com/v1/events \
-H "Authorization: Bearer $KULA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "ada@example.com",
"name": "signed_up",
"properties": { "plan": "trial" },
"contact": {
"firstName": "Ada",
"attributes": { "plan": "trial", "trial_ends_at": "2026-11-01T00:00:00Z" }
}
}'
await fetch('https://api.kulamail.com/v1/events', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.KULA_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: user.email,
name: 'signed_up',
properties: { plan: 'trial' },
contact: {
firstName: user.firstName,
attributes: { plan: 'trial', trial_ends_at: user.trialEndsAt.toISOString() }
}
})
})
Event names use letters, digits and _ . : -, up to 100 characters: signed_up, project_created, trial_ended. Events API.
Send the other moments
Send an event for each moment worth reacting to:
await kulaEvent(user.email, 'project_created', { projectId: project.id })
Each event is stored on the contact, so you can use it in segments and flow conditions: "has done project_created within 7 days".
Build the onboarding flow
Open Flows › New flow:
- Starts when: A contact performs an event, event name
signed_up. - Add email: the welcome email. Use the values you sent:
{{ contact.first_name | default: "there" }},{{ contact.plan }}. - Add delay: 2 days.
- Add condition: Continue only if Event
project_createdhas not done. - Add email: "Create your first project in 2 minutes", with a direct link.
Users who created a project exit at step 4. Flows.
Remind users before the trial ends
Create a second flow triggered by a trial_ending event, sent by your app three days before the end, with one email that explains what happens next.
Sending the event at the right moment stays correct if the trial date changes, unlike a long wait in a flow.
Test and activate
Send an event with your own address, check the emails with Send a test, then click Activate on each flow. Only events received after activation start a run.
Connect Stripe and other services
Kula has no built-in Stripe integration: forward the events you need from your webhook handler.
app.post('/stripe/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
const event = stripe.webhooks.constructEvent(req.body, req.headers['stripe-signature'], endpointSecret)
if (event.type === 'invoice.paid') {
const invoice = event.data.object
await fetch('https://api.kulamail.com/v1/events', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.KULA_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: invoice.customer_email,
name: 'invoice_paid',
properties: { amount: invoice.amount_paid / 100, currency: invoice.currency },
contact: { attributes: { plan: 'pro' } }
})
})
}
res.sendStatus(200)
})
A flow on invoice_paid with Re-entry set to Every time the trigger fires can thank customers after each payment. The plan attribute updated on the way lets you leave paying customers out of your trial reminders with a segment.
The same pattern works for any tool that sends webhooks: your auth provider, your billing tool, your CRM.
Good to know
- Events with
createContact: falseare ignored for unknown addresses (the API answers 404): use it when only existing contacts should be tracked. - Pass
occurredAtto record an event that happened earlier, for example when backfilling history. - Flow emails are marketing emails: they carry an unsubscribe link and respect your reputation rules. Password resets and receipts belong in transactional emails.