# Slack 1-Click Interactive Approvals

> Connect Slack to receive real-time Block Kit approval cards for emails held in approval mode. Review previews and approve or reject sends with one click.

Autonomous AI agents and automated workflows can draft emails without unilateral send authority. When an email triggers an approval policy, SadaSend posts a rich Block Kit card into your Slack channel with one-click decision buttons.

## How Slack interactive approvals work

SadaSend introduces interactive human-in-the-loop email governance directly inside your engineering and operations channels in Slack. When an AI agent, background worker, or API key with approval policies queues an email, it enters `pending_approval` status rather than dispatching directly.

Instead of requiring human operators to log into the web dashboard, SadaSend formats and delivers an interactive Block Kit notification card into your designated Slack channel. The card includes recipient details, subject line, security hold reason, agent key label, and a safe blockquote preview of the draft content.

Operators can click **Approve & Send ✅** or **Reject ❌** directly in Slack. SadaSend receives the signed interaction payload, verifies its HMAC-SHA256 signature, validates a strict 5-minute replay window, atomically updates the message status, releases it into the MTA outbox queue, and replaces the Slack card in-place with an authoritative audit confirmation.

> Slack approvals require a Starter plan ($12/mo) or above. Integrations can be configured by account owners and admins under Settings → Slack Approvals.

## Quickstart: 3-Minute Slack app setup

Setting up SadaSend Approvals in Slack takes three minutes using Slack’s App Manifest feature. Follow these five quick steps:

