> ## Documentation Index
> Fetch the complete documentation index at: https://docs.anyformat.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Slack alert

> Posts a message to a Slack channel when a document reaches it, with extracted values and rule verdicts filled in. Free.

**Slack alert** posts a message to a Slack channel for every document that reaches it. The message is a template: you write the text once, and placeholders fill in with the document's extracted values and its [Validate](/guides/nodes/validate) verdicts. It lives in the **Alerts** section of the Studio palette and is in **Beta**.

It is a terminal node. Put it at the end of a branch, usually the **true** branch of an [If/Else](/guides/nodes/if-else), so it fires only on the documents you want to hear about.

It needs the Slack connector. Connect your workspace once per organization: [Slack integration](/integrations/slack).

## The node

<CodeGroup>
  ```json API theme={null}
  {
    "id": "slack_1",
    "type": "slack_alert",
    "channel_id": "C0123ABC",
    "channel_name": "#finance",
    "message_template": "Invoice from ${field.vendor_name}: ${field.total} ${field.currency}. Totals check: ${validation.totals-add-up.status}",
    "severity": "warning"
  }
  ```

  ```python Python theme={null}
  import os
  from anyformat.sdk import Client
  from anyformat.workflow import (
      WorkflowDefinition, Edge,
      ParseNode, ExtractNode, ExtractionSchema, Schema,
      ValidateNode, ValidationRule, ArithmeticCheck,
  )
  from anyformat.workflow.nodes import SlackAlertNode

  client = Client(api_key=os.environ["ANYFORMAT_API_KEY"])

  workflow = client.create_workflow(WorkflowDefinition(
      name="Invoices to Slack",
      nodes=[
          ParseNode(id="parse_1", type="parse"),
          ExtractNode(id="extract_1", type="extract", extraction_schema=ExtractionSchema(fields=[
              Schema.string("vendor_name", "Vendor name."),
              Schema.float("subtotal", "Subtotal before tax."),
              Schema.float("tax", "Tax amount."),
              Schema.float("total", "Grand total."),
              Schema.string("currency", "ISO currency code."),
          ])),
          ValidateNode(id="validate_1", type="validate", rules=[
              ValidationRule(id="totals-add-up", kind="deterministic",
                  check=ArithmeticCheck(type="arithmetic", operands=["subtotal", "tax"], equals="total", tolerance=0.01)),
          ]),
          SlackAlertNode(id="slack_1", type="slack_alert", channel_id="C0123ABC", channel_name="#finance",
              message_template="Invoice from ${field.vendor_name}: ${field.total} ${field.currency}. "
                               "Totals check: ${validation.totals-add-up.status}",
              severity="warning"),
      ],
      edges=[
          Edge(source="parse_1", target="extract_1"),
          Edge(source="extract_1", target="validate_1"),
          Edge(source="validate_1", target="slack_1"),
      ],
  ))
  ```

  ```typescript TypeScript theme={null}
  // The TypeScript builder has no slackAlert() method yet.
  // Send the API JSON on this page to POST /v3/workflows/, or pass the same
  // graph to af.updateWorkflow(workflowId, definition) on an existing workflow.
  ```
</CodeGroup>

The Python builder (`client.workflow(...).parse().extract(...)`) has no `slack_alert()` verb. Build a `WorkflowDefinition` from the node classes instead, as above, and pass it to `create_workflow`. The TypeScript builder has no method either; send the JSON.

`channel_id` is the Slack channel id (`C…`), which is stable across renames. Get it from the Studio channel picker, or from Slack: open the channel details, and the id is at the bottom. `channel_name` is the display name shown in the app and in logs; it is not re-resolved on every send.

## In Studio

