> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.solvimon.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.solvimon.com/_mcp/server.

# 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.

| Field                                            | Required                  | Description                                                                                                                                                                                  |
| ------------------------------------------------ | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `workflow_id`                                    | Yes                       | The workflow this action belongs to.                                                                                                                                                         |
| `type`                                           | Yes                       | `SEND_EMAIL_TO_CUSTOMER`, `EXPORT_TO_ERP` or `SEND_WEBHOOK`.                                                                                                                                 |
| `status`                                         | Yes                       | `DRAFT`, `INACTIVE`, `ACTIVE` or `ARCHIVED`.                                                                                                                                                 |
| `send_email_to_customer.integration_id`          | Yes                       | The Mailgun or SendGrid integration to send through.                                                                                                                                         |
| `send_email_to_customer.template_name`           | Yes                       | Template on the provider used to render the email.                                                                                                                                           |
| `send_email_to_customer.variant`                 | Yes                       | `INVOICE`, `PAYMENT` or `PRICING_PLAN_SUBSCRIPTION`. Must match the workflow's type.                                                                                                         |
| `send_email_to_customer.from`                    | Yes                       | Sender `name` and `email`.                                                                                                                                                                   |
| `send_email_to_customer.reply_to`                | Yes                       | Reply-to `name` and `email`.                                                                                                                                                                 |
| `send_email_to_customer.subject`                 | No                        | Subject line override. Cannot be combined with `use_template_subject`.                                                                                                                       |
| `send_email_to_customer.use_template_subject`    | No                        | Send 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](#subject-lines). |
| `send_email_to_customer.cc_recipients`           | No                        | Extra CC addresses.                                                                                                                                                                          |
| `send_email_to_customer.bcc_recipients`          | No                        | Extra BCC addresses.                                                                                                                                                                         |
| `send_email_to_customer.localize_template_names` | No                        | Append the end customer's locale to the template name at send time. See [Localized email templates](#localized-email-templates).                                                             |
| `send_email_to_customer.tags`                    | No                        | Up to 3 tags passed to Mailgun as `o:tag`. See [Tagging outgoing email](#tagging-outgoing-email).                                                                                            |
| `export_to_erp.executor`                         | Yes (for `EXPORT_TO_ERP`) | Which integration performs the export. `THIRD_PARTY` is the available value. See [Export to an ERP](#export-to-an-erp).                                                                      |
| `send_webhook.webhook_id`                        | Yes (for `SEND_WEBHOOK`)  | The registered [webhook](/platform-guides/for-developers/webhooks) 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`**

```bash 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`**

```json 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`**

```bash 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](#localized-email-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`**

```json {5} 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](/platform-guides/workflows/workflow-triggers) 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`**

```json {6} 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](/platform-guides/workflows/monitoring-and-audit) 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`**

```bash 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](/platform-guides/for-developers/webhooks), referenced by `webhook_id` in the action's `send_webhook` block:

**`Attach a send-webhook action`**

```bash 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](/platform-guides/meter-and-event-design/usage-limits), 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}](https://docs.solvimon.com/api-docs/configuration-api/workflow-actions/patch-workflow-actions-by-resource-id), not through dedicated transition endpoints:

**`Activate an action`**

```bash title="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`**

```bash title="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](/platform-guides/invoicing/payment-collections) and the [Adyen payment acceptor](/integrations/paymentserviceproviders/adyen#configure-the-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.

## Related guides

* Email providers: [Mailgun](/integrations/email-providers/mailgun), [SendGrid](/integrations/email-providers/sendgrid)
* [Workflow triggers](/platform-guides/workflows/workflow-triggers)

## API reference

* [List workflow actions](https://docs.solvimon.com/api-docs/configuration-api/workflow-actions/get-workflow-actions)
* [Create a workflow action](https://docs.solvimon.com/api-docs/configuration-api/workflow-actions/post-workflow-actions)
* [Get a workflow action](https://docs.solvimon.com/api-docs/configuration-api/workflow-actions/get-workflow-actions-by-resource-id)
* [Update a workflow action](https://docs.solvimon.com/api-docs/configuration-api/workflow-actions/patch-workflow-actions-by-resource-id)
* [Delete a workflow action](https://docs.solvimon.com/api-docs/configuration-api/workflow-actions/delete-workflow-actions-by-resource-id)