Skip to navigation

Workflow actions

A workflow action defines what Solvimon does when a workflow fires: send a templated email to the customer, export the invoice to an ERP, 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, EXPORT_TO_ERP 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_toYesReply-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, so set it to false when you set subject. 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_email_to_customer.tagsNoUp to 3 tags passed to Mailgun as o:tag. See Tagging outgoing email.
export_to_erp.executorYes (for EXPORT_TO_ERP)Which integration performs the export. THIRD_PARTY is the available value. See Export to an ERP.
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",
"use_template_subject": false,
"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
{
"object_type": "WORKFLOW_ACTION",
"id": "wfa_2HbNq8YtvRcXeM5KpLZ3D",
"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",
"use_template_subject": false,
"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
}
},
"created_at": "2026-07-31T09:16:41Z"
}

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" },
"reply_to": { "name": "Acme Support", "email": "support@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
{
"send_email_to_customer": {
"integration_id": "intg_AbD3DqausjOYiMNDZY11F",
"template_name": "credit.invoice",
"use_template_subject": true,
"localize_template_names": true,
"variant": "INVOICE",
"from": { "name": "Acme Billing", "email": "billing@acme.com" }
}
}

Template variables

The send-email action passes invoice_type, open_amount, customer_name, customer_type, credit_note and original_invoice_number to the template, alongside the variables it already sent. Templates written against the legacy Paragon-based Mailgun integration relied on these; a template migrated to native workflows renders them correctly without being rewritten.

For a wallet_balance trigger, the action also passes wallet_balance and wallet_balance_threshold as rendered figures, and credit_unit_name as the unit label: a credit type name for a wallet denominated in credits, or the currency code for one denominated in an amount. The wallet_balance trigger itself reports the balance as a structured credits/amount object; these template variables stay flat regardless of which unit the wallet uses.

Tagging outgoing email

tags carries up to 3 tags on a send-email action, each at most 128 ASCII characters. They are sent to Mailgun as o:tag, which is what its dashboard filters and reports on. A dunning reminder and a final invoice can then be told apart in delivery statistics, without inspecting subject lines.

Tag a reminder so it can be reported on separately
{
"send_email_to_customer": {
"integration_id": "intg_9PvTa4XcnRbEwK1MjQZ6L",
"template_name": "invoice-overdue",
"variant": "INVOICE",
"tags": ["dunning", "overdue-reminder"],
"from": { "name": "Acme Billing", "email": "billing@acme.com" }
}
}

Tags are per action, so different workflows can tag their mail differently. They only apply to a Mailgun account you connected yourself. A Solvimon-managed email integration tags its own traffic, and rejects the field with not allowed for Solvimon-managed email integrations. The legacy Paragon-based Mailgun integration exposed the same capability, so a workflow migrated from it can keep the tags its reporting was built on.

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.

Export to an ERP

An EXPORT_TO_ERP action exports the invoice that triggered the workflow to the ERP connected to your platform. The export itself is not new. Running it as a workflow action is, and that puts it in the same place as the rest of your automation. It is triggered by the same conditions, retried the same way, and recorded in the execution log with a row per attempt. Previously it happened outside the workflow engine, where nothing reported on it.

Export an invoice to the ERP when it goes final
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": "EXPORT_TO_ERP",
"status": "DRAFT",
"description": "Push the final invoice to the ERP",
"export_to_erp": {
"executor": "THIRD_PARTY"
}
}'

executor selects which integration performs the export. THIRD_PARTY runs it through the connected third-party ERP integration, and is the value to use.

In Desk the action is added from the workflow’s detail page like any other. The panel lists the ERP integrations connected to your platform.

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"
}
}'

With a usage-limit workflow, this action sends USAGE_LIMIT.THRESHOLD_REACHED notifications. Each notification contains the customer, the metric, the crossed threshold, the resolved limit and the consumption. Your platform can thus 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.
  • An EXPORT_TO_ERP action needs an ERP integration on the platform. Without one there is nothing for the executor to run, and the failure surfaces on the execution rather than when you save the action.
  • 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