Click the Slack alert node on the canvas to open its panel. It has a **Slack Channel** picker that lists your public channels, a **Message** editor where `/` or the field picker inserts an extracted field as a chip, a **Severity** choice (Info, Warning, Critical), and a **Preview** of the rendered message with a **Send test** button that posts it to the chosen channel. If nobody has connected Slack for your organization yet, the panel shows a **Connect Slack** prompt instead. That is what a workspace sees until the [connector](/integrations/slack) is set up:

<img src="https://mintcdn.com/anyformat/G2lOO-2_Ah2kKl9r/images/studio-slack-alert-config.webp?fit=max&auto=format&n=G2lOO-2_Ah2kKl9r&q=85&s=f0bd977aa80d80a05aee0fb02c832571" alt="The Slack alert panel before Slack is connected" width="503" height="641" data-path="images/studio-slack-alert-config.webp" />

## Options

| Field | Type | Default | What it does |
| - | - | - | - |
| `channel_id` | string | required | Slack channel id, for example `C0123ABC`. anyformat joins the channel the first time it posts there. Public channels only. |
| `channel_name` | string | required | Display name of the channel at save time, for example `#finance`. Shown in the app; never used to route. |
| `message_template` | string | required | The message body. Plain text with the placeholders below. |
| `severity` | `info` \| `warning` \| `critical` | `info` | Colour of the bar on the Slack card: blue, amber, red. Presentation only. It changes neither routing nor whether the alert fires; gate that with an [If/Else](/guides/nodes/if-else). |

The schema the API accepts is generated from the same source: [Slack alert node schema](/api-reference-v3/node-schemas#slack_alert).

### Placeholders

| Placeholder | Renders as |
| - | - |
| `${field.<name>}` | The extracted value of that field. Name the field as you did on the Extract node; Studio writes the field's persistent id instead, and both resolve. |
| `${validation.<rule_id>.status}` | The verdict of the upstream Validate rule: `pass`, `fail`, or `inconclusive`. |
| `${validation.<rule_id>.detail}` | The rule's one-line explanation. |
| `${validation.<rule_id>.severity}` | The rule's severity: `error` or `warning`. |

A `validation` placeholder needs a [Validate](/guides/nodes/validate) node upstream that carries the rule. A placeholder that resolves to nothing, because the field was renamed, deleted, or not extracted for this document, or the rule did not run, renders as `<missing: …>` in the delivered message. Nothing is dropped silently.

## Connects to

<div className="af-flow" role="img" aria-label="If/Else feeds a Slack alert, which is terminal">
  <div className="af-flow-row">
    <a className="af-node" href="/guides/nodes/if-else">If/Else</a>

    <span className="af-link" />

    <a className="af-node af-node-on" href="/guides/nodes/slack-alert">Slack alert</a>
  </div>

  <div className="af-flow-note">Either If/Else branch works. <a href="/guides/nodes/extract">Extract</a> and <a href="/guides/nodes/validate">Validate</a> can feed it directly instead. Nothing follows it.</div>
</div>

Parse, Classify, and Split cannot feed it: they carry no extracted fields for the template to fill. The API rejects those edges.

## What it returns

A message in the channel, and nothing in the run results. Each message carries:

* The rendered template, with the severity colour on the card.
* An **Open document** button that opens the file in Studio at the workflow version the alert fired against.

The alert fires after the node before it finishes for the document. Behind an If/Else, it fires only when the document took that branch. Deliveries are capped per organization at **60 per minute** and **500 per hour**; alerts over the cap are dropped for that window, not queued. Details and troubleshooting: [Slack integration](/integrations/slack#how-alerts-are-delivered).

## Billing

Free. Slack alert runs no model and bills no credits. Test messages from Studio are free too. Full price list: [How credits work](/concepts/how-credits-work).

## Examples

* [Invoice processing](/examples/invoice-processing): post every invoice over 10,000 to `#finance` with the [If/Else](/guides/nodes/if-else) on that page in front of this node.
* [Contract analysis](/examples/contract-analysis): alert legal when a contract's key clause fails an AI validation rule, with `${validation.<rule_id>.detail}` in the message.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.