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
80 changes: 32 additions & 48 deletions apps/docs/content/docs/en/api-reference/getting-started.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -49,28 +49,28 @@ A workflow must be deployed before it can be executed via the API. Click the **D
<Tabs items={['curl', 'TypeScript', 'Python']}>
<Tab value="curl">
```bash
curl -X POST https://www.sim.ai/api/workflows/{workflowId}/execute \
curl -X POST https://www.sim.ai/api/v2/workflows/{workflowId}/execute \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_API_KEY" \
-d '{"inputs": {}}'
-d '{"input": {}}'
```
</Tab>
<Tab value="TypeScript">
```typescript
const response = await fetch(
`https://www.sim.ai/api/workflows/${workflowId}/execute`,
`https://www.sim.ai/api/v2/workflows/${workflowId}/execute`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.SIM_API_KEY!,
},
body: JSON.stringify({ inputs: {} }),
body: JSON.stringify({ input: {} }),
}
)

const data = await response.json()
console.log(data.output)
console.log(data.data.output)
```
</Tab>
<Tab value="Python">
Expand All @@ -79,16 +79,16 @@ A workflow must be deployed before it can be executed via the API. Click the **D
import os

response = requests.post(
f"https://www.sim.ai/api/workflows/{workflow_id}/execute",
f"https://www.sim.ai/api/v2/workflows/{workflow_id}/execute",
headers={
"Content-Type": "application/json",
"X-API-Key": os.environ["SIM_API_KEY"],
},
json={"inputs": {}},
json={"input": {}},
)

data = response.json()
print(data["output"])
print(data["data"]["output"])
```
</Tab>
</Tabs>
Expand All @@ -103,77 +103,61 @@ By default, workflow executions are **synchronous** — the API blocks until the
For long-running workflows, use **asynchronous execution** by passing `async: true`:

```bash
curl -X POST https://www.sim.ai/api/workflows/{workflowId}/execute \
curl -X POST https://www.sim.ai/api/v2/workflows/{workflowId}/execute \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_API_KEY" \
-d '{"inputs": {}, "async": true}'
-d '{"input": {}, "async": true}'
```

This returns immediately with a `jobId` and `statusUrl`:
This returns immediately with an `executionId` and `statusUrl`:

```json
{
"success": true,
"jobId": "job_abc123",
"statusUrl": "https://www.sim.ai/api/jobs/job_abc123",
"message": "Workflow execution started",
"async": true
"data": {
"executionId": "c7a92e15-3f4b-4d8c-a1e6-9b0d5f2c8e74",
"statusUrl": "https://www.sim.ai/api/v2/workflows/{workflowId}/executions/c7a92e15-3f4b-4d8c-a1e6-9b0d5f2c8e74"
}
}
```

Poll the [Get Job Status](/api-reference/execution/getJobStatus) endpoint until the status is `completed` or `failed`:
Poll the [Get Execution Status](/api-reference/execution/getWorkflowExecution) endpoint until the status is terminal:

```bash
curl https://www.sim.ai/api/jobs/{jobId} \
curl https://www.sim.ai/api/v2/workflows/{workflowId}/executions/{executionId}?includeOutput=true \
-H "X-API-Key: YOUR_API_KEY"
```

<Callout type="info">
Job status transitions follow: `queued` → `processing` → `completed` or `failed`. The `output` field is only present when status is `completed`.
Execution status transitions follow: `queued` → `running` → `completed`, `failed`, `cancelled`, or `paused`. The `data.output` field is populated for completed executions when `includeOutput=true`.
</Callout>

## Response Format

Successful responses include an `output` object with your workflow results and a `limits` object with your current rate limit and usage status:
Successful v2 responses wrap the execution resource in `data`:

```json
{
"success": true,
"output": {
"result": "Hello, world!"
},
"limits": {
"workflowExecutionRateLimit": {
"sync": {
"requestsPerMinute": 60,
"maxBurst": 10,
"remaining": 59,
"resetAt": "2025-01-01T00:01:00Z"
},
"async": {
"requestsPerMinute": 30,
"maxBurst": 5,
"remaining": 30,
"resetAt": "2025-01-01T00:01:00Z"
}
},
"usage": {
"currentPeriodCost": 1.25,
"limit": 50.00,
"plan": "pro",
"isExceeded": false
}
"data": {
"executionId": "c7a92e15-3f4b-4d8c-a1e6-9b0d5f2c8e74",
"workflowId": "{workflowId}",
"status": "completed",
"output": { "result": "Hello, world!" },
"error": null,
"durationMs": 842
}
}
```

