Workflow Notification Emails Send internal workflow notifications to your configured notification address. api.sendEmail() sends an internal workflow notification to the notification address configured in Settings. It is intended for operational alerts: notifying you or your team when a workflow reaches a specific state, needs attention, completes with a useful summary, or encounters a condition worth flagging. This API is not a general email-sending feature. It always sends to the single notification email address in Settings and is designed for internal workflow notifications, not customer or external messaging. Requirements - To send emails successfully, a notification email address should be set in Settings. - The shop must be on a paid plan (Starter or above). - Each plan includes a sending quota that resets at the start of each billing cycle. | Plan | Quota | | Free | Not available | | Starter | 500 emails / billing cycle | | Growth | 2,000 emails / billing cycle | | Business | 5,000 emails / billing cycle | | Enterprise | 10,000 emails / billing cycle | Signature await api.sendEmail({ subject, text, html }); | Option | Type | Required | Description | | subject | string | yes | Email subject line | | text | string | no | Plain-text body | | html | string | no | HTML body | At least one of text or html must be provided. If both are given, email clients that support HTML will show the HTML version; others fall back to plain text. No per-message routing fields are supported. Do not pass to, cc, bcc, replyTo, or custom sender fields to api.sendEmail(). Returns Promise<{ sent: boolean, reason?: string }>. | Result | When | | { sent: true } | Email was sent successfully | | { sent: false, reason } | Email was skipped (free plan, quota reached, no notification email set). The workflow continues normally. | An exception is thrown only when the platform itself is unable to send the email due to an internal configuration or delivery error. The to address is always the notification email from Settings. It cannot be changed per-call. Common use cases The strongest uses for api.sendEmail() are internal operational notifications such as: - alert me when something needs attention - send me a completion summary - notify me when a workflow failed or skipped important records These are the kinds of notifications this API is designed for: a workflow can notify your team, but it cannot email arbitrary recipients. api.sendEmail() is available in both regular workflow steps and in the onWorkflowComplete and onWorkflowError lifecycle hooks. Sending an alert from onWorkflowError is a common pattern: it fires regardless of which step failed. Example: alert when something needs attention export class Workflow { async start(data, headers, api) { if (data.refundamount > 500) { await api.scheduleNextStep({ delay: 10, action: 'flagForReview', payload: { orderId: data.orderid, amount: data.refund_amount }, }); } } async flagForReview(data, headers, api) { await api.sendEmail({ subject: High-value refund flagged: order ${data.orderId}, text: A refund of $${data.amount} was requested for order ${data.orderId} and requires review., }); } } Example: send a completion summary async sendSummary(data, headers, api) { await api.sendEmail({ subject: Inventory sync complete: ${data.updatedCount} items updated, text: Sync finished. Updated: ${data.updatedCount}. Skipped: ${data.skippedCount}. Errors: ${data.errorCount}., html:

Inventory sync complete

Updated${data.updatedCount}
Skipped${data.skippedCount}
Errors${data.errorCount}
, }); } Example: send a completion summary from run state If earlier steps collect totals or summary data in api.runStore, you can read that data in onWorkflowComplete(api) and send a single completion email after the entire run finishes. export class Workflow { async start(data, headers, api) { for (const row of data.rows) { await api.scheduleNextStep({ delay: 10, action: 'processRow', payload: { row }, }); } } async processRow(data, headers, api) { if (data.row.status === 'updated') { await api.runStore.increment('updatedCount'); } else if (data.row.status === 'skipped') { await api.runStore.increment('skippedCount'); } else if (data.row.status === 'error') { await api.runStore.increment('errorCount'); } } async onWorkflowComplete(api) { const updatedCount = (await api.runStore.get('updatedCount')) ?? 0; const skippedCount = (await api.runStore.get('skippedCount')) ?? 0; const errorCount = (await api.runStore.get('errorCount')) ?? 0; await api.sendEmail({ subject: 'Inventory sync complete', text: Updated: ${updatedCount}. Skipped: ${skippedCount}. Errors: ${errorCount}., }); } } Example: notify when records were skipped async notifySkippedRows(data, headers, api) { if (!data.skippedCount) return; await api.sendEmail({ subject: Inventory sync skipped ${data.skippedCount} records, text: The workflow skipped ${data.skippedCount} records and may need review., }); } Checking the result api.sendEmail() returns { sent: false, reason } rather than throwing when the email cannot be sent due to a predictable condition. This keeps the workflow running. Check the result if you need to react or log: async notifyTeam(data, headers, api) { const result = await api.sendEmail({ subject: 'Order flagged for review', text: Order ${data.orderId} has been flagged., }); if (!result.sent) { console.log('Email skipped:', result.reason); } } Conditions that return { sent: false } (workflow continues): - No notification email set. Configure one in Settings. - Free plan. Upgrade to a paid plan to use this feature. - Quota reached. The sending limit for your plan has been exhausted. It resets at the start of your next billing cycle. Conditions that throw (workflow fails): - The platform email service is not configured. - The email delivery service returns an error. Usage and quota Current email usage for your billing cycle is visible in Settings under the notification email field. The quota resets at the start of each billing cycle, not on the calendar month. Upgrading your plan starts a fresh quota window immediately. Note: api.sendEmail() always delivers to the single notification address in Settings. It cannot be used to email customers or any external address.