Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions apps/docs/content/docs/en/workflows/blocks/webhook.mdx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
---
title: Webhook
description: The Webhook block sends an HTTP POST to an external endpoint, with automatic headers and optional signing.
title: Outgoing Webhook
description: The Outgoing Webhook block sends an HTTP POST to an external endpoint, with automatic headers and optional signing.
pageType: reference
---

import { Callout } from 'fumadocs-ui/components/callout'
import { BlockPreview, WorkflowPreview, WEBHOOK_NOTIFY_WORKFLOW, WEBHOOK_TRIGGER_WORKFLOW } from '@/components/workflow-preview'
import { FAQ } from '@/components/ui/faq'

The Webhook block sends HTTP POST requests to external webhook endpoints with automatic webhook headers and optional HMAC signing.
The Outgoing Webhook block sends HTTP POST requests to external webhook endpoints with automatic webhook headers and optional HMAC signing.

<BlockPreview type="webhook" />

Expand Down Expand Up @@ -77,16 +77,16 @@ Format the result, then POST it to a Slack, Discord, or custom endpoint.

<WorkflowPreview workflow={WEBHOOK_TRIGGER_WORKFLOW} />

When the Condition passes, the Webhook starts a process in another system.
When the Condition passes, the Outgoing Webhook starts a process in another system.

<Callout>
The Webhook block always uses POST. For other HTTP methods or more control, use the [API block](/workflows/blocks/api).
The Outgoing Webhook block always uses POST. For other HTTP methods or more control, use the [API block](/workflows/blocks/api).
</Callout>

<FAQ items={[
{ question: "Can I use HTTP methods other than POST?", answer: "No. The Webhook block always sends POST requests. If you need GET, PUT, DELETE, or PATCH, use the API block instead, which supports all standard HTTP methods." },
{ question: "Can I use HTTP methods other than POST?", answer: "No. The Outgoing Webhook block always sends POST requests. If you need GET, PUT, DELETE, or PATCH, use the API block instead, which supports all standard HTTP methods." },
{ question: "How does HMAC payload signing work?", answer: "When you provide a signing secret, the block generates an HMAC-SHA256 signature of the payload and includes it in the X-Webhook-Signature header in the format t=timestamp,v1=signature. The receiver can verify by computing HMAC-SHA256(secret, \"timestamp.body\") and comparing with the v1 value." },
{ question: "What headers are added automatically?", answer: "Every webhook request automatically includes Content-Type (application/json), X-Webhook-Timestamp (Unix timestamp in milliseconds), X-Delivery-ID (unique UUID), and Idempotency-Key (same as X-Delivery-ID for deduplication)." },
{ question: "Can custom headers override the automatic ones?", answer: "Yes. Any custom headers you define in the Additional Headers section will override automatic headers that share the same name." },
{ question: "How is the Webhook block different from the API block?", answer: "The Webhook block is purpose-built for webhook delivery: it is POST-only, automatically adds webhook-specific headers (timestamp, delivery ID, idempotency key), and supports optional HMAC signing. The API block is more general-purpose with support for all HTTP methods, query parameters, and configurable retries." },
{ question: "How is the Outgoing Webhook block different from the API block?", answer: "The Outgoing Webhook block is purpose-built for webhook delivery: it is POST-only, automatically adds webhook-specific headers (timestamp, delivery ID, idempotency key), and supports optional HMAC signing. The API block is more general-purpose with support for all HTTP methods, query parameters, and configurable retries." },
]} />
14 changes: 7 additions & 7 deletions apps/docs/content/docs/en/workflows/triggers/sim.mdx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
---
title: Sim
title: Sim Workspace Events
---

import { Callout } from 'fumadocs-ui/components/callout'
import { Tab, Tabs } from 'fumadocs-ui/components/tabs'
import { FAQ } from '@/components/ui/faq'

The Sim trigger runs a workflow when events happen in your workspace: another workflow's run fails or succeeds, a workflow is deployed, or an alert condition like a latency spike or cost threshold is met. Use it to build side-effect workflows — alerting, escalation, auto-remediation — composed from any blocks (Slack, email, webhooks, custom logic).
The Sim Workspace Events trigger runs a workflow when events happen in your workspace: another workflow's run fails or succeeds, a workflow is deployed, or an alert condition like a latency spike or cost threshold is met. Use it to build side-effect workflows — alerting, escalation, auto-remediation — composed from any blocks (Slack, email, webhooks, custom logic).

## Events

Pick one event per Sim trigger block:
Pick one event per Sim Workspace Events trigger block:

**Plain events** — fire on every occurrence:

