Workflow actions

A workflow action defines what Solvimon does when a workflow fires. There are two action types: send a templated email to the customer, or deliver the trigger payload to one of your webhooks.


How it works

Actions belong to a workflow through workflow_id, and carry their own status. A workflow can hold several actions, and each one is activated independently, so you can add an action to a live workflow without it sending anything until you activate it.

The email itself is rendered and delivered by an email provider integration, so an action always references an integration_id and a template_name that exists on that provider.

FieldRequiredDescription
workflow_idYesThe workflow this action belongs to.
typeYesSEND_EMAIL_TO_CUSTOMER or SEND_WEBHOOK.
statusYesDRAFT, INACTIVE, ACTIVE or ARCHIVED.
send_email_to_customer.integration_idYesThe Mailgun or SendGrid integration to send through.
send_email_to_customer.template_nameYesTemplate on the provider used to render the email.
send_email_to_customer.variantYesINVOICE, PAYMENT or PRICING_PLAN_SUBSCRIPTION. Must match the workflow’s type.
send_email_to_customer.fromYesSender name and email.
send_email_to_customer.reply_toNoReply-to name and email.
send_email_to_customer.subjectNoSubject line override. Cannot be combined with use_template_subject.
send_email_to_customer.use_template_subjectNoSend no subject override, so the provider uses the subject of the template it renders. Defaults to true when no subject is set. See Subject lines.
send_email_to_customer.cc_recipientsNoExtra CC addresses.
send_email_to_customer.bcc_recipientsNoExtra BCC addresses.
send_email_to_customer.localize_template_namesNoAppend the end customer’s locale to the template name at send time. See Localized email templates.
send_webhook.webhook_idYes (for SEND_WEBHOOK)The registered webhook to deliver the trigger payload to.

Implementation

Invoice emails

Invoice actions carry an invoice block whose type must match the workflow’s invoice variant. include_pdf and include_payment_link apply to TO_FINAL and OVERDUE only:

Attach an invoice delivery action
$curl -X POST https://test.api.solvimon.com/v1/workflow-actions \
> -H "X-API-KEY: <apiKey>" \
> -H "Content-Type: application/json" \
> -d '{
> "workflow_id": "wf_7KcQm1RtbXeUvL2NpHZ4S",
> "type": "SEND_EMAIL_TO_CUSTOMER",
> "status": "DRAFT",
> "description": "Send the final invoice with PDF and pay link",
> "send_email_to_customer": {
> "integration_id": "intg_9PvTa4XcnRbEwK1MjQZ6L",
> "template_name": "invoice-final",
> "variant": "INVOICE",
> "subject": "Your invoice is ready",
> "from": { "name": "Acme Billing", "email": "billing@acme.com" },
> "reply_to": { "name": "Acme Support", "email": "support@acme.com" },
> "invoice": {
> "type": "TO_FINAL",
> "include_pdf": true,
> "include_payment_link": true,
> "include_customer_contacts_as_cc": true
> }
> }
> }'
Response
1{
2 "object_type": "WORKFLOW_ACTION",
3 "id": "wfa_2HbNq8YtvRcXeM5KpLZ3D",
4 "workflow_id": "wf_7KcQm1RtbXeUvL2NpHZ4S",
5 "type": "SEND_EMAIL_TO_CUSTOMER",
6 "status": "DRAFT",
7 "description": "Send the final invoice with PDF and pay link",
8 "send_email_to_customer": {
9 "integration_id": "intg_9PvTa4XcnRbEwK1MjQZ6L",
10 "template_name": "invoice-final",
11 "variant": "INVOICE",
12 "subject": "Your invoice is ready",
13 "from": { "name": "Acme Billing", "email": "billing@acme.com" },
14 "reply_to": { "name": "Acme Support", "email": "support@acme.com" },
15 "invoice": {
16 "type": "TO_FINAL",
17 "include_pdf": true,
18 "include_payment_link": true,
19 "include_customer_contacts_as_cc": true
20 }
21 },
22 "created_at": "2026-07-31T09:16:41Z"
23}

include_customer_contacts_as_cc adds the contacts configured on the customer as CC recipients. It defaults to false, so the email goes only to the customer’s billing address unless you set it.

Payment and subscription emails

Payment and subscription actions take no per-type options beyond the CC behaviour. Set the variant and the matching configuration block:

Attach a failed payment action
$curl -X POST https://test.api.solvimon.com/v1/workflow-actions \
> -H "X-API-KEY: <apiKey>" \
> -H "Content-Type: application/json" \
> -d '{
> "workflow_id": "wf_4TnRb7YqvXcJeP2MkLZ8W",
> "type": "SEND_EMAIL_TO_CUSTOMER",
> "status": "DRAFT",
> "send_email_to_customer": {
> "integration_id": "intg_9PvTa4XcnRbEwK1MjQZ6L",
> "template_name": "payment-failed",
> "variant": "PAYMENT",
> "from": { "name": "Acme Billing", "email": "billing@acme.com" },
> "payment": {
> "include_customer_contacts_as_cc": false
> }
> }
> }'

