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
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ This returns immediately with a `jobId` and `statusUrl`:
}
```

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

```bash
curl https://www.sim.ai/api/jobs/{jobId} \
Expand Down
9 changes: 7 additions & 2 deletions apps/docs/content/docs/de/api-reference/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"title": "API Reference",
"root": true,
"pages": [
"---Getting Started---",
"getting-started",
"authentication",
"---SDKs---",
Expand All @@ -10,9 +11,13 @@
"---Endpoints---",
"(generated)/workflows",
"(generated)/logs",
"(generated)/usage",
"(generated)/audit-logs",
"(generated)/tables",
"(generated)/files"
"(generated)/files",
"(generated)/knowledge-bases",
"---Execution and Usage---",
"(generated)/execution",
"(generated)/human-in-the-loop",
"(generated)/usage"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"pages": ["executeWorkflow", "getWorkflowExecution", "cancelExecution", "getJobStatus"]
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
{
"pages": [
"executeWorkflow",
"getWorkflowExecution",
"cancelExecution",
"listWorkflows",
"getWorkflow",
"deployWorkflow",
"undeployWorkflow",
"rollbackWorkflow",
"getJobStatus"
"rollbackWorkflow"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ This returns immediately with a `jobId` and `statusUrl`:
}
```

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

```bash
curl https://www.sim.ai/api/jobs/{jobId} \
Expand Down
8 changes: 5 additions & 3 deletions apps/docs/content/docs/en/api-reference/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
"typescript",
"---Endpoints---",
"(generated)/workflows",
"(generated)/human-in-the-loop",
"(generated)/logs",
"(generated)/usage",
"(generated)/audit-logs",
"(generated)/tables",
"(generated)/files",
"(generated)/knowledge-bases"
"(generated)/knowledge-bases",
"---Execution and Usage---",
"(generated)/execution",
"(generated)/human-in-the-loop",
"(generated)/usage"
]
}
13 changes: 10 additions & 3 deletions apps/docs/content/docs/en/platform/enterprise/audit-logs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Audit logs are also accessible through the Sim API for integration with external

```http
GET /api/v1/audit-logs
Authorization: Bearer <api-key>
X-API-Key: <api-key>
```

**Query parameters:**
Expand Down Expand Up @@ -71,11 +71,18 @@ Authorization: Bearer <api-key>
"createdAt": "2026-04-20T21:16:00.000Z"
}
],
"nextCursor": "eyJpZCI6ImFiYzEyMyJ9"
"nextCursor": "eyJpZCI6ImFiYzEyMyJ9",
"limits": {
"workflowExecutionRateLimit": {
"sync": { "requestsPerMinute": 60, "maxBurst": 10, "remaining": 59, "resetAt": "2026-04-20T21:17:00.000Z" },
"async": { "requestsPerMinute": 30, "maxBurst": 5, "remaining": 30, "resetAt": "2026-04-20T21:17:00.000Z" }
},
"usage": { "currentPeriodCost": 1.25, "limit": 50, "plan": "enterprise", "isExceeded": false }
}
}
```

Paginate by passing the `nextCursor` value as the `cursor` parameter in the next request. When `nextCursor` is absent, you have reached the last page.
Paginate by passing the `nextCursor` value as the `cursor` parameter in the next request. When `nextCursor` is absent, you have reached the last page. Each entry also includes `actorName`; `metadata` is an arbitrary per-action JSON object. The `limits` object reports your current rate-limit and usage status.

The API accepts both personal and workspace-scoped API keys. Rate limits apply — the response includes `X-RateLimit-*` headers with your current limit and remaining quota.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ This returns immediately with a `jobId` and `statusUrl`:
}
```

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

```bash
curl https://www.sim.ai/api/jobs/{jobId} \
Expand Down
11 changes: 9 additions & 2 deletions apps/docs/content/docs/es/api-reference/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"title": "API Reference",
"root": true,
"pages": [
"---Getting Started---",
"getting-started",
"authentication",
"---SDKs---",
Expand All @@ -10,7 +11,13 @@
"---Endpoints---",
"(generated)/workflows",
"(generated)/logs",
"(generated)/usage",
"(generated)/audit-logs"
"(generated)/audit-logs",
"(generated)/tables",
"(generated)/files",
"(generated)/knowledge-bases",
"---Execution and Usage---",
"(generated)/execution",
"(generated)/human-in-the-loop",
"(generated)/usage"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ This returns immediately with a `jobId` and `statusUrl`:
}
```

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

```bash
curl https://www.sim.ai/api/jobs/{jobId} \
Expand Down
11 changes: 9 additions & 2 deletions apps/docs/content/docs/fr/api-reference/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"title": "API Reference",
"root": true,
"pages": [
"---Getting Started---",
"getting-started",
"authentication",
"---SDKs---",
Expand All @@ -10,7 +11,13 @@
"---Endpoints---",
"(generated)/workflows",
"(generated)/logs",
"(generated)/usage",
"(generated)/audit-logs"
"(generated)/audit-logs",
"(generated)/tables",
"(generated)/files",
"(generated)/knowledge-bases",
"---Execution and Usage---",
"(generated)/execution",
"(generated)/human-in-the-loop",
"(generated)/usage"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ This returns immediately with a `jobId` and `statusUrl`:
}
```

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