Expand Down Expand Up @@ -68,8 +68,8 @@ All events include `event`, `timestamp`, `workflowId`, and `workflowName` (the s
## Behavior

<ul className="list-disc space-y-1 pl-6">
<li>The workflow containing the Sim trigger must be <strong>deployed</strong> for events to fire.</li>
<li>Runs started by a Sim trigger never emit workspace events, so side-effect workflows cannot chain or loop.</li>
<li>The workflow containing the Sim Workspace Events trigger must be <strong>deployed</strong> for events to fire.</li>
<li>Runs started by a Sim Workspace Events trigger never emit workspace events, so side-effect workflows cannot chain or loop.</li>
<li>Alert conditions fire at most once per cooldown window (one hour, or the inactivity window for No Activity).</li>
<li>Event delivery is fire-and-forget: side-effect runs are billed like any other run and are subject to workspace rate limits.</li>
</ul>
Expand All @@ -80,8 +80,8 @@ All events include `event`, `timestamp`, `workflowId`, and `workflowName` (the s
</Callout>

<FAQ items={[
{ question: "Why isn't my Sim trigger firing?", answer: "The workflow containing the trigger must be deployed — events only fire for deployed workflows. Also note the trigger never fires for the workflow it lives in, and runs started by another Sim trigger don't emit events." },
{ question: "Can a Sim-triggered workflow trigger other Sim triggers?", answer: "No. Runs started by a Sim trigger never emit workspace events. This prevents chains and infinite loops — an alert workflow that fails can't re-trigger itself." },
{ question: "Why isn't my Sim Workspace Events trigger firing?", answer: "The workflow containing the trigger must be deployed — events only fire for deployed workflows. Also note the trigger never fires for the workflow it lives in, and runs started by another Sim Workspace Events trigger don't emit events." },
{ question: "Can a workflow started by a Sim Workspace Events trigger fire other Sim Workspace Events triggers?", answer: "No. Runs started by a Sim Workspace Events trigger never emit workspace events. This prevents chains and infinite loops — an alert workflow that fails can't re-trigger itself." },
{ question: "How often do alert conditions fire?", answer: "At most once per cooldown window per trigger block. Most conditions use a one-hour cooldown; No Activity uses the configured inactivity window, evaluated per watched workflow." },
{ question: "What unit is cost in?", answer: "Credits, both for the Cost Threshold configuration and the cost field in event payloads." },
]} />
2 changes: 1 addition & 1 deletion apps/sim/blocks/blocks/sim_workspace_event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const SimWorkspaceEventBlock: BlockConfig = {
// can scrape the type for icon-map keys; a test asserts it stays equal to
// the constant.
type: 'sim_workspace_event',
name: 'Sim',
name: 'Sim Workspace Events',
description:
'Run this workflow when workspace events occur: run errors or successes, deployments, and alert conditions like latency or cost spikes.',
category: 'triggers',
Expand Down
2 changes: 1 addition & 1 deletion apps/sim/blocks/blocks/webhook_request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { RequestResponse } from '@/tools/http/types'

export const WebhookRequestBlock: BlockConfig<RequestResponse> = {
type: 'webhook_request',
name: 'Webhook',
name: 'Outgoing Webhook',
description: 'Send a webhook request',
longDescription:
'Send an HTTP POST request to a webhook URL with automatic webhook headers. Optionally sign the payload with HMAC-SHA256 for secure webhook delivery.',
Expand Down
46 changes: 26 additions & 20 deletions apps/sim/ee/access-control/components/access-control.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1170,6 +1170,28 @@ export function AccessControl() {
)
}

const deleteConfirmModal = (
<ChipConfirmModal
open={!!deletingGroup}
onOpenChange={() => setDeletingGroup(null)}
srTitle='Delete Permission Group'
title='Delete Permission Group'
text={[
'Are you sure you want to delete ',
{ text: deletingGroup?.name ?? 'this group', bold: true },
'? ',
{ text: 'All members will be removed from this group.', error: true },
' This action cannot be undone.',
]}
confirm={{
label: 'Delete',
onClick: confirmDelete,
pending: deletePermissionGroup.isPending,
pendingLabel: 'Deleting...',
}}
/>
)

if (viewingGroup) {
return (
<>
Expand Down Expand Up @@ -1479,7 +1501,7 @@ export function AccessControl() {
{filteredToolBlocks.length > 0 && (
<div className='flex flex-col gap-1.5 border-[var(--border)] border-t pt-4'>
<span className='font-medium text-[var(--text-tertiary)] text-xs uppercase tracking-wide'>
Tools
Integrations and Triggers
</span>
<div className='grid grid-cols-3 gap-x-2 gap-y-0.5'>
{filteredToolBlocks.map((block) => {
Expand Down Expand Up @@ -1638,6 +1660,8 @@ export function AccessControl() {
isAdding={bulkAddMembers.isPending}
errorMessage={addMembersError}
/>

{deleteConfirmModal}
</>
)
}
Expand Down Expand Up @@ -1784,25 +1808,7 @@ export function AccessControl() {
/>
</ChipModal>

<ChipConfirmModal
open={!!deletingGroup}
onOpenChange={() => setDeletingGroup(null)}
srTitle='Delete Permission Group'
title='Delete Permission Group'
text={[
'Are you sure you want to delete ',
{ text: deletingGroup?.name ?? 'this group', bold: true },
'? ',
{ text: 'All members will be removed from this group.', error: true },
' This action cannot be undone.',
]}
confirm={{
label: 'Delete',
onClick: confirmDelete,
pending: deletePermissionGroup.isPending,
pendingLabel: 'Deleting...',
}}
/>
{deleteConfirmModal}
</>
)
}
6 changes: 3 additions & 3 deletions apps/sim/triggers/sim/workspace-event.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ describe('sim workspace event trigger registration', () => {
})
})

it('is named Sim', () => {
expect(SimWorkspaceEventBlock.name).toBe('Sim')
expect(simWorkspaceEventTrigger.name).toBe('Sim')
it('is named Sim Workspace Events', () => {
expect(SimWorkspaceEventBlock.name).toBe('Sim Workspace Events')
expect(simWorkspaceEventTrigger.name).toBe('Sim Workspace Events')
})
})

Expand Down
2 changes: 1 addition & 1 deletion apps/sim/triggers/sim/workspace-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type { TriggerConfig } from '@/triggers/types'

export const simWorkspaceEventTrigger: TriggerConfig = {
id: SIM_WORKSPACE_EVENT_TRIGGER_ID,
name: 'Sim',
name: 'Sim Workspace Events',
provider: SIM_TRIGGER_PROVIDER,
description:
'Triggers when workspace events occur: run errors or successes, deployments, and alert conditions like latency or cost spikes',
Expand Down
Loading