# API deployment (/workflows/deployment/api)





Call a deployed workflow at `POST /api/v2/workflows/{workflow-id}/execute`. Choose a complete JSON result, an SSE stream, or an async run receipt.

## Deploy the workflow [#deploying-a-workflow]

You need workspace **Admin** access and the applicable deployment permission. Test with **Run**, then open **Deploy → General** and click **Deploy** or **Update**. [Deployment](/workflows/deployment) covers versions, comparison, rollback, and undeploying.

Ordinary API calls use the active snapshot. Editing the draft does not change that version. Deploy an update before expecting a normal API call to use your changes.

## Authentication [#authentication]

Send a valid Sim API key in `X-API-Key`, or use a supported OAuth access token. Deployed workflow execution requires access to the workflow's workspace; OAuth callers also need the operation's `api:write` scope. See [API authentication](/api-reference/authentication).

Generate keys in **Settings → Sim API keys** or **Deploy → API → Generate API Key**. Keep the key available to your application as `SIM_API_KEY`.

### API info and public access [#api-info-and-public-access]

Open **Deploy → API → Edit API Info** to set a description and choose **API Key** or **Public** access. API-key access is the default.

<Callout type="warn">
  A public endpoint lets an anonymous caller run the deployed workflow. Restrict what input can do and what output reveals before enabling it. Public access is subject to deployment and organization policy; anonymous callers cannot start async or manual draft runs.
</Callout>

## Make a call [#making-api-calls]

Put named [Start inputs](/workflows/triggers/start) inside the request's `input` value. For a field named `message`:

```bash
curl -X POST 'https://www.sim.ai/api/v2/workflows/{workflow-id}/execute' \
  -H "X-API-Key: $SIM_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"input":{"message":"Summarize this article"}}'
```

The **API** tab offers cURL, Python, JavaScript, and TypeScript examples. Replace example identifiers and supply your own key before calling them.

## Execution modes [#execution-modes]

### Synchronous [#synchronous]

The default mode waits for the run to settle:

<Tabs items="['cURL', 'Python', 'TypeScript']">
  <Tab value="cURL">
    ```bash
    curl -X POST 'https://www.sim.ai/api/v2/workflows/{workflow-id}/execute' \
      -H "X-API-Key: $SIM_API_KEY" \
      -H 'Content-Type: application/json' \
      -d '{"input":{"message":"Summarize this article"}}'
    ```
  </Tab>

  <Tab value="Python">
    ```python
    import os
    import requests

    response = requests.post(
        "https://www.sim.ai/api/v2/workflows/{workflow-id}/execute",
        headers={"X-API-Key": os.environ["SIM_API_KEY"]},
        json={"input": {"message": "Summarize this article"}},
    )
    response.raise_for_status()
    print(response.json())
    ```
  </Tab>

  <Tab value="TypeScript">
    ```typescript
    const apiKey = process.env.SIM_API_KEY
    if (!apiKey) throw new Error('Set SIM_API_KEY')

    const response = await fetch('https://www.sim.ai/api/v2/workflows/{workflow-id}/execute', {
      method: 'POST',
      headers: { 'X-API-Key': apiKey, 'Content-Type': 'application/json' },
      body: JSON.stringify({ input: { message: 'Summarize this article' } })
    })
    if (!response.ok) throw new Error(`HTTP ${response.status}`)
    const result = await response.json()
    process.stdout.write(JSON.stringify(result))
    ```
  </Tab>
</Tabs>

V2 returns a run resource in `data`, including `runId`, `workflowId`, `status`, `output`, `blockOutputs`, `error`, and timing fields. Check `data.status`: a workflow that ran and failed can return HTTP `200` with `status: "failed"`. An HTTP error instead describes a rejected request or a service failure.

A [Response block](/workflows/blocks/response) selects the workflow result, which remains inside `data.output`. It cannot override the v2 endpoint's HTTP status, headers, or envelope.

A synchronous caller can request `Accept: application/x-ndjson` to receive heartbeat frames while waiting, followed by a `type: "final"` frame containing the same run resource. This is distinct from Agent token streaming with `stream: true`.

### Streaming [#streaming]

Set `stream: true` and use `selectedOutputs` to select fields. **Select outputs** in the API tab groups fields by block; `content` from an Agent is a common choice.

Selectors use a stable block ID or normalized block name followed by a field path, such as `agent.content` for a block named Agent. Nested paths and reachable child-workflow selectors are also supported; see [Execute workflow](/api-reference/workflows/executeWorkflowV2).

For live answer tokens, send `X-Sim-Stream-Protocol: agent-events-v1` and handle `chunk_reset`. Without that header, answer text arrives after a final model turn settles. The header alone does not expose thinking or tool events.