## Error Handling

The API uses standard HTTP status codes. Error responses include a human-readable `error` message:
The API uses standard HTTP status codes. v2 errors include a stable code and human-readable message:

```json
{
"error": "Workflow not found"
"error": {
"code": "NOT_FOUND",
"message": "Workflow not found"
}
}
```

Expand All @@ -191,7 +175,7 @@ The API uses standard HTTP status codes. Error responses include a human-readabl

## Rate Limits

Rate limits depend on your subscription plan and apply separately to synchronous and asynchronous executions. Every execution response includes a `limits` object showing your current rate limit status.
Rate limits depend on your subscription plan and apply separately to synchronous and asynchronous executions.

When rate limited, the API returns a `429` response with a `Retry-After` header indicating how many seconds to wait before retrying.

Expand Down
65 changes: 40 additions & 25 deletions apps/docs/content/docs/en/api-reference/python.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ result = client.execute_workflow(

**Returns:** `WorkflowExecutionResult | AsyncExecutionResult`

When `async_execution=True`, returns immediately with a `job_id` and `status_url` for polling. Otherwise, waits for completion.
When `async_execution=True`, returns immediately with an `execution_id` and `status_url` for polling. Otherwise, waits for completion.

##### get_workflow_status()

Expand Down Expand Up @@ -112,30 +112,42 @@ if is_ready:

**Returns:** `bool`

##### get_job_status()
##### get_workflow_execution()

Get the status of an async job execution.
Get the status and optional outputs of a workflow execution.

```python
status = client.get_job_status("job-id-from-async-execution")
print("Status:", status["status"]) # 'queued', 'processing', 'completed', 'failed'
status = client.get_workflow_execution("workflow-id", "execution-id", include_output=True)
print("Status:", status["status"]) # 'queued', 'running', 'completed', 'failed'
if status["status"] == "completed":
print("Output:", status["output"])
```

**Parameters:**
- `task_id` (str): The job ID returned from async execution
- `workflow_id` (str): The workflow ID
- `execution_id` (str): The execution ID returned from async execution
- `include_output` (bool, optional): Include the final output for completed executions
- `selected_outputs` (list[str], optional): Block output selectors to include

**Returns:** `Dict[str, Any]`

**Response fields:**
- `success` (bool): Whether the request was successful
- `taskId` (str): The job ID
- `status` (str): One of `'queued'`, `'processing'`, `'completed'`, `'failed'`, `'cancelled'`
- `metadata` (dict): Contains `startedAt`, `completedAt`, and `duration`
- `output` (any, optional): The workflow output (when completed)
- `error` (any, optional): Error details (when failed)
- `estimatedDuration` (int, optional): Estimated duration in milliseconds (when processing/queued)
- `executionId` (str): The execution ID
- `workflowId` (str): The workflow ID
- `status` (str): One of `'queued'`, `'pending'`, `'running'`, `'paused'`, `'completed'`, `'failed'`, `'cancelled'`
- `startedAt` / `endedAt` (str): Execution timestamps
- `durationMs` (int, optional): Duration in milliseconds
- `output` (any, optional): The workflow output when requested for a completed execution
- `blockOutputs` (dict, optional): Requested block outputs
- `error` (dict, optional): Structured failure details with `code`, `message`, and optional `details`

##### get_job_status()

Get the status of a job created through the legacy async execution endpoint. New integrations should use `get_workflow_execution()` with the execution ID instead.

```python
status = client.get_job_status("legacy-job-id")
```

##### execute_with_retry()

Expand Down Expand Up @@ -270,9 +282,8 @@ class WorkflowExecutionResult:
@dataclass
class AsyncExecutionResult:
success: bool
job_id: str
execution_id: str
status_url: str
execution_id: Optional[str] = None
message: str = ""
async_execution: bool = True
```
Expand Down Expand Up @@ -494,22 +505,26 @@ def execute_async():
)

# Check if result is an async execution
if hasattr(result, 'job_id'):
print(f"Job ID: {result.job_id}")
if hasattr(result, 'async_execution') and result.async_execution:
print(f"Execution ID: {result.execution_id}")
print(f"Status endpoint: {result.status_url}")

# Poll for completion
status = client.get_job_status(result.job_id)
status = client.get_workflow_execution(
"workflow-id", result.execution_id, include_output=True
)

while status["status"] in ["queued", "processing"]:
while status["status"] in ["queued", "pending", "running"]:
print(f"Current status: {status['status']}")
time.sleep(2) # Wait 2 seconds
status = client.get_job_status(result.job_id)
status = client.get_workflow_execution(
"workflow-id", result.execution_id, include_output=True
)

if status["status"] == "completed":
print("Workflow completed!")
print(f"Output: {status['output']}")
print(f"Duration: {status['metadata']['duration']}")
print(f"Duration: {status['durationMs']}")
else:
print(f"Workflow failed: {status['error']}")

Expand Down Expand Up @@ -656,13 +671,13 @@ def stream_workflow():

def generate():
response = requests.post(
'https://sim.ai/api/workflows/WORKFLOW_ID/execute',
'https://sim.ai/api/v2/workflows/WORKFLOW_ID/execute',
headers={
'Content-Type': 'application/json',
'X-API-Key': os.getenv('SIM_API_KEY')
},
json={
'message': 'Generate a story',
'input': {'message': 'Generate a story'},
'stream': True,
'selectedOutputs': ['agent1.content']
},
Expand Down Expand Up @@ -765,9 +780,9 @@ import { FAQ } from '@/components/ui/faq'

<FAQ items={[
{ question: "Do I need to deploy a workflow before I can execute it via the SDK?", answer: "Yes. Workflows must be deployed before they can be executed through the SDK. You can use the validate_workflow() method to check whether a workflow is deployed and ready. If it returns False, deploy the workflow from the Sim UI first and create or select an API key during deployment." },
{ question: "What is the difference between sync and async execution?", answer: "Sync execution (the default) blocks until the workflow completes and returns the full result. Async execution (async_execution=True) returns immediately with a job ID and status URL that you can poll using get_job_status(). Use async mode for long-running workflows to avoid request timeouts. Async job statuses include queued, processing, completed, failed, and cancelled." },
{ question: "What is the difference between sync and async execution?", answer: "Sync execution (the default) blocks until the workflow completes and returns the full result. Async execution (async_execution=True) returns immediately with an execution ID and status URL that you can poll using get_workflow_execution(). Use async mode for long-running workflows to avoid request timeouts. Execution statuses include queued, pending, running, paused, completed, failed, and cancelled." },
{ question: "How does the SDK handle rate limiting?", answer: "The SDK provides built-in rate limiting support through the execute_with_retry() method. It uses exponential backoff (1s, 2s, 4s, 8s...) with 25% jitter to avoid thundering herd problems. If the API returns a retry-after header, that value is used instead. You can configure max_retries, initial_delay, max_delay, and backoff_multiplier. Use get_rate_limit_info() to check your current rate limit status." },
{ question: "Can I use the Python SDK as a context manager?", answer: "Yes. The SimStudioClient supports Python's context manager protocol. Use it with the 'with' statement to automatically close the underlying HTTP session when you are done, which is especially useful for scripts that create and discard client instances." },
{ question: "How do I handle different types of errors from the SDK?", answer: "The SDK raises SimStudioError with a code property for API-specific errors. Common error codes are UNAUTHORIZED (invalid API key), TIMEOUT (request timed out), RATE_LIMIT_EXCEEDED (too many requests), USAGE_LIMIT_EXCEEDED (billing limit reached), and EXECUTION_ERROR (workflow failed). Use the error code to implement targeted error handling and recovery logic." },
{ question: "How do I monitor my API usage and remaining quota?", answer: "Use the get_usage_limits() method to check your current usage. It returns sync and async rate limit details (limit, remaining, reset time, whether you are currently limited), plus your current period cost, usage limit, and plan tier. This lets you monitor consumption and alert before hitting limits." },
]} />
]} />
Loading
Loading