Skip to content
Open
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
112 changes: 111 additions & 1 deletion apps/docs/content/docs/en/blocks/function.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
title: Function
---

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

The Function block executes custom JavaScript or TypeScript code in your workflows. Transform data, perform calculations, or implement custom logic.
The Function block executes custom JavaScript, TypeScript, or Python code in your workflows. Transform data, perform calculations, or implement custom logic.

<div className="flex justify-center">
<Image
Expand Down Expand Up @@ -41,6 +43,8 @@ Input → Function (Validate & Sanitize) → API (Save to Database)

### Example: Loyalty Score Calculator

<Tabs items={['JavaScript', 'Python']}>
<Tab value="JavaScript">
```javascript title="loyalty-calculator.js"
// Process customer data and calculate loyalty score
const { purchaseHistory, accountAge, supportTickets } = <agent>;
Expand All @@ -64,6 +68,112 @@ return {
metrics: { spendScore, frequencyScore, supportScore }
};
```
</Tab>
<Tab value="Python">
```python title="loyalty-calculator.py"
import json

# Reference outputs from other blocks using angle bracket syntax
data = json.loads('<agent>')
purchase_history = data["purchaseHistory"]
account_age = data["accountAge"]
support_tickets = data["supportTickets"]

# Calculate metrics
total_spent = sum(p["amount"] for p in purchase_history)
purchase_frequency = len(purchase_history) / (account_age / 365)
ticket_ratio = support_tickets["resolved"] / support_tickets["total"]

# Calculate loyalty score (0-100)
spend_score = min(total_spent / 1000 * 30, 30)
frequency_score = min(purchase_frequency * 20, 40)
support_score = ticket_ratio * 30

loyalty_score = round(spend_score + frequency_score + support_score)

tier = "Platinum" if loyalty_score >= 80 else "Gold" if loyalty_score >= 60 else "Silver"

result = {
"customer": data["name"],
"loyaltyScore": loyalty_score,
"loyaltyTier": tier,
"metrics": {
"spendScore": spend_score,
"frequencyScore": frequency_score,
"supportScore": support_score
}
}
print(json.dumps(result))
```
</Tab>
</Tabs>

## Python Support