Subscription actions use variant: "PRICING_PLAN_SUBSCRIPTION" and a pricing_plan_subscription block with the same single option.

Subject lines

The subject of a workflow email comes from one of two places, and the two are mutually exclusive. This matters most for localized templates: an action with no subject of its own used to fall back to a hard-coded English subject, which left the body localized and the subject not, so a translated email could never actually be finished.

use_template_subject sends no subject override at all, which leaves the subject to the template the provider renders. This is what a localized template needs: the subject arrives in the same language as the body, out of the same template. It defaults to true, so an action that sets no subject takes the template’s.

subject is the alternative: a fixed string used for every recipient, whatever language their template is in. Setting both explicitly is rejected with a validation error pointing at use_template_subject, so an action that currently carries a subject has to have it cleared to adopt the template’s.

Use the subject from the template
1{
2 "send_email_to_customer": {
3 "integration_id": "intg_AbD3DqausjOYiMNDZY11F",
4 "template_name": "credit.invoice",
5 "use_template_subject": true,
6 "localize_template_names": true,
7 "variant": "INVOICE",
8 "from": { "name": "Acme Billing", "email": "billing@acme.com" }
9 }
10}

Threading

Every workflow email carries an X-Entity-Ref-ID header that is unique to that send, derived from the action and the trigger that produced it. Mail clients that group by this header, Gmail in particular, would otherwise fold a customer’s successive invoices and reminders into a single conversation, hiding the newest message behind the older ones. Each email arrives as its own thread instead. There is nothing to configure.

Localized email templates

Set localize_template_names to true on a send-email action to send each customer the template in their own language. At send time the action appends the end customer’s locale to the template name (for example credit.invoice becomes credit.invoice_en-us) and looks that template up with your email provider. When no localized variant exists, the action falls back to the base template, so a missing translation degrades to the default language instead of failing the send.

This matches the behaviour of the legacy Paragon email integration, so platforms sending invoice emails in their customers’ languages can migrate to native workflows without losing localization. In Desk, the toggle sits in the send-email action settings.

Send a webhook

A SEND_WEBHOOK action delivers the workflow’s trigger payload to one of your registered webhooks, referenced by webhook_id in the action’s send_webhook block:

Attach a send-webhook action
$curl -X POST https://test.api.solvimon.com/v1/workflow-actions \
> -H "X-API-KEY: <apiKey>" \
> -H "Content-Type: application/json" \
> -d '{
> "workflow_id": "wf_7KcQm1RtbXeUvL2NpHZ4S",
> "type": "SEND_WEBHOOK",
> "status": "DRAFT",
> "description": "Notify the platform when a usage threshold is crossed",
> "send_webhook": {
> "webhook_id": "wh_3QeWzT0mLk2Rp6Yvh9fGb"
> }
> }'

Combined with a usage-limit workflow, this produces usage.threshold_reached notifications carrying the customer, the metric, the threshold that was crossed, the resolved limit and the consumption, so your platform can react to usage events in real time.

Activate an action

Actions move between statuses through PATCH /v1/workflow-actions/{id}, not through dedicated transition endpoints:

Activate an action
$curl -X PATCH https://test.api.solvimon.com/v1/workflow-actions/wfa_2HbNq8YtvRcXeM5KpLZ3D \
> -H "X-API-KEY: <apiKey>" \
> -H "Content-Type: application/json" \
> -d '{ "status": "ACTIVE" }'

Deleting removes the action outright, which is the right move for one that was never activated:

Delete an action
$curl -X DELETE https://test.api.solvimon.com/v1/workflow-actions/wfa_2HbNq8YtvRcXeM5KpLZ3D \
> -H "X-API-KEY: <apiKey>"

Via Desk

Actions live on the workflow’s detail page under Actions. The template picker lists the templates available on the selected email integration, so configure the integration before adding the action.

Edge cases

  • The action variant and the workflow type must agree. A PAYMENT action on an invoice workflow is rejected.
  • include_payment_link requires a working payment setup. See Payment collections and the Adyen payment acceptor.
  • A missing template on the provider fails at send time, not at configuration time. The workflow still records a trigger; the failure shows up in the executions table in Desk.
  • If you use localize_template_names, make sure a localized template exists for every locale your customers use, or accept that those customers get the base template. The fallback is silent, so a missing translation shows up as a wrong-language email, not an error.

API reference