```bash
curl https://www.sim.ai/api/jobs/{jobId} \
Expand Down
11 changes: 9 additions & 2 deletions apps/docs/content/docs/ja/api-reference/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"title": "API Reference",
"root": true,
"pages": [
"---Getting Started---",
"getting-started",
"authentication",
"---SDKs---",
Expand All @@ -10,7 +11,13 @@
"---Endpoints---",
"(generated)/workflows",
"(generated)/logs",
"(generated)/usage",
"(generated)/audit-logs"
"(generated)/audit-logs",
"(generated)/tables",
"(generated)/files",
"(generated)/knowledge-bases",
"---Execution and Usage---",
"(generated)/execution",
"(generated)/human-in-the-loop",
"(generated)/usage"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ This returns immediately with a `jobId` and `statusUrl`:
}
```

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

```bash
curl https://www.sim.ai/api/jobs/{jobId} \
Expand Down
11 changes: 9 additions & 2 deletions apps/docs/content/docs/zh/api-reference/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"title": "API Reference",
"root": true,
"pages": [
"---Getting Started---",
"getting-started",
"authentication",
"---SDKs---",
Expand All @@ -10,7 +11,13 @@
"---Endpoints---",
"(generated)/workflows",
"(generated)/logs",
"(generated)/usage",
"(generated)/audit-logs"
"(generated)/audit-logs",
"(generated)/tables",
"(generated)/files",
"(generated)/knowledge-bases",
"---Execution and Usage---",
"(generated)/execution",
"(generated)/human-in-the-loop",
"(generated)/usage"
]
}
80 changes: 60 additions & 20 deletions apps/docs/lib/openapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,17 @@ import { readFileSync } from 'node:fs'
import { join } from 'node:path'
import { createOpenAPI } from 'fumadocs-openapi/server'

const SPEC_FILES = [
'openapi-core.json',
'openapi-v2-logs.json',
'openapi-v2-workflows.json',
'openapi-v2-tables.json',
'openapi-v2-knowledge.json',
'openapi-v2-files-audit.json',
] as const

export const openapi = createOpenAPI({
input: ['./openapi.json'],
input: SPEC_FILES.map((file) => `./${file}`),
})

interface OpenAPIOperation {
Expand All @@ -24,20 +33,34 @@ function resolveRef(ref: string, spec: Record<string, unknown>): unknown {
return current
}

function resolveRefs(obj: unknown, spec: Record<string, unknown>, depth = 0): unknown {
if (depth > 10) return obj
function resolveRefs(
obj: unknown,
spec: Record<string, unknown>,
seen: Set<string> = new Set(),
depth = 0
): unknown {
// Generous backstop against pathological fan-out; real schemas nest far shallower.
if (depth > 50) return obj
if (Array.isArray(obj)) {
return obj.map((item) => resolveRefs(item, spec, depth + 1))
return obj.map((item) => resolveRefs(item, spec, seen, depth + 1))
}
if (obj && typeof obj === 'object') {
const record = obj as Record<string, unknown>
if ('$ref' in record && typeof record.$ref === 'string') {
const resolved = resolveRef(record.$ref, spec)
return resolveRefs(resolved, spec, depth + 1)
if (typeof record.$ref === 'string') {
const ref = record.$ref
// Break reference cycles: if this $ref is already being expanded above us,
// leave it untouched instead of recursing forever.
if (seen.has(ref)) return record
const resolved = resolveRef(ref, spec)
if (resolved === undefined) return record
seen.add(ref)
const out = resolveRefs(resolved, spec, seen, depth + 1)
seen.delete(ref)
return out
}
const result: Record<string, unknown> = {}
for (const [key, value] of Object.entries(record)) {
result[key] = resolveRefs(value, spec, depth + 1)
result[key] = resolveRefs(value, spec, seen, depth + 1)
}
return result
}
Expand All @@ -48,37 +71,54 @@ function formatSchema(schema: unknown): string {
return JSON.stringify(schema, null, 2)
}

let cachedSpec: Record<string, unknown> | null = null
let cachedSpecs: Record<string, unknown>[] | null = null

function getSpecs(): Record<string, unknown>[] {
if (!cachedSpecs) {
cachedSpecs = SPEC_FILES.map(
(file) =>
JSON.parse(readFileSync(join(process.cwd(), file), 'utf8')) as Record<string, unknown>
)
}
return cachedSpecs
}

function getSpec(): Record<string, unknown> {
if (!cachedSpec) {
const specPath = join(process.cwd(), 'openapi.json')
cachedSpec = JSON.parse(readFileSync(specPath, 'utf8')) as Record<string, unknown>
/**
* Locate an operation by path + method across every rendered spec, returning the
* operation together with the spec that owns it so `$ref`s resolve within the
* correct document (each spec carries its own `components`).
*/
function findOperation(
path: string,
method: string
): { operation: Record<string, unknown>; spec: Record<string, unknown> } | undefined {
const key = method.toLowerCase()
for (const spec of getSpecs()) {
const pathObj = (spec.paths as Record<string, Record<string, unknown>> | undefined)?.[path]
const operation = pathObj?.[key] as Record<string, unknown> | undefined
if (operation) return { operation, spec }
}
return cachedSpec
return undefined
}

export function getApiSpecContent(
title: string,
description: string | undefined,
operations: OpenAPIOperation[]
): string {
const spec = getSpec()

if (!operations || operations.length === 0) {
return `# ${title}\n\n${description || ''}`
}

const op = operations[0]
const method = op.method.toUpperCase()
const pathObj = (spec.paths as Record<string, Record<string, unknown>>)?.[op.path]
const operation = pathObj?.[op.method.toLowerCase()] as Record<string, unknown> | undefined
const found = findOperation(op.path, op.method)

if (!operation) {
if (!found) {
return `# ${title}\n\n${description || ''}`
}

const resolved = resolveRefs(operation, spec) as Record<string, unknown>
const resolved = resolveRefs(found.operation, found.spec) as Record<string, unknown>
const lines: string[] = []

lines.push(`# ${title}`)
Expand Down
Loading
Loading