The Function block supports Python as an alternative to JavaScript. Python code runs in a secure [E2B](https://e2b.dev) cloud sandbox.

{/* TODO: Screenshot of the Function block with Python language selected */}

### Enabling Python

Select **Python** from the language dropdown in the Function block. Python execution requires E2B to be enabled on your Sim instance.

<Callout type="warn">
If you don't see Python as an option in the language dropdown, E2B is not enabled. This only applies to self-hosted instances — E2B is enabled by default on sim.ai.
</Callout>

<Callout type="info">
Python code always runs in the E2B sandbox, even for simple scripts without imports. This ensures a secure, isolated execution environment.
</Callout>

### Returning Results

In Python, print your result as JSON to stdout. The Function block captures stdout and makes it available via `<function.result>`:

```python title="example.py"
import json

data = {"status": "processed", "count": 42}
print(json.dumps(data))
```

### Available Libraries

The E2B sandbox includes the Python standard library (`json`, `re`, `datetime`, `math`, `os`, `collections`, etc.) and common packages like `matplotlib` for visualization. Charts generated with matplotlib are captured as images automatically.

<Callout type="info">
The exact set of pre-installed packages depends on the E2B sandbox configuration. If a package you need isn't available, consider calling an external API from your code instead.
</Callout>

### Matplotlib Charts

When your Python code generates matplotlib figures, they are automatically captured and returned as base64-encoded PNG images in the output:

```python title="chart.py"
import matplotlib.pyplot as plt
import json

data = json.loads('<api.data>')

plt.figure(figsize=(10, 6))
plt.bar(data["labels"], data["values"])
plt.title("Monthly Revenue")
plt.xlabel("Month")
plt.ylabel("Revenue ($)")
plt.savefig("chart.png")
plt.show()
```

{/* TODO: Screenshot of Python code execution output in the logs panel */}

### JavaScript vs. Python

| | JavaScript | Python |
|--|-----------|--------|
| **Execution** | Local VM (fast) or E2B sandbox (with imports) | Always E2B sandbox |
| **Returning results** | `return { ... }` | `print(json.dumps({ ... }))` |
| **HTTP requests** | `fetch()` built-in | `requests` or `httpx` |
| **Best for** | Quick transforms, JSON manipulation | Data science, charting, complex math |

## Best Practices

Expand Down
262 changes: 262 additions & 0 deletions apps/docs/content/docs/en/execution/api-deployment.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
---
title: API Deployment
---

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

Deploy your workflow as a REST API endpoint that applications can call directly. Supports synchronous, streaming, and asynchronous execution modes.

## Deploying a Workflow

1. Open your workflow and click **Deploy**
2. The **General** tab shows deployment status — click **Deploy** to publish
3. Switch to the **API** tab to see your endpoint URL and code examples

{/* TODO: Screenshot of the API tab in the deploy modal showing code examples */}

Once deployed, your workflow is available at:

```
POST https://sim.ai/api/workflows/{workflow-id}/execute
```

<Callout type="info">
API executions run against the active deployment snapshot. After making canvas changes, click **Update** in the Deploy modal to publish a new version.
</Callout>

## Authentication

By default, API endpoints require an API key in the `x-api-key` header. You can generate keys in **Settings → Sim Keys**.

```bash
curl -X POST https://sim.ai/api/workflows/{workflow-id}/execute \
-H "Content-Type: application/json" \
-H "x-api-key: $SIM_API_KEY" \
-d '{ "input": "Hello" }'
```

### Public APIs

You can make an API endpoint public so it doesn't require authentication. This is useful for public-facing integrations or webhooks from external services.

{/* TODO: Screenshot of the public/private API toggle */}

<Callout type="warn">
Public endpoints can be called by anyone with the URL. Only use this for workflows that don't expose sensitive data or perform sensitive actions.
</Callout>

## Execution Modes

The API tab in the Deploy modal shows code examples for each mode in **cURL**, **Python**, **JavaScript**, and **TypeScript**.

### Synchronous

The default mode. Send a request and wait for the complete response:

<Tabs items={['cURL', 'Python']}>
<Tab value="cURL">
```bash
curl -X POST https://sim.ai/api/workflows/{workflow-id}/execute \
-H "Content-Type: application/json" \
-H "x-api-key: $SIM_API_KEY" \
-d '{ "input": "Summarize this article" }'
```
</Tab>
<Tab value="Python">
```python
import requests
import os

response = requests.post(
"https://sim.ai/api/workflows/{workflow-id}/execute",
headers={
"Content-Type": "application/json",
"x-api-key": os.environ.get("SIM_API_KEY")
},
json={"input": "Summarize this article"}
)

print(response.json())
```
</Tab>
</Tabs>

### Streaming

Stream the response as it's generated. Choose which block outputs to stream using the output selector in the API tab.

{/* TODO: Screenshot of the streaming output selector dropdown */}

<Tabs items={['cURL', 'Python']}>
<Tab value="cURL">
```bash
curl -X POST https://sim.ai/api/workflows/{workflow-id}/execute \
-H "Content-Type: application/json" \
-H "x-api-key: $SIM_API_KEY" \
-d '{
"input": "Write a long essay",
"stream": true,
"selectedOutputs": ["agent_1.content"]
}'
```
</Tab>
<Tab value="Python">
```python
import requests
import os

response = requests.post(
"https://sim.ai/api/workflows/{workflow-id}/execute",
headers={
"Content-Type": "application/json",
"x-api-key": os.environ.get("SIM_API_KEY")
},
json={
"input": "Write a long essay",
"stream": True,
"selectedOutputs": ["agent_1.content"]
},
stream=True
)

for line in response.iter_lines():
if line:
print(line.decode())
```
</Tab>
</Tabs>

### Asynchronous

For long-running workflows, use async mode to start a job and poll for results. Set the `X-Execution-Mode: async` header to submit the workflow and receive a job ID immediately without waiting for completion.

<Tabs items={['Start Job', 'Check Status']}>
<Tab value="Start Job">
```bash
curl -X POST https://sim.ai/api/workflows/{workflow-id}/execute \
-H "Content-Type: application/json" \
-H "x-api-key: $SIM_API_KEY" \
-H "X-Execution-Mode: async" \
-d '{ "input": "Process this large dataset" }'
```

**Response** (HTTP 202):
```json
{
"success": true,
"async": true,
"jobId": "run_abc123",
"executionId": "exec_xyz",
"message": "Workflow execution queued",
"statusUrl": "https://sim.ai/api/jobs/run_abc123"
}
```
</Tab>
<Tab value="Check Status">
```bash
curl https://sim.ai/api/jobs/{jobId} \
-H "x-api-key: $SIM_API_KEY"
```

**Response** (while processing):
```json
{
"success": true,
"taskId": "run_abc123",
"status": "processing",
"metadata": {
"createdAt": "2025-09-10T12:00:00.000Z",
"startedAt": "2025-09-10T12:00:01.000Z"
},
"estimatedDuration": 300000
}
```

**Response** (when completed):
```json
{
"success": true,
"taskId": "run_abc123",
"status": "completed",
"metadata": {
"createdAt": "2025-09-10T12:00:00.000Z",
"startedAt": "2025-09-10T12:00:01.000Z",
"completedAt": "2025-09-10T12:00:05.000Z",
"duration": 4000
},
"output": { "result": "..." }
}
```
</Tab>
</Tabs>

#### Job Status Values

| Status | Description |
|--------|-------------|
| `queued` | Job is waiting to be picked up |
| `processing` | Workflow is actively executing |
| `completed` | Finished successfully — `output` field contains the result |
| `failed` | Execution failed — `error` field contains the message |

Poll the `statusUrl` returned in the initial response until the status is `completed` or `failed`.

#### Execution Time Limits

Async jobs can run significantly longer than synchronous requests:

| Plan | Sync Limit | Async Limit |
|------|-----------|-------------|
| **Community** | 5 minutes | 90 minutes |
| **Pro / Max / Team / Enterprise** | 50 minutes | 90 minutes |

If a job exceeds its time limit, it is automatically marked as `failed`.

#### Job Retention

Completed and failed job results are retained for **24 hours**. After that, the job data is cleaned up and the status endpoint returns `404`. If you need results longer, retrieve and store them on your end after completion.

#### Capacity Limits

If the execution queue is full, the API returns a `503` response with a `Retry-After` header:

```json
{
"error": "Service temporarily at capacity",
"retryAfterSeconds": 10
}
```

Wait the indicated number of seconds before retrying.

<Callout type="info">
Async mode always runs against the deployed version. It does not support draft state, block overrides, or partial execution options like `runFromBlock` or `stopAfterBlockId`.
</Callout>

## API Key Management

Generate and manage API keys in **Settings → Sim Keys**:

- **Create** new keys for different applications or environments
- **Revoke** keys that are no longer needed
- Keys are scoped to your workspace

<Callout type="info">
The API tab in the Deploy modal shows a masked version of your key in the code examples. Copy the examples directly — they include the correct authentication header.
</Callout>

## Rate Limits

API calls are subject to rate limits based on your plan. Rate limit details are returned in response headers (`X-RateLimit-*`) and in the response body. Use async mode for high-volume or long-running workloads.

For detailed rate limit information and the logs/webhooks API, see [External API](/execution/api).

<FAQ items={[
{ question: "What's the difference between the API tab and the External API docs?", answer: "The API tab in the Deploy modal is for deploying your workflow as a callable endpoint. The External API documentation covers the logs query API and webhook notifications for monitoring executions." },
{ question: "Can I deploy the same workflow as both an API and a chat?", answer: "Yes. A workflow can be deployed as an API, chat, MCP tool, and more simultaneously. Each deployment type runs against the same active snapshot." },
{ question: "How do I choose between sync, streaming, and async?", answer: "Use sync for quick workflows (under a few seconds). Use streaming when you want to show progressive output to users. Use async for long-running workflows where you don't want to hold a connection open." },
{ question: "How long are async job results available?", answer: "Completed and failed job results are retained for 24 hours. After that, the status endpoint returns 404. Retrieve and store results on your end if you need them longer." },
{ question: "What happens if my API key is compromised?", answer: "Revoke the key immediately in Settings → Sim Keys and create a new one. Revoked keys stop working instantly." },
]} />
Loading
Loading