1. **Create the app**: Visit [api.slack.com/apps](https://api.slack.com/apps) → Click **Create New App** → Select **From an app manifest** → Select your target workspace.

2. **Paste the manifest**: Choose the **JSON** tab, paste the official manifest provided in the section below, and click **Create**.

3. **Install to workspace**: In the left sidebar, click **Install App** → Click **Install to Workspace** → Select your target notification channel (e.g., `#email-approvals`) → Click **Allow**.

4. **Copy credentials**: Copy the generated **Incoming Webhook URL** (under *Incoming Webhooks*) and the **Signing Secret** (under *Basic Information → App Credentials*).

5. **Enable interactivity**: In the left sidebar, click **Interactivity & Shortcuts** → Toggle Interactivity to **On** → In **Request URL**, enter `https://api.sadasend.com/webhooks/slack/actions` → Click **Save Changes**.

## Official Slack app manifest (JSON)

You can copy and paste this complete manifest into the Slack App Manifest editor. It automatically configures the required bot scopes (`incoming-webhook`, `chat:write`), app display info, and interactivity endpoints:

```json
{
  "display_information": {
    "name": "SadaSend Approvals",
    "description": "1-Click Interactive Human Approvals for Autonomous Email Sends",
    "background_color": "#09090b"
  },
  "features": {
    "bot_user": {
      "display_name": "SadaSend Approvals",
      "always_online": true
    }
  },
  "oauth_config": {
    "scopes": {
      "bot": [
        "incoming-webhook",
        "chat:write"
      ]
    }
  },
  "settings": {
    "interactivity": {
      "is_enabled": true,
      "request_url": "https://api.sadasend.com/webhooks/slack/actions"
    },
    "org_deploy_enabled": false,
    "socket_mode_enabled": false,
    "token_rotation_enabled": false
  }
}
```

## Connecting Slack in the SadaSend dashboard

Once your Slack app is created, connect it to your SadaSend organization:

1. In your SadaSend dashboard, navigate to **Settings → Slack Approvals** (`/app/settings#slack-integration`).

2. Enter your **Incoming Webhook URL** (`https://hooks.slack.com/services/...`).

3. Enter your **Slack Signing Secret** from *Basic Information → App Credentials*.

4. Enter your target **Channel Name** (e.g., `#email-approvals`).

5. Click **Test Connection** to dispatch a live verification card into your Slack channel.

6. Click **Save Slack Settings** to persist the encrypted configuration.

> Credentials are encrypted at rest using AES-256-GCM authenticated envelopes (`v1.<iv>.<tag>.<ciphertext>`) before storage. Plaintext secrets are never logged or exposed in client payloads.

## Triggering approval mode in code

You can hold emails for Slack approval using any of SadaSend’s four ingress channels: REST API, TypeScript SDK, Python SDK, or Model Context Protocol (MCP).

To require human approval on an email send, provide `mode: "approval"` or set `approval` mode on the API key used by your agent:

```typescript
// TypeScript SDK — Hold email for Slack 1-click human review
import { SadaSend } from 'sadasend';

const sadasend = new SadaSend({ apiKey: process.env.SADASEND_API_KEY });

const result = await sadasend.emails.send({
  from: 'Deal Agent <deals@yourdomain.com>',
  to: 'client@example.com',
  subject: 'Q4 Contract Amendment & Volume Discount',
  html: '<p>Attached please find the revised agreement...</p>',
  mode: 'approval', // Held for human review
  agent_name: 'AutonomousDealNegotiator',
  hold_reason: 'High-value outbound communication requires human review',
});

if (result.status === 'pending_approval') {
  console.log('Held for Slack review:', result.id);
  console.log('Approval card dispatched to your configured Slack channel.');
}
```

| Field / Header | Type | Description |

| --- | --- | --- |

| mode | string (optional) | Set to `"approval"` to hold the email for human sign-off rather than sending immediately. |
| agent_name | string (optional) | Human-readable label for the AI agent or automated script drafting the email. |
| hold_reason | string (optional) | Contextual explanation displayed in the Slack card explaining why review was requested. |
| Idempotency-Key | header (recommended) | UUID preventing duplicate holds if an agent or background worker retries. |

Using standard HTTP REST API:

## Python SDK example

Holding messages from Python autonomous workflows or LangChain / CrewAI agents:

```python
# Python SDK — Hold email for Slack interactive review
from sadasend import SadaSend

client = SadaSend(api_key="sada_live_sk_...")

res = client.emails.send(
    from_="billing@yourdomain.com",
    to="vendor@example.com",
    subject="Wire Transfer Payment Confirmation",
    text="Please confirm receipt of wire transfer #WT-94810.",
    mode="approval",
    agent_name="ProcurementAgent",
    hold_reason="Wire transfers above threshold require operator sign-off",
)

if res.status == "pending_approval":
    print(f"Held for Slack approval with ID: {res.id}")
```

## Security, cryptographic verification & replay defense

SadaSend enforces strict zero-trust cryptographic guardrails on every incoming Slack action callback to prevent forgery and unauthorized email releases:

• **HMAC-SHA256 Signature Verification**: Every request to `POST /webhooks/slack/actions` must carry a valid `X-Slack-Signature` header calculated with your account’s Slack signing secret (`v0=hash(signing_secret, "v0:timestamp:body")`). Invalid signatures are rejected with HTTP 401 `signature_mismatch`.

• **5-Minute Replay Attack Defense**: SadaSend inspects `X-Slack-Request-Timestamp` and verifies that `|now - timestamp| <= 300` seconds. Replayed or delayed requests are rejected immediately.

• **In-Place Atomic Transition**: When an operator clicks `Approve & Send ✅`, the database executes an atomic state transition from `pending_approval` to `queued`, pushes the job to the transactional MTA outbox queue, and locks the row. Attempting to approve or reject a message that has already been decided returns an ephemeral notice to Slack and prevents duplicate processing.

• **Tamper-Evident Audit Logging**: Every decision logs an immutable `queued` or `cancelled` event in `message_event`, permanently recording the operator’s Slack username, user ID, channel ID, and timestamp.

> Never expose your Slack Signing Secret or Incoming Webhook URL in public client code or git repositories. Both values are stored with AES-256-GCM encryption in SadaSend.

## Troubleshooting & common questions

**Why does clicking the button in Slack show an exclamation mark (!)?**

Ensure that your Slack App has **Interactivity** enabled under *Interactivity & Shortcuts* and that the **Request URL** is set exactly to `https://api.sadasend.com/webhooks/slack/actions`. If the URL is misconfigured or inaccessible, Slack cannot deliver the click event.

**Can I approve emails from the SadaSend web app instead of Slack?**

Yes. All emails held in `pending_approval` are visible under **Approvals** (`/app/approvals`). You can review the full HTML email, headers, and security rules, and click Approve or Reject directly from the web dashboard.

**What happens if an approval card is ignored?**

Held emails remain safely paused in `pending_approval` status until an authorized operator approves or rejects them, or until their expiration window is reached. They will never send autonomously without human action.