<Tabs items="['cURL', 'Python', 'TypeScript']">
  <Tab value="cURL">
    ```bash
    curl -N -X POST 'https://www.sim.ai/api/v2/workflows/{workflow-id}/execute' \
      -H "X-API-Key: $SIM_API_KEY" \
      -H 'Content-Type: application/json' \
      -H 'X-Sim-Stream-Protocol: agent-events-v1' \
      -d '{"input":{"message":"Write a long essay"},"stream":true,"selectedOutputs":["agent.content"]}'
    ```
  </Tab>

  <Tab value="Python">
    ```python
    import os
    import requests

    with requests.post(
        "https://www.sim.ai/api/v2/workflows/{workflow-id}/execute",
        headers={
            "X-API-Key": os.environ["SIM_API_KEY"],
            "X-Sim-Stream-Protocol": "agent-events-v1",
        },
        json={
            "input": {"message": "Write a long essay"},
            "stream": True,
            "selectedOutputs": ["agent.content"],
        },
        stream=True,
    ) as response:
        response.raise_for_status()
        for line in response.iter_lines():
            if line:
                print(line.decode())
    ```
  </Tab>

  <Tab value="TypeScript">
    ```typescript
    const apiKey = process.env.SIM_API_KEY
    if (!apiKey) throw new Error('Set SIM_API_KEY')

    const response = await fetch('https://www.sim.ai/api/v2/workflows/{workflow-id}/execute', {
      method: 'POST',
      headers: {
        'X-API-Key': apiKey,
        'Content-Type': 'application/json',
        'X-Sim-Stream-Protocol': 'agent-events-v1'
      },
      body: JSON.stringify({
        input: { message: 'Write a long essay' },
        stream: true,
        selectedOutputs: ['agent.content']
      })
    })
    if (!response.ok) throw new Error(`HTTP ${response.status}`)
    if (!response.body) throw new Error('Response body is missing')

    const reader = response.body.getReader()
    const decoder = new TextDecoder()
    try {
      while (true) {
        const { done, value } = await reader.read()
        if (done) break
        process.stdout.write(decoder.decode(value, { stream: true }))
      }
    } finally {
      reader.releaseLock()
    }
    ```
  </Tab>
</Tabs>

