Create a key
Create a project-scoped key in the dashboard. Use Mail send for outbound email.
Get Started
Use one endpoint for transactional mail and one endpoint for event-driven automation. Keep the key in env, send JSON, and you are live.
Quick Path
Create a project-scoped key in the dashboard. Use Mail send for outbound email.
Keep the secret outside source code. Use environment variables in your app and deployment.
Send JSON to /v1/send for mail or /v1/events when you want flows to react.
Mail Send
Use a Mail send key with POST https://relay.mlib.app/v1/send.
curl -X POST https://relay.mlib.app/v1/send \
-H "Authorization: Bearer YOUR_MAIL_SEND_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "you@example.com",
"subject": "AutoRelay test",
"html": "<p>Hello from AutoRelay.</p>",
"idempotency_key": "app-send-001"
}'
const response = await fetch("https://relay.mlib.app/v1/send", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.AUTORELAY_MAIL_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
to: "you@example.com",
subject: "AutoRelay test",
html: "<p>Hello from AutoRelay.</p>",
idempotency_key: `app-${Date.now()}`
})
});
const data = await response.json();
console.log(data);
Required fields
to for the recipient addresssubject for the message subjecthtml for the rendered bodyidempotency_key to prevent duplicate sendsAutomation
Use an Events key with POST https://relay.mlib.app/v1/events.
curl -X POST https://relay.mlib.app/v1/events \
-H "Authorization: Bearer YOUR_EVENTS_KEY" \
-H "Content-Type: application/json" \
-d '{
"event_name": "user_signed_up",
"user_id": "user_123",
"properties": {
"email": "you@example.com"
}
}'
const response = await fetch("https://relay.mlib.app/v1/events", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.AUTORELAY_EVENTS_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
event_name: "user_signed_up",
user_id: "user_123",
properties: {
email: "you@example.com"
}
})
});
const data = await response.json();
console.log(data);
Typical event payload
event_name names the triggeruser_id identifies the actor or customerproperties carries flow context like email or planFlow Studio
Trigger on sign-up, wait, and send follow-up mail without wiring cron jobs into your app.
React to product events, branch on context, and keep operational messaging close to the source event.
Read the guides mini blog for more Flow Studio patterns, sender setup, and signup funnel recipes.
Flow API
Create a flow with an Events key.
curl -X POST https://relay.mlib.app/v1/flows \
-H "Authorization: Bearer YOUR_EVENTS_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Welcome Flow",
"status": "active",
"trigger_kind": "event",
"trigger_value": "user_signed_up",
"audience_filter": "",
"steps": [
{
"id": "step_send_welcome",
"type": "send_email",
"label": "Welcome message",
"config": {
"mode": "inline",
"subject": "Welcome",
"html": "<p>Thanks for joining.</p>"
}
}
]
}'
curl -X GET https://relay.mlib.app/v1/flows \
-H "Authorization: Bearer YOUR_EVENTS_KEY"
Execution model
/v1/flows./v1/events.API Responses
POST /v1/flows response
{
"id": "flow_uuid",
"project_id": "proj_123",
"name": "Welcome Flow",
"status": "active",
"version": 1,
"updated_at": "2026-03-22T23:32:43.780282+00:00",
"definition": {
"entry": {
"kind": "event",
"value": "user_signed_up",
"audience_filter": null
},
"steps": [
{
"id": "step_send_welcome",
"type": "send_email",
"label": "Welcome message",
"config": {
"mode": "inline",
"subject": "Welcome",
"html": "<p>Thanks for joining.</p>"
}
}
]
}
}
POST /v1/events response
{
"event_id": "event_uuid",
"status": "accepted",
"flow_result": {
"matchedFlows": 1,
"sentMessages": 1,
"scheduledWaits": 0,
"emittedSignals": 0
}
}
The event response confirms flow execution counts. It does not report the sender address used for the email.
Test Recipe
Use POST /v1/flows with an Events key and set status to active.
Send a matching event_name to /v1/events with an email in properties.email.
Expect matchedFlows >= 1 and sentMessages >= 1 in the response.
Sending Domain
Use a project sender domain when you want mail to come from your own brand.
mail.example.com.Save Domain.Refresh.DNS guidance
mail.example.com, many DNS providers want a host like token._domainkey.mail instead of the full hostname.DNS only.Flow Sender
Default behavior
/v1/events response. Check the project sender settings or the delivered message headers when testing.Normalization note
audience_filter as an empty string when creating a flow.null. That is expected behavior.Branded Sender Test
Recommended test pattern
mail.northstar.example.noreply@mail.northstar.example.matchedFlows and sentMessages in the API response.Why both checks matter
Notes
Use one key for direct delivery and another for events when you want cleaner access control.
Send a stable idempotency_key when a retry might happen.
Begin with one project, one mail key, one test event, then expand flows after the first successful run.
Troubleshooting
Event accepted but no flow matched
active.trigger_value matches the exact event_name.Events key.Flow matched but no email sent
properties.email is present.Mail sent from the wrong sender
/v1/events response.