These examples print raw SSE for inspection. For an application, parse frames, accumulate answers per `blockId`, and honor resets and terminal errors using the [stream reference client](/workflows/deployment/agent-events#reference-client).

#### Streaming agent thinking and tool calls [#streaming-agent-thinking-and-tool-calls]

Add independent `includeThinking` and `includeToolCalls` flags:

```bash
curl -N -X POST 'https://www.sim.ai/api/v2/workflows/{workflow-id}/execute' \
  -H "X-API-Key: $SIM_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'X-Sim-Stream-Protocol: agent-events-v1' \
  -d '{"input":{"message":"Research this topic"},"stream":true,"selectedOutputs":["agent.content"],"includeThinking":true,"includeToolCalls":true}'
```

Both flags default false. Enabling either without `stream: true` and the protocol header returns `400`. Tool lifecycle frames contain names and status; full tool arguments/results can appear in the authenticated API's terminal envelope. Thinking support varies by model. See [Agent stream events](/workflows/deployment/agent-events) for the contract.

### Asynchronous [#asynchronous]

Set `async: true` to receive HTTP `202` with a run ID and status URL instead of holding the connection open:

```bash
curl -X POST 'https://www.sim.ai/api/v2/workflows/{workflow-id}/execute' \
  -H "X-API-Key: $SIM_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"input":{"message":"Process this dataset"},"async":true,"executionTimeoutSeconds":3600}'
```

```json
{
  "data": {
    "runId": "c7a92e15-3f4b-4d8c-a1e6-9b0d5f2c8e74",
    "statusUrl": "https://www.sim.ai/api/v2/workflows/{workflow-id}/runs/c7a92e15-3f4b-4d8c-a1e6-9b0d5f2c8e74"
  }
}
```

Async execution requires an API key or OAuth token and uses the deployed version. It cannot be combined with `stream`, manual draft execution, partial-run options, or streaming/output-shaping options such as `selectedOutputs` and `includeThinking`.

`executionTimeoutSeconds` accepts an integer from `1` to `604800` and is supported only with `async: true`. The effective limit is the smaller of that value and the account policy; it cannot extend the policy. Your HTTP client's timeout is separate.

Poll the returned run URL, requesting output when needed:

```bash
curl 'https://www.sim.ai/api/v2/workflows/{workflow-id}/runs/{runId}?includeOutput=true' \
  -H "X-API-Key: $SIM_API_KEY"
```

A completed response includes the result when requested:

```json
{
  "data": {
    "runId": "c7a92e15-3f4b-4d8c-a1e6-9b0d5f2c8e74",
    "workflowId": "{workflow-id}",
    "status": "completed",
    "startedAt": "2026-10-13T12:00:01.000Z",
    "endedAt": "2026-10-13T12:00:05.000Z",
    "durationMs": 4000,
    "output": { "result": "..." }
  }
}
```

#### Execution status values [#execution-status-values]

| Status | Meaning |
| - | - |
| `queued` | Waiting to be picked up |
| `pending` | Durable record exists; execution has not started |
| `running` | Executing |
| `paused` | Waiting for a resume condition or submitted input |
| `redacting` | Finished execution; output is still being scrubbed |
| `completed` | Finished successfully |
| `failed` | Failed; inspect `error` |
| `cancelled` | Cancelled |

Stop polling on `completed`, `failed`, or `cancelled`. A paused Human run requires submitted input; a time pause can resume automatically. See [Human](/workflows/blocks/human-in-the-loop) and [Wait](/workflows/blocks/wait). Resuming an originally streaming run through the v2 resume endpoint returns an async receipt, not an SSE continuation.

## Select outputs and handle large values [#oversized-outputs]

`selectedOutputs` can project smaller fields. For a synchronous v2 call, selected values appear in `data.blockOutputs`, separately from `data.output`.

Oversized nested values in outputs, logs, streamed fields, or async status payloads may be replaced with a versioned reference:

```json
{
  "__simLargeValueRef": true,
  "version": 1,
  "id": "lv_abc123DEF456",
  "kind": "array",
  "size": 12582912,
  "key": "execution/workspace-id/workflow-id/c7a92e15-3f4b-4d8c-a1e6-9b0d5f2c8e74/large-value-lv_abc123DEF456.json",
  "executionId": "c7a92e15-3f4b-4d8c-a1e6-9b0d5f2c8e74",
  "preview": { "length": 25000 }
}
```

Treat this as an opaque placeholder. `version` is part of the contract; `id`, `key`, and `executionId` are not fetch URLs. Reduce the payload or select a smaller field. A Response block remains subject to the v2 response contract and size limits.

File outputs contain metadata by default; request inline base64 only when needed. JavaScript Function code can read large files, value references, and manifest-backed arrays with `sim.files` and `sim.values` under memory caps. See [Function](/workflows/blocks/function).

## Manual draft execution [#manual-draft-execution]

V2 supports explicit `run.source: "manual"` for a personal API-key or OAuth caller with Write access. Workspace keys and anonymous callers cannot use it. Choose `run.entry.blockId` when several triggers are runnable; mock payloads and explicit input cannot be combined.

Manual mode uses the saved draft and supports sync or streaming, not async. Run-from-block and stop-after options have additional validation. See [Execute workflow](/api-reference/workflows/executeWorkflowV2) for the full request.

## Limits and recovery [#limits-and-recovery]

### Execution time limits [#execution-time-limits]

See [run duration](/workflows/how-it-runs#how-long-a-run-can-take) for current billing-enabled defaults and self-hosted configuration. Async callers can shorten, but never extend, the account policy.

### Execution retention [#execution-retention]

Completed and failed runs are read from execution logs and follow the effective [data retention policy](/platform/enterprise/data-retention).

### Capacity limits [#capacity-limits]

A request rejected for rate or capacity limits can return `429` or `503`. V2 uses a structured error envelope, for example:

```json
{
  "error": {
    "code": "RATE_LIMITED",
    "message": "Server is at capacity. Please retry shortly."
  }
}
```

Use the HTTP status and `Retry-After` header for retry timing. If an async enqueue outcome is uncertain and the error includes a run ID, reconcile that run before repeating a request. `X-Run-Id` claims are one-shot identifiers, not cached-response replay keys; a conflict or missing run does not prove the first call had no effects.

### Rate limits [#rate-limits]

Plan and deployment policy govern rate and concurrent execution limits. `X-RateLimit-*` headers describe the applicable request limit. Async mode remains subject to admission and execution limits; it does not bypass them.

### API key management [#api-key-management]

Revoke a compromised key in **Settings → Sim API keys**, create a replacement, and update callers. Use separate keys for applications or environments and the appropriate personal/workspace scope. See [authentication](/api-reference/authentication) for key lifecycle and access.

## Related docs [#related-docs]

* [Deployment versions](/workflows/deployment) for tracking changes, promotion, and API deployment management
* [Agent stream events](/workflows/deployment/agent-events)
* [Execute workflow](/api-reference/workflows/executeWorkflowV2)
* [API getting started](/api-reference/getting-started)
