From 3335d624573749d4063aa85662c6a655143e507a Mon Sep 17 00:00:00 2001 From: Java Julian Date: Mon, 28 Sep 2026 10:44:17 -0400 Subject: [PATCH] docs: Refine documentation for workflow recovery and tool alignment - Updated CONTENT-ALIGNMENT.md to enhance clarity on workflow behavior and layout, including save recovery procedures. - Revised copilot.mdx with instructions for managing failed saves and conflict resolution. - Clarified saving processes in workflows.mdx and emphasized layout metadata in introduction.mdx and cli.mdx. - Improved consistency and user guidance across multiple documentation files. --- .gitignore | 3 +- API-REFERENCE-REVIEW.md | 28 + content/docs/api-reference/authentication.mdx | 80 + content/docs/api-reference/authoring.mdx | 45 + .../endpoints/authoring-context.mdx | 34 + .../endpoints/configure-trigger.mdx | 78 + .../endpoints/create-workflow.mdx | 54 + .../endpoints/delete-workflow.mdx | 35 + .../endpoints/deploy-workflow.mdx | 37 + .../endpoints/duplicate-workflow.mdx | 55 + .../endpoints/execute-workflow.mdx | 61 + .../endpoints/execution-logs.mdx | 38 + .../endpoints/execution-payload.mdx | 37 + .../api-reference/endpoints/get-execution.mdx | 36 + .../api-reference/endpoints/get-node-type.mdx | 36 + .../api-reference/endpoints/get-openapi.mdx | 29 + .../api-reference/endpoints/get-operation.mdx | 35 + .../api-reference/endpoints/get-workflow.mdx | 37 + .../endpoints/import-workflow.mdx | 167 ++ .../docs/api-reference/endpoints/index.mdx | 67 + .../endpoints/list-connections.mdx | 37 + .../endpoints/list-executions.mdx | 38 + .../endpoints/list-node-types.mdx | 37 + .../endpoints/list-workflows.mdx | 37 + .../endpoints/list-workspaces.mdx | 34 + .../docs/api-reference/endpoints/meta.json | 37 + .../api-reference/endpoints/node-options.mdx | 39 + .../api-reference/endpoints/patch-graph.mdx | 291 ++ .../endpoints/undeploy-workflow.mdx | 37 + .../endpoints/update-workflow.mdx | 66 + .../endpoints/validate-workflow.mdx | 35 + content/docs/api-reference/errors.mdx | 65 + content/docs/api-reference/executions.mdx | 107 + content/docs/api-reference/introduction.mdx | 105 +- content/docs/api-reference/meta.json | 6 +- content/docs/api-reference/workflows.mdx | 150 + package.json | 5 +- public/openapi.json | 2424 +++++++++++++++++ scripts/api/catalog.mjs | 35 + scripts/api/request-schemas.json | 374 +++ scripts/api/source-manifest.json | 34 + scripts/sync-api-reference.mjs | 61 + scripts/verify-build.mjs | 4 +- 43 files changed, 4989 insertions(+), 61 deletions(-) create mode 100644 API-REFERENCE-REVIEW.md create mode 100644 content/docs/api-reference/authentication.mdx create mode 100644 content/docs/api-reference/authoring.mdx create mode 100644 content/docs/api-reference/endpoints/authoring-context.mdx create mode 100644 content/docs/api-reference/endpoints/configure-trigger.mdx create mode 100644 content/docs/api-reference/endpoints/create-workflow.mdx create mode 100644 content/docs/api-reference/endpoints/delete-workflow.mdx create mode 100644 content/docs/api-reference/endpoints/deploy-workflow.mdx create mode 100644 content/docs/api-reference/endpoints/duplicate-workflow.mdx create mode 100644 content/docs/api-reference/endpoints/execute-workflow.mdx create mode 100644 content/docs/api-reference/endpoints/execution-logs.mdx create mode 100644 content/docs/api-reference/endpoints/execution-payload.mdx create mode 100644 content/docs/api-reference/endpoints/get-execution.mdx create mode 100644 content/docs/api-reference/endpoints/get-node-type.mdx create mode 100644 content/docs/api-reference/endpoints/get-openapi.mdx create mode 100644 content/docs/api-reference/endpoints/get-operation.mdx create mode 100644 content/docs/api-reference/endpoints/get-workflow.mdx create mode 100644 content/docs/api-reference/endpoints/import-workflow.mdx create mode 100644 content/docs/api-reference/endpoints/index.mdx create mode 100644 content/docs/api-reference/endpoints/list-connections.mdx create mode 100644 content/docs/api-reference/endpoints/list-executions.mdx create mode 100644 content/docs/api-reference/endpoints/list-node-types.mdx create mode 100644 content/docs/api-reference/endpoints/list-workflows.mdx create mode 100644 content/docs/api-reference/endpoints/list-workspaces.mdx create mode 100644 content/docs/api-reference/endpoints/meta.json create mode 100644 content/docs/api-reference/endpoints/node-options.mdx create mode 100644 content/docs/api-reference/endpoints/patch-graph.mdx create mode 100644 content/docs/api-reference/endpoints/undeploy-workflow.mdx create mode 100644 content/docs/api-reference/endpoints/update-workflow.mdx create mode 100644 content/docs/api-reference/endpoints/validate-workflow.mdx create mode 100644 content/docs/api-reference/errors.mdx create mode 100644 content/docs/api-reference/executions.mdx create mode 100644 content/docs/api-reference/workflows.mdx create mode 100644 public/openapi.json create mode 100644 scripts/api/catalog.mjs create mode 100644 scripts/api/request-schemas.json create mode 100644 scripts/api/source-manifest.json create mode 100644 scripts/sync-api-reference.mjs diff --git a/.gitignore b/.gitignore index 9e429e4..fd4455d 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,5 @@ yarn-error.log* # others .env*.local .vercel -next-env.d.ts \ No newline at end of file +next-env.d.ts +.env* diff --git a/API-REFERENCE-REVIEW.md b/API-REFERENCE-REVIEW.md new file mode 100644 index 0000000..7781f3b --- /dev/null +++ b/API-REFERENCE-REVIEW.md @@ -0,0 +1,28 @@ +# REST API reference review — September 28, 2026 + +## Scope and evidence + +Extended the existing Fumadocs API section with authentication/workspace guidance, workflows, executions, authoring, errors/retries, a complete endpoint index, endpoint pages, and a downloadable OpenAPI reference snapshot. Preserved existing introduction and CLI URLs. + +Reviewed application source at `3782e045` in `/Users/julianpatrick/Developer/innflow`: all customer-facing `/api/v1` route handlers, shared API contracts, bearer/workspace authentication, proxy limits, response replay, and authoring operation receipts. Coverage is 25 HTTP operations. The portal event service-ingestion route and non-public application routes are outside customer API coverage. + +Live read-only checks found the application OpenAPI endpoint reachable and serving the core subset. This is not an authenticated end-to-end test of every endpoint or proof that gated authoring is enabled in production. + +## Corrections + +- Explicit workspace selection: `personal` restricts personal resources; omission retains legacy user-owned scope. +- Core create/import/duplicate/execute response replay is distinct from authoring transaction receipts. Deploy/undeploy do not have API-key response replay. +- Execution dispatch is not completion; use the returned execution ID. +- Read graph connections differ from import index-based edges. +- Rate-limit proxy errors differ from application error envelopes. + +## Validation + +- `npm run api:source-check`: passed, all 25 operations and recorded source fingerprints. +- `npm run check`: passed. +- `npm run build`: passed. +- `npm run verify`: passed, 91 content pages and 113 local targets, navigation, search, and 404 behavior. +- `git diff --check`: passed. +- `npm run docs:check`: existing generated integration-tool reference/snapshot drift against current app source. The REST reference does not change that catalog; no unrelated tool catalog regeneration was included. + +Public MDX is not an input to the app's current Copilot retrieval corpus. No Qdrant update or application deployment is required for these documentation changes. diff --git a/content/docs/api-reference/authentication.mdx b/content/docs/api-reference/authentication.mdx new file mode 100644 index 0000000..51a0f07 --- /dev/null +++ b/content/docs/api-reference/authentication.mdx @@ -0,0 +1,80 @@ +--- +title: 'Authentication and errors' +description: 'API keys, workspace permissions, retries, pagination and rate limits' +--- + +## API keys + +Create an API key under **Settings → API Keys**. Send it with every authenticated REST request: + +```http +Authorization: Bearer inf_sk_your_key +``` + +Keep keys on your server. Do not embed them in browser JavaScript, commit them to a repository or include them in public URLs. [Manage API keys](/features/api-keys). + +The CLI can also use a browser-login session token. MCP OAuth uses the same routes with its own scopes and contract behavior; see [authoring](/api-reference/authoring). + +## Workspaces and permissions + +Select a workspace explicitly. `X-Innflow-Workspace: personal` restricts resource reads to your personal workspace. Omitting the header uses legacy user-owned resource scope, which can also include organization resources you created. To select an organization you belong to, pass its ID: + +```http +X-Innflow-Workspace: organization_id +``` + +Use [List workspaces](/api-reference/endpoints/list-workspaces) to discover IDs and roles. Permission checks are endpoint-specific: workflows use read/write/execute actions; execution reads use `executions:read`; workspace discovery uses `workspaces:read`. Organization members with read-only roles cannot mutate or execute workflows. A key does not grant access to another user's resources. + +## Request and response format + +Send `Content-Type: application/json` with JSON bodies. Most successful responses wrap results in `data`. List workflows and List executions also return `pagination` with `page`, `pageSize`, `totalCount` and `totalPages`. Their default page size is 20 and maximum is 100. + +Catalog and log endpoints use `data.items` with `nextPage`; field options and payloads use `nextCursor`. Follow the endpoint-specific format rather than assuming one pagination envelope for every route. + +## Idempotency and retries + +| Operations | API-key behavior | +| --- | --- | +| Create, import, duplicate, execute | Optional `Idempotency-Key`; matching requests replay saved responses for 24 hours | +| Graph patch, trigger configuration | Required operation key; receipts are transactional | +| Update, delete, deploy, undeploy | No generic idempotency replay guarantee | + +Optional keys have a maximum length of 200 characters. Required authoring keys must contain 1–200 letters, digits, dots, colons, underscores or hyphens. Reusing a key with a different request body returns `409`. Replays include `X-Idempotent-Replayed: true`. Keys are scoped to the authenticated principal, workspace and route. + +For ordinary optional-key writes, expired receipts can be replaced after 24 hours. For transactional authoring, an expired receipt returns `IDEMPOTENCY_EXPIRED`; inspect the workflow before starting another operation. + +Optional-key response replay is not an exactly-once guarantee: concurrent first requests or a failure before receipt persistence can repeat work. Serialize retries and inspect ambiguous outcomes. + +On a network failure, retry eligible writes with the same key and the exact same body. Use backoff for reads and honor `Retry-After` on rate limits. Inspect resource state before repeating a write without idempotency support. + +## Errors + +Application handler errors generally include: + +```json +{ + "error": "Workflow not found", + "code": "NOT_FOUND", + "requestId": "request_identifier" +} +``` + +Some errors include `details`. Handler responses include `X-Request-Id`; retain it when asking support about a request. Proxy failures can have a different envelope. + +| Status | Meaning and action | +| --- | --- | +| 400 | Invalid JSON, parameters, cursor or missing required idempotency key; correct the request | +| 401 | Missing/invalid credentials or unavailable workspace; check key and workspace | +| 403 | Insufficient permission or workspace role | +| 404 | Resource not found or not accessible to this principal | +| 409 | Idempotency or revision conflict; inspect state before retrying | +| 422 | Configuration or workflow state does not allow the operation | +| 429 | Rate limited; wait for `Retry-After` | +| 500 | Unexpected server failure; retain request ID and retry only when safe | +| 503 | Authoring unavailable when code is `AUTHORING_DISABLED` | + +## Rate limits + +The application proxy currently applies 60 requests per minute per client IP and route pathname to `/api/v1`. This is a process-local guard, not a guaranteed account-wide quota. Additional credential or infrastructure limits may apply. + +Proxy responses expose `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset` (Unix milliseconds). A proxy `429` also includes `Retry-After` in seconds. Build clients around response headers rather than a fixed request rate. diff --git a/content/docs/api-reference/authoring.mdx b/content/docs/api-reference/authoring.mdx new file mode 100644 index 0000000..b245796 --- /dev/null +++ b/content/docs/api-reference/authoring.mdx @@ -0,0 +1,45 @@ +--- +title: 'Workflow authoring' +description: 'Discover schemas, edit graphs safely and configure triggers through REST' +--- + +## Check availability + +Read [Get authoring context](/api-reference/endpoints/authoring-context). Graph patching and trigger configuration require `authoringEnabled: true`; unavailable authoring returns `503 AUTHORING_DISABLED`. This documentation release does not enable authoring on your deployment. + +## Build from the node catalog + +1. [Search node types](/api-reference/endpoints/list-node-types) to find a type and its operations. +2. [Get its schema](/api-reference/endpoints/get-node-type) for field definitions, outputs and connection handles. +3. [List connections](/api-reference/endpoints/list-connections) using the provider ID returned by the schema. Connect new accounts through Innflow's UI. +4. [Create a workflow](/api-reference/endpoints/create-workflow) or [import a complete graph](/api-reference/endpoints/import-workflow). +5. [Get the workflow](/api-reference/endpoints/get-workflow) and retain `graphRevision` as `expectedRevision`. +6. [Patch the graph](/api-reference/endpoints/patch-graph) with a unique `Idempotency-Key` and up to 25 operations. +7. [Configure triggers](/api-reference/endpoints/configure-trigger), then [validate](/api-reference/endpoints/validate-workflow) before deploying. + +## Graph operations + +| Operation | Required fields beyond operation | +| --- | --- | +| `addNode` | `ref`, `type`; optional `name`, `position`, `data` | +| `configureNode` | `nodeId`, `data` | +| `removeNode` | `nodeId` | +| `moveNode` | `nodeId`, `position` | +| `connect` | `source`, `target`; optional `sourceHandle`, `targetHandle` (default `main`) | +| `disconnect` | `source`, `target`; optional `sourceHandle`, `targetHandle` (default `main`) | + +Temporary `ref` values identify added nodes within a patch; the response's `nodeIds` maps them to saved IDs. Read the full [graph request schema](/api-reference/endpoints/patch-graph) for constraints. Use handles returned by the node schema. + +A revision conflict means another edit occurred. Refetch the graph, reconcile the intended change and submit with the new revision and a new operation key. Do not blindly overwrite another editor's work. + +## Provider setup and execution + +A trigger response can report `needs_input`, `provider_handoff` or `pending` rather than `configured`. Inspect `persisted`, `missing` and `instructions` before treating setup as complete. Dynamic field selectors may return `handoffUrl` for editor-only setup. + +Execution is asynchronous. Use the execution ID to read progress and the operation ID, when returned, to inspect its dispatch receipt. + +## MCP OAuth contract + +MCP clients authenticate with OAuth and send `X-Innflow-MCP-Contract: 1`. On that authenticated contract, create, deploy, undeploy and execute use transactional operation receipts with a required idempotency key. Setting the header on a normal API-key request does not switch it into the MCP OAuth contract. + +MCP deploy/undeploy accept an optional nonnegative `expectedRevision`. MCP execution and deferred deployment work can return `202`, with `operationId` and `idempotencyKey` alongside `data`. Poll [Get operation receipt](/api-reference/endpoints/get-operation). These semantics differ from the normal API-key endpoints; see the [MCP reference](/mcp) for client setup. diff --git a/content/docs/api-reference/endpoints/authoring-context.mdx b/content/docs/api-reference/endpoints/authoring-context.mdx new file mode 100644 index 0000000..964a083 --- /dev/null +++ b/content/docs/api-reference/endpoints/authoring-context.mdx @@ -0,0 +1,34 @@ +--- +title: 'Get authoring context' +description: 'GET /mcp/context' +--- + +Inspect the authenticated principal and authoring availability. + + +```http +GET /api/v1/mcp/context +``` + +**Permission:** `workflows:read`. Write endpoints also require a workspace role that permits changes. See [authentication](/api-reference/authentication) and [errors](/api-reference/errors). + +## Request + +```bash +curl --request GET 'https://app.innflow.ai/api/v1/mcp/context' \ + --header "Authorization: Bearer $INNFLOW_API_KEY" +``` + +Examples use placeholder IDs. Set `INNFLOW_API_KEY` in your shell and replace IDs with your own before sending a request. + +## Parameters + +| Name | In | Required | Details | +| --- | --- | --- | --- | +| `X-Innflow-Workspace` | header | No | Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope. | + +## Response + +**HTTP 200** — Returns data with workspace, userId, role, permissions, authoringEnabled and contractVersion. Check authoringEnabled before graph or trigger mutations. + +See [OpenAPI download](/openapi.json) for the machine-readable request contract and [errors](/api-reference/errors) for errors and retry behavior. diff --git a/content/docs/api-reference/endpoints/configure-trigger.mdx b/content/docs/api-reference/endpoints/configure-trigger.mdx new file mode 100644 index 0000000..7f1ed8d --- /dev/null +++ b/content/docs/api-reference/endpoints/configure-trigger.mdx @@ -0,0 +1,78 @@ +--- +title: 'Configure trigger' +description: 'POST /workflows/{workflowId}/trigger' +--- + +Configure a trigger on a saved graph using its nodeId and expectedRevision. Requires authoring to be enabled. Configuration fields depend on the trigger type; obtain its node schema first. + + +```http +POST /api/v1/workflows/{workflowId}/trigger +``` + +**Permission:** `workflows:write`. Write endpoints also require a workspace role that permits changes. See [authentication](/api-reference/authentication) and [errors](/api-reference/errors). + +## Request + +```bash +curl --request POST 'https://app.innflow.ai/api/v1/workflows/workflow_id/trigger' \ + --header "Authorization: Bearer $INNFLOW_API_KEY" \ + --header "Idempotency-Key: unique-request-001" \ + --header "Content-Type: application/json" \ + --data '{ + "nodeId": "node_id", + "expectedRevision": 0, + "config": {} +}' +``` + +Examples use placeholder IDs. Set `INNFLOW_API_KEY` in your shell and replace IDs with your own before sending a request. + +## Parameters + +| Name | In | Required | Details | +| --- | --- | --- | --- | +| `workflowId` | path | Yes | Resource identifier. | +| `X-Innflow-Workspace` | header | No | Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope. | +| `Idempotency-Key` | header | Yes | Required operation key: 1–200 letters, digits, dots, colons, underscores or hyphens. | + +## JSON body + +Required JSON body. +```json +{ + "type": "object", + "properties": { + "nodeId": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "pattern": "^[A-Za-z0-9_-]+$" + }, + "expectedRevision": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "config": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "nodeId", + "expectedRevision", + "config" + ], + "additionalProperties": false +} +``` + +## Response + +**HTTP 200** — Returns data with status (configured, needs_input, provider_handoff or pending), persisted, revision, nodePatch and optional missing/instructions. The envelope includes operationId and idempotencyKey. Follow handoff instructions if provider setup is needed. + +See [OpenAPI download](/openapi.json) for the machine-readable request contract and [errors](/api-reference/errors) for errors and retry behavior. diff --git a/content/docs/api-reference/endpoints/create-workflow.mdx b/content/docs/api-reference/endpoints/create-workflow.mdx new file mode 100644 index 0000000..fe6411a --- /dev/null +++ b/content/docs/api-reference/endpoints/create-workflow.mdx @@ -0,0 +1,54 @@ +--- +title: 'Create workflow' +description: 'POST /workflows' +--- + +Create a draft workflow with an initial node. An omitted or empty name uses the default untitled name. + + +```http +POST /api/v1/workflows +``` + +**Permission:** `workflows:write`. Write endpoints also require a workspace role that permits changes. See [authentication](/api-reference/authentication) and [errors](/api-reference/errors). + +## Request + +```bash +curl --request POST 'https://app.innflow.ai/api/v1/workflows' \ + --header "Authorization: Bearer $INNFLOW_API_KEY" \ + --header "Idempotency-Key: unique-request-001" \ + --header "Content-Type: application/json" \ + --data '{ + "name": "Customer onboarding" +}' +``` + +Examples use placeholder IDs. Set `INNFLOW_API_KEY` in your shell and replace IDs with your own before sending a request. + +## Parameters + +| Name | In | Required | Details | +| --- | --- | --- | --- | +| `X-Innflow-Workspace` | header | No | Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope. | +| `Idempotency-Key` | header | No | Optional replay key, at most 200 characters. Same request and key replay for 24 hours. | + +## JSON body + +Optional JSON body. +```json +{ + "type": "object", + "properties": { + "name": { + "type": "string" + } + } +} +``` + +## Response + +**HTTP 201** — Returns data with id, name, icon, iconColor, deploymentStatus, deployedAt, createdAt and updatedAt. + +See [OpenAPI download](/openapi.json) for the machine-readable request contract and [errors](/api-reference/errors) for errors and retry behavior. diff --git a/content/docs/api-reference/endpoints/delete-workflow.mdx b/content/docs/api-reference/endpoints/delete-workflow.mdx new file mode 100644 index 0000000..33699dd --- /dev/null +++ b/content/docs/api-reference/endpoints/delete-workflow.mdx @@ -0,0 +1,35 @@ +--- +title: 'Delete workflow' +description: 'DELETE /workflows/{workflowId}' +--- + +Delete a workflow and its execution history. This is destructive. + + +```http +DELETE /api/v1/workflows/{workflowId} +``` + +**Permission:** `workflows:write`. Write endpoints also require a workspace role that permits changes. See [authentication](/api-reference/authentication) and [errors](/api-reference/errors). + +## Request + +```bash +curl --request DELETE 'https://app.innflow.ai/api/v1/workflows/workflow_id' \ + --header "Authorization: Bearer $INNFLOW_API_KEY" +``` + +Examples use placeholder IDs. Set `INNFLOW_API_KEY` in your shell and replace IDs with your own before sending a request. + +## Parameters + +| Name | In | Required | Details | +| --- | --- | --- | --- | +| `workflowId` | path | Yes | Resource identifier. | +| `X-Innflow-Workspace` | header | No | Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope. | + +## Response + +**HTTP 200** — Returns data with id and deleted: true. + +See [OpenAPI download](/openapi.json) for the machine-readable request contract and [errors](/api-reference/errors) for errors and retry behavior. diff --git a/content/docs/api-reference/endpoints/deploy-workflow.mdx b/content/docs/api-reference/endpoints/deploy-workflow.mdx new file mode 100644 index 0000000..7ed83c0 --- /dev/null +++ b/content/docs/api-reference/endpoints/deploy-workflow.mdx @@ -0,0 +1,37 @@ +--- +title: 'Deploy workflow' +description: 'POST /workflows/{workflowId}/deploy' +--- + +Set a draft workflow to deployed and resume eligible paused schedules. Already-deployed workflows return 422. Validate configuration before deploying. + + +```http +POST /api/v1/workflows/{workflowId}/deploy +``` + +**Permission:** `workflows:write`. Write endpoints also require a workspace role that permits changes. See [authentication](/api-reference/authentication) and [errors](/api-reference/errors). + +With API-key authentication, this endpoint does not replay Idempotency-Key receipts. MCP OAuth contract calls have separate transaction semantics; see the authoring guide. + +## Request + +```bash +curl --request POST 'https://app.innflow.ai/api/v1/workflows/workflow_id/deploy' \ + --header "Authorization: Bearer $INNFLOW_API_KEY" +``` + +Examples use placeholder IDs. Set `INNFLOW_API_KEY` in your shell and replace IDs with your own before sending a request. + +## Parameters + +| Name | In | Required | Details | +| --- | --- | --- | --- | +| `workflowId` | path | Yes | Resource identifier. | +| `X-Innflow-Workspace` | header | No | Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope. | + +## Response + +**HTTP 200** — Returns data with id, name, icon, iconColor, deploymentStatus, deployedAt, createdAt and updatedAt. + +See [OpenAPI download](/openapi.json) for the machine-readable request contract and [errors](/api-reference/errors) for errors and retry behavior. diff --git a/content/docs/api-reference/endpoints/duplicate-workflow.mdx b/content/docs/api-reference/endpoints/duplicate-workflow.mdx new file mode 100644 index 0000000..a484859 --- /dev/null +++ b/content/docs/api-reference/endpoints/duplicate-workflow.mdx @@ -0,0 +1,55 @@ +--- +title: 'Duplicate workflow' +description: 'POST /workflows/{workflowId}/duplicate' +--- + +Copy the graph into a new draft, preserving canvas layout metadata and generating new node IDs. Trigger connection state is refreshed. + + +```http +POST /api/v1/workflows/{workflowId}/duplicate +``` + +**Permission:** `workflows:write`. Write endpoints also require a workspace role that permits changes. See [authentication](/api-reference/authentication) and [errors](/api-reference/errors). + +## Request + +```bash +curl --request POST 'https://app.innflow.ai/api/v1/workflows/workflow_id/duplicate' \ + --header "Authorization: Bearer $INNFLOW_API_KEY" \ + --header "Idempotency-Key: unique-request-001" \ + --header "Content-Type: application/json" \ + --data '{ + "name": "Workflow copy" +}' +``` + +Examples use placeholder IDs. Set `INNFLOW_API_KEY` in your shell and replace IDs with your own before sending a request. + +## Parameters + +| Name | In | Required | Details | +| --- | --- | --- | --- | +| `workflowId` | path | Yes | Resource identifier. | +| `X-Innflow-Workspace` | header | No | Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope. | +| `Idempotency-Key` | header | No | Optional replay key, at most 200 characters. Same request and key replay for 24 hours. | + +## JSON body + +Optional JSON body. +```json +{ + "type": "object", + "properties": { + "name": { + "type": "string" + } + } +} +``` + +## Response + +**HTTP 201** — Returns data with id, name, icon, iconColor, deploymentStatus, deployedAt, createdAt and updatedAt. + +See [OpenAPI download](/openapi.json) for the machine-readable request contract and [errors](/api-reference/errors) for errors and retry behavior. diff --git a/content/docs/api-reference/endpoints/execute-workflow.mdx b/content/docs/api-reference/endpoints/execute-workflow.mdx new file mode 100644 index 0000000..e67f830 --- /dev/null +++ b/content/docs/api-reference/endpoints/execute-workflow.mdx @@ -0,0 +1,61 @@ +--- +title: 'Execute workflow' +description: 'POST /workflows/{workflowId}/execute' +--- + +Start an asynchronous execution of a deployed workflow. Supply triggerNodeId when more than one eligible trigger exists. A successful request means the run was triggered, not that it completed. + + +```http +POST /api/v1/workflows/{workflowId}/execute +``` + +**Permission:** `workflows:execute`. Write endpoints also require a workspace role that permits changes. See [authentication](/api-reference/authentication) and [errors](/api-reference/errors). + +## Request + +```bash +curl --request POST 'https://app.innflow.ai/api/v1/workflows/workflow_id/execute' \ + --header "Authorization: Bearer $INNFLOW_API_KEY" \ + --header "Idempotency-Key: unique-request-001" \ + --header "Content-Type: application/json" \ + --data '{ + "input": { + "email": "customer@example.com" + } +}' +``` + +Examples use placeholder IDs. Set `INNFLOW_API_KEY` in your shell and replace IDs with your own before sending a request. + +## Parameters + +| Name | In | Required | Details | +| --- | --- | --- | --- | +| `workflowId` | path | Yes | Resource identifier. | +| `X-Innflow-Workspace` | header | No | Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope. | +| `Idempotency-Key` | header | No | Optional replay key, at most 200 characters. Same request and key replay for 24 hours. | + +## JSON body + +Optional JSON body. +```json +{ + "type": "object", + "properties": { + "input": { + "type": "object", + "additionalProperties": true + }, + "triggerNodeId": { + "type": "string" + } + } +} +``` + +## Response + +**HTTP 200** — Returns data with workflowId, eventIds, executionId and status: triggered. Poll Get execution with executionId. MCP OAuth contract requests return 202 and include an operationId receipt. + +See [OpenAPI download](/openapi.json) for the machine-readable request contract and [errors](/api-reference/errors) for errors and retry behavior. diff --git a/content/docs/api-reference/endpoints/execution-logs.mdx b/content/docs/api-reference/endpoints/execution-logs.mdx new file mode 100644 index 0000000..e1c29d8 --- /dev/null +++ b/content/docs/api-reference/endpoints/execution-logs.mdx @@ -0,0 +1,38 @@ +--- +title: 'List execution logs' +description: 'GET /executions/{executionId}/logs' +--- + +Read paginated node log metadata, ordered by start time then ID. Payload values are redacted. + + +```http +GET /api/v1/executions/{executionId}/logs +``` + +**Permission:** `executions:read`. Write endpoints also require a workspace role that permits changes. See [authentication](/api-reference/authentication) and [errors](/api-reference/errors). + +## Request + +```bash +curl --request GET 'https://app.innflow.ai/api/v1/executions/execution_id/logs' \ + --header "Authorization: Bearer $INNFLOW_API_KEY" +``` + +Examples use placeholder IDs. Set `INNFLOW_API_KEY` in your shell and replace IDs with your own before sending a request. + +## Parameters + +| Name | In | Required | Details | +| --- | --- | --- | --- | +| `executionId` | path | Yes | Resource identifier. | +| `X-Innflow-Workspace` | header | No | Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope. | +| `page` | query | No | Page number, starting at 1. | +| `pageSize` | query | No | Results per page (1–100). | +| `nodeId` | query | No | Filter logs to one node. | + +## Response + +**HTTP 200** — Returns data with items, totalCount and nextPage (null at the end). Items include id, nodeId, nodeName, nodeType, status, startedAt, completedAt, durationMs, error and diagnostics. Use the payload endpoint for log input/output. + +See [OpenAPI download](/openapi.json) for the machine-readable request contract and [errors](/api-reference/errors) for errors and retry behavior. diff --git a/content/docs/api-reference/endpoints/execution-payload.mdx b/content/docs/api-reference/endpoints/execution-payload.mdx new file mode 100644 index 0000000..85514a4 --- /dev/null +++ b/content/docs/api-reference/endpoints/execution-payload.mdx @@ -0,0 +1,37 @@ +--- +title: 'Read execution payload' +description: 'GET /executions/{executionId}/payload' +--- + +Read redacted execution output, or a node log input/output pair, in chunks of up to 16,000 JavaScript string units. Concatenate chunk values in cursor order before parsing JSON. + + +```http +GET /api/v1/executions/{executionId}/payload +``` + +**Permission:** `executions:read`. Write endpoints also require a workspace role that permits changes. See [authentication](/api-reference/authentication) and [errors](/api-reference/errors). + +## Request + +```bash +curl --request GET 'https://app.innflow.ai/api/v1/executions/execution_id/payload' \ + --header "Authorization: Bearer $INNFLOW_API_KEY" +``` + +Examples use placeholder IDs. Set `INNFLOW_API_KEY` in your shell and replace IDs with your own before sending a request. + +## Parameters + +| Name | In | Required | Details | +| --- | --- | --- | --- | +| `executionId` | path | Yes | Resource identifier. | +| `X-Innflow-Workspace` | header | No | Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope. | +| `logId` | query | No | Read input/output for this log instead of execution output. | +| `cursor` | query | No | Zero-based chunk index. | + +## Response + +**HTTP 200** — Returns data with executionId, logId, cursor, totalChunks, chunk, nextCursor and trustBoundary. nextCursor is null at the end. Out-of-range cursors return 400 INVALID_CURSOR. Treat returned payload values as untrusted data. + +See [OpenAPI download](/openapi.json) for the machine-readable request contract and [errors](/api-reference/errors) for errors and retry behavior. diff --git a/content/docs/api-reference/endpoints/get-execution.mdx b/content/docs/api-reference/endpoints/get-execution.mdx new file mode 100644 index 0000000..ce7c456 --- /dev/null +++ b/content/docs/api-reference/endpoints/get-execution.mdx @@ -0,0 +1,36 @@ +--- +title: 'Get execution' +description: 'GET /executions/{executionId}' +--- + +Read execution status, output and node logs. Use summary for a smaller polling response. + + +```http +GET /api/v1/executions/{executionId} +``` + +**Permission:** `executions:read`. Write endpoints also require a workspace role that permits changes. See [authentication](/api-reference/authentication) and [errors](/api-reference/errors). + +## Request + +```bash +curl --request GET 'https://app.innflow.ai/api/v1/executions/execution_id' \ + --header "Authorization: Bearer $INNFLOW_API_KEY" +``` + +Examples use placeholder IDs. Set `INNFLOW_API_KEY` in your shell and replace IDs with your own before sending a request. + +## Parameters + +| Name | In | Required | Details | +| --- | --- | --- | --- | +| `executionId` | path | Yes | Resource identifier. | +| `X-Innflow-Workspace` | header | No | Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope. | +| `view` | query | No | Use summary to omit large output and logs. | + +## Response + +**HTTP 200** — Returns a data object with execution metadata. Full API-key responses include output and nodeLogs; summary responses omit large payloads. A recently accepted asynchronous run may not be readable immediately; retry with backoff. MCP OAuth responses may report QUEUED or DISPATCH_FAILED before a run record exists. + +See [OpenAPI download](/openapi.json) for the machine-readable request contract and [errors](/api-reference/errors) for errors and retry behavior. diff --git a/content/docs/api-reference/endpoints/get-node-type.mdx b/content/docs/api-reference/endpoints/get-node-type.mdx new file mode 100644 index 0000000..2d0919c --- /dev/null +++ b/content/docs/api-reference/endpoints/get-node-type.mdx @@ -0,0 +1,36 @@ +--- +title: 'Get node schema' +description: 'GET /mcp/node-types/{nodeType}' +--- + +Get configuration fields, outputs and handles for a node type. + + +```http +GET /api/v1/mcp/node-types/{nodeType} +``` + +**Permission:** `workflows:read`. Write endpoints also require a workspace role that permits changes. See [authentication](/api-reference/authentication) and [errors](/api-reference/errors). + +## Request + +```bash +curl --request GET 'https://app.innflow.ai/api/v1/mcp/node-types/MANUAL_TRIGGER' \ + --header "Authorization: Bearer $INNFLOW_API_KEY" +``` + +Examples use placeholder IDs. Set `INNFLOW_API_KEY` in your shell and replace IDs with your own before sending a request. + +## Parameters + +| Name | In | Required | Details | +| --- | --- | --- | --- | +| `nodeType` | path | Yes | Resource identifier. | +| `X-Innflow-Workspace` | header | No | Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope. | +| `operation` | query | No | Operation identifier returned by the node catalog. | + +## Response + +**HTTP 200** — Returns data with type, optional operation, fields, outputs, handles and contractVersion. Use these fields to build configuration rather than guessing provider parameters. + +See [OpenAPI download](/openapi.json) for the machine-readable request contract and [errors](/api-reference/errors) for errors and retry behavior. diff --git a/content/docs/api-reference/endpoints/get-openapi.mdx b/content/docs/api-reference/endpoints/get-openapi.mdx new file mode 100644 index 0000000..389babc --- /dev/null +++ b/content/docs/api-reference/endpoints/get-openapi.mdx @@ -0,0 +1,29 @@ +--- +title: 'Get OpenAPI document' +description: 'GET /openapi.json' +--- + +Retrieve the application’s machine-readable OpenAPI 3.1 document without authentication. + + +```http +GET /api/v1/openapi.json +``` + +No authentication required. + +The application-served document currently covers the core API subset. The complete reference snapshot used by these docs is available at /openapi.json on docs.innflow.ai. + +## Request + +```bash +curl --request GET 'https://app.innflow.ai/api/v1/openapi.json' +``` + +Examples use placeholder IDs. Set `INNFLOW_API_KEY` in your shell and replace IDs with your own before sending a request. + +## Response + +**HTTP 200** — Returns the application OpenAPI document directly, without a data envelope. + +See [OpenAPI download](/openapi.json) for the machine-readable request contract and [errors](/api-reference/errors) for errors and retry behavior. diff --git a/content/docs/api-reference/endpoints/get-operation.mdx b/content/docs/api-reference/endpoints/get-operation.mdx new file mode 100644 index 0000000..e5e171f --- /dev/null +++ b/content/docs/api-reference/endpoints/get-operation.mdx @@ -0,0 +1,35 @@ +--- +title: 'Get operation receipt' +description: 'GET /mcp/operations/{operationId}' +--- + +Read an authoring operation receipt owned by the current principal and workspace. + + +```http +GET /api/v1/mcp/operations/{operationId} +``` + +**Permission:** `workflows:read`. Write endpoints also require a workspace role that permits changes. See [authentication](/api-reference/authentication) and [errors](/api-reference/errors). + +## Request + +```bash +curl --request GET 'https://app.innflow.ai/api/v1/mcp/operations/operation_id' \ + --header "Authorization: Bearer $INNFLOW_API_KEY" +``` + +Examples use placeholder IDs. Set `INNFLOW_API_KEY` in your shell and replace IDs with your own before sending a request. + +## Parameters + +| Name | In | Required | Details | +| --- | --- | --- | --- | +| `operationId` | path | Yes | Resource identifier. | +| `X-Innflow-Workspace` | header | No | Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope. | + +## Response + +**HTTP 200** — Returns data with id, state, executionId, workflowId, lastError and response. Use this to inspect accepted operations and dispatch failures. + +See [OpenAPI download](/openapi.json) for the machine-readable request contract and [errors](/api-reference/errors) for errors and retry behavior. diff --git a/content/docs/api-reference/endpoints/get-workflow.mdx b/content/docs/api-reference/endpoints/get-workflow.mdx new file mode 100644 index 0000000..1c21166 --- /dev/null +++ b/content/docs/api-reference/endpoints/get-workflow.mdx @@ -0,0 +1,37 @@ +--- +title: 'Get workflow' +description: 'GET /workflows/{workflowId}' +--- + +Read workflow metadata and its graph. + + +```http +GET /api/v1/workflows/{workflowId} +``` + +**Permission:** `workflows:read`. Write endpoints also require a workspace role that permits changes. See [authentication](/api-reference/authentication) and [errors](/api-reference/errors). + +## Request + +```bash +curl --request GET 'https://app.innflow.ai/api/v1/workflows/workflow_id' \ + --header "Authorization: Bearer $INNFLOW_API_KEY" +``` + +Examples use placeholder IDs. Set `INNFLOW_API_KEY` in your shell and replace IDs with your own before sending a request. + +## Parameters + +| Name | In | Required | Details | +| --- | --- | --- | --- | +| `workflowId` | path | Yes | Resource identifier. | +| `X-Innflow-Workspace` | header | No | Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope. | +| `view` | query | No | Use summary to omit nodes and connections. | +| `nodeIds` | query | No | Comma-separated list of at most 50 node IDs. Filters nodes only; connections remain unfiltered. | + +## Response + +**HTTP 200** — Returns data with workflow metadata, graphRevision, executionVersion, canvasLayoutVersion, nodes and connections. Summary view returns nodeCount and connectionCount instead of graph arrays. + +See [OpenAPI download](/openapi.json) for the machine-readable request contract and [errors](/api-reference/errors) for errors and retry behavior. diff --git a/content/docs/api-reference/endpoints/import-workflow.mdx b/content/docs/api-reference/endpoints/import-workflow.mdx new file mode 100644 index 0000000..57070e6 --- /dev/null +++ b/content/docs/api-reference/endpoints/import-workflow.mdx @@ -0,0 +1,167 @@ +--- +title: 'Import workflow' +description: 'POST /workflows/import' +--- + +Create a draft from 1–200 nodes and optional edges. Edge source and target are zero-based indexes into nodes. Node types must exist in the Innflow registry. description is accepted by the input schema but is not persisted by this endpoint. + + +```http +POST /api/v1/workflows/import +``` + +**Permission:** `workflows:write`. Write endpoints also require a workspace role that permits changes. See [authentication](/api-reference/authentication) and [errors](/api-reference/errors). + +## Request + +```bash +curl --request POST 'https://app.innflow.ai/api/v1/workflows/import' \ + --header "Authorization: Bearer $INNFLOW_API_KEY" \ + --header "Idempotency-Key: unique-request-001" \ + --header "Content-Type: application/json" \ + --data '{ + "name": "API workflow", + "nodes": [ + { + "type": "MANUAL_TRIGGER", + "position": { + "x": 0, + "y": 0 + }, + "data": {} + } + ], + "edges": [] +}' +``` + +Examples use placeholder IDs. Set `INNFLOW_API_KEY` in your shell and replace IDs with your own before sending a request. + +## Parameters + +| Name | In | Required | Details | +| --- | --- | --- | --- | +| `X-Innflow-Workspace` | header | No | Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope. | +| `Idempotency-Key` | header | No | Optional replay key, at most 200 characters. Same request and key replay for 24 hours. | + +## JSON body + +Required JSON body. +```json +{ + "type": "object", + "properties": { + "canvasLayoutVersion": { + "default": 0, + "type": "integer", + "minimum": 0, + "maximum": 1 + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 255 + }, + "description": { + "type": "string" + }, + "icon": { + "type": "string", + "maxLength": 100 + }, + "iconColor": { + "type": "string", + "maxLength": 20 + }, + "nodes": { + "minItems": 1, + "maxItems": 200, + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "minLength": 1 + }, + "name": { + "type": "string", + "maxLength": 255 + }, + "position": { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + }, + "required": [ + "x", + "y" + ] + }, + "data": { + "default": {}, + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type", + "position" + ] + } + }, + "edges": { + "default": [], + "type": "array", + "items": { + "type": "object", + "properties": { + "source": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "target": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "fromOutput": { + "type": "string" + }, + "toInput": { + "type": "string" + }, + "sourceHandle": { + "type": "string" + }, + "targetHandle": { + "type": "string" + } + }, + "required": [ + "source", + "target" + ] + } + } + }, + "required": [ + "nodes" + ] +} +``` + +## Response + +**HTTP 201** — Returns data with id, name, deploymentStatus, nodeCount, edgeCount, createdAt and updatedAt. Node IDs are generated on import. canvasLayoutVersion defaults to 0; preserve 1 when reimporting an already arranged graph. + +See [OpenAPI download](/openapi.json) for the machine-readable request contract and [errors](/api-reference/errors) for errors and retry behavior. diff --git a/content/docs/api-reference/endpoints/index.mdx b/content/docs/api-reference/endpoints/index.mdx new file mode 100644 index 0000000..2c82600 --- /dev/null +++ b/content/docs/api-reference/endpoints/index.mdx @@ -0,0 +1,67 @@ +--- +title: 'REST endpoints' +description: '25 REST operations for workflows, executions, workspaces and authoring' +--- + +Base URL: `https://app.innflow.ai/api/v1`. + +[Authentication](/api-reference/authentication) · [Authoring guide](/api-reference/authoring) · [Download OpenAPI 3.1](/openapi.json) + +## Workspaces + +| Method | Path | Reference | +| --- | --- | --- | +| `GET` | `/workspaces` | [List workspaces](/api-reference/endpoints/list-workspaces) | + +## Workflows + +| Method | Path | Reference | +| --- | --- | --- | +| `GET` | `/workflows` | [List workflows](/api-reference/endpoints/list-workflows) | +| `POST` | `/workflows` | [Create workflow](/api-reference/endpoints/create-workflow) | +| `POST` | `/workflows/import` | [Import workflow](/api-reference/endpoints/import-workflow) | +| `GET` | `/workflows/{workflowId}` | [Get workflow](/api-reference/endpoints/get-workflow) | +| `PATCH` | `/workflows/{workflowId}` | [Update workflow](/api-reference/endpoints/update-workflow) | +| `DELETE` | `/workflows/{workflowId}` | [Delete workflow](/api-reference/endpoints/delete-workflow) | +| `POST` | `/workflows/{workflowId}/duplicate` | [Duplicate workflow](/api-reference/endpoints/duplicate-workflow) | +| `POST` | `/workflows/{workflowId}/deploy` | [Deploy workflow](/api-reference/endpoints/deploy-workflow) | +| `POST` | `/workflows/{workflowId}/undeploy` | [Undeploy workflow](/api-reference/endpoints/undeploy-workflow) | + +## Executions + +| Method | Path | Reference | +| --- | --- | --- | +| `POST` | `/workflows/{workflowId}/execute` | [Execute workflow](/api-reference/endpoints/execute-workflow) | +| `GET` | `/executions` | [List executions](/api-reference/endpoints/list-executions) | +| `GET` | `/executions/{executionId}` | [Get execution](/api-reference/endpoints/get-execution) | +| `GET` | `/executions/{executionId}/logs` | [List execution logs](/api-reference/endpoints/execution-logs) | +| `GET` | `/executions/{executionId}/payload` | [Read execution payload](/api-reference/endpoints/execution-payload) | + +## Authoring + +| Method | Path | Reference | +| --- | --- | --- | +| `GET` | `/workflows/{workflowId}/validate` | [Validate workflow](/api-reference/endpoints/validate-workflow) | +| `PATCH` | `/workflows/{workflowId}/graph` | [Patch workflow graph](/api-reference/endpoints/patch-graph) | +| `POST` | `/workflows/{workflowId}/trigger` | [Configure trigger](/api-reference/endpoints/configure-trigger) | +| `GET` | `/workflows/{workflowId}/node-options` | [Get node field options](/api-reference/endpoints/node-options) | + +## Catalog + +| Method | Path | Reference | +| --- | --- | --- | +| `GET` | `/mcp/context` | [Get authoring context](/api-reference/endpoints/authoring-context) | +| `GET` | `/mcp/node-types` | [Search node types](/api-reference/endpoints/list-node-types) | +| `GET` | `/mcp/node-types/{nodeType}` | [Get node schema](/api-reference/endpoints/get-node-type) | +| `GET` | `/mcp/connections` | [List connections](/api-reference/endpoints/list-connections) | +| `GET` | `/mcp/operations/{operationId}` | [Get operation receipt](/api-reference/endpoints/get-operation) | + +## Discovery + +| Method | Path | Reference | +| --- | --- | --- | +| `GET` | `/openapi.json` | [Get OpenAPI document](/api-reference/endpoints/get-openapi) | + +## Scope + +This reference covers every customer-facing route under `/api/v1`, including authoring and discovery. `/api/v1/portal-events` is service-to-service ingestion and does not accept customer API keys. Provider callbacks, internal service APIs, browser-session routes and tRPC are separate interfaces, not general customer REST endpoints. See [triggers](/triggers) for workflow-specific webhook setup and [MCP](/mcp) for the MCP interface. diff --git a/content/docs/api-reference/endpoints/list-connections.mdx b/content/docs/api-reference/endpoints/list-connections.mdx new file mode 100644 index 0000000..a18d5b3 --- /dev/null +++ b/content/docs/api-reference/endpoints/list-connections.mdx @@ -0,0 +1,37 @@ +--- +title: 'List connections' +description: 'GET /mcp/connections' +--- + +List active connected accounts for a provider returned by a node schema. This endpoint returns identifiers and display names, not credentials. + + +```http +GET /api/v1/mcp/connections +``` + +**Permission:** `workflows:read`. Write endpoints also require a workspace role that permits changes. See [authentication](/api-reference/authentication) and [errors](/api-reference/errors). + +## Request + +```bash +curl --request GET 'https://app.innflow.ai/api/v1/mcp/connections?provider=provider_id' \ + --header "Authorization: Bearer $INNFLOW_API_KEY" +``` + +Examples use placeholder IDs. Set `INNFLOW_API_KEY` in your shell and replace IDs with your own before sending a request. + +## Parameters + +| Name | In | Required | Details | +| --- | --- | --- | --- | +| `X-Innflow-Workspace` | header | No | Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope. | +| `provider` | query | Yes | Provider identifier from the node schema. | +| `page` | query | No | Page number, starting at 1. | +| `pageSize` | query | No | Results per page (1–100). | + +## Response + +**HTTP 200** — Returns data with items (id, provider, name) and nextPage. An unknown provider returns 422 UNKNOWN_PROVIDER. + +See [OpenAPI download](/openapi.json) for the machine-readable request contract and [errors](/api-reference/errors) for errors and retry behavior. diff --git a/content/docs/api-reference/endpoints/list-executions.mdx b/content/docs/api-reference/endpoints/list-executions.mdx new file mode 100644 index 0000000..94e7be6 --- /dev/null +++ b/content/docs/api-reference/endpoints/list-executions.mdx @@ -0,0 +1,38 @@ +--- +title: 'List executions' +description: 'GET /executions' +--- + +List accessible executions, newest started first. + + +```http +GET /api/v1/executions +``` + +**Permission:** `executions:read`. Write endpoints also require a workspace role that permits changes. See [authentication](/api-reference/authentication) and [errors](/api-reference/errors). + +## Request + +```bash +curl --request GET 'https://app.innflow.ai/api/v1/executions' \ + --header "Authorization: Bearer $INNFLOW_API_KEY" +``` + +Examples use placeholder IDs. Set `INNFLOW_API_KEY` in your shell and replace IDs with your own before sending a request. + +## Parameters + +| Name | In | Required | Details | +| --- | --- | --- | --- | +| `X-Innflow-Workspace` | header | No | Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope. | +| `page` | query | No | Page number, starting at 1. | +| `pageSize` | query | No | Results per page (1–100). | +| `workflowId` | query | No | Filter to one workflow. | +| `status` | query | No | Filter by execution status. | + +## Response + +**HTTP 200** — Returns data as an array with id, workflowId, workflowName, status, startedAt, completedAt and error; pagination has page, pageSize, totalCount and totalPages. + +See [OpenAPI download](/openapi.json) for the machine-readable request contract and [errors](/api-reference/errors) for errors and retry behavior. diff --git a/content/docs/api-reference/endpoints/list-node-types.mdx b/content/docs/api-reference/endpoints/list-node-types.mdx new file mode 100644 index 0000000..a464960 --- /dev/null +++ b/content/docs/api-reference/endpoints/list-node-types.mdx @@ -0,0 +1,37 @@ +--- +title: 'Search node types' +description: 'GET /mcp/node-types' +--- + +Discover available node types and operations before creating graph nodes. + + +```http +GET /api/v1/mcp/node-types +``` + +**Permission:** `workflows:read`. Write endpoints also require a workspace role that permits changes. See [authentication](/api-reference/authentication) and [errors](/api-reference/errors). + +## Request + +```bash +curl --request GET 'https://app.innflow.ai/api/v1/mcp/node-types' \ + --header "Authorization: Bearer $INNFLOW_API_KEY" +``` + +Examples use placeholder IDs. Set `INNFLOW_API_KEY` in your shell and replace IDs with your own before sending a request. + +## Parameters + +| Name | In | Required | Details | +| --- | --- | --- | --- | +| `X-Innflow-Workspace` | header | No | Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope. | +| `page` | query | No | Page number, starting at 1. | +| `pageSize` | query | No | Results per page (1–100). | +| `search` | query | No | Search the node catalog. | + +## Response + +**HTTP 200** — Returns data with items, totalCount, nextPage and contractVersion. Each item describes type, name, description, category, authMode and operations. + +See [OpenAPI download](/openapi.json) for the machine-readable request contract and [errors](/api-reference/errors) for errors and retry behavior. diff --git a/content/docs/api-reference/endpoints/list-workflows.mdx b/content/docs/api-reference/endpoints/list-workflows.mdx new file mode 100644 index 0000000..1fcb198 --- /dev/null +++ b/content/docs/api-reference/endpoints/list-workflows.mdx @@ -0,0 +1,37 @@ +--- +title: 'List workflows' +description: 'GET /workflows' +--- + +List standard workflows accessible in the selected workspace, newest updated first. + + +```http +GET /api/v1/workflows +``` + +**Permission:** `workflows:read`. Write endpoints also require a workspace role that permits changes. See [authentication](/api-reference/authentication) and [errors](/api-reference/errors). + +## Request + +```bash +curl --request GET 'https://app.innflow.ai/api/v1/workflows' \ + --header "Authorization: Bearer $INNFLOW_API_KEY" +``` + +Examples use placeholder IDs. Set `INNFLOW_API_KEY` in your shell and replace IDs with your own before sending a request. + +## Parameters + +| Name | In | Required | Details | +| --- | --- | --- | --- | +| `X-Innflow-Workspace` | header | No | Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope. | +| `page` | query | No | Page number, starting at 1. | +| `pageSize` | query | No | Results per page (1–100). | +| `search` | query | No | Case-insensitive workflow name filter. | + +## Response + +**HTTP 200** — Returns data as an array of workflow summaries and pagination with page, pageSize, totalCount and totalPages. + +See [OpenAPI download](/openapi.json) for the machine-readable request contract and [errors](/api-reference/errors) for errors and retry behavior. diff --git a/content/docs/api-reference/endpoints/list-workspaces.mdx b/content/docs/api-reference/endpoints/list-workspaces.mdx new file mode 100644 index 0000000..e949918 --- /dev/null +++ b/content/docs/api-reference/endpoints/list-workspaces.mdx @@ -0,0 +1,34 @@ +--- +title: 'List workspaces' +description: 'GET /workspaces' +--- + +List the personal workspace and organizations you belong to. + + +```http +GET /api/v1/workspaces +``` + +**Permission:** `workspaces:read`. Write endpoints also require a workspace role that permits changes. See [authentication](/api-reference/authentication) and [errors](/api-reference/errors). + +## Request + +```bash +curl --request GET 'https://app.innflow.ai/api/v1/workspaces' \ + --header "Authorization: Bearer $INNFLOW_API_KEY" +``` + +Examples use placeholder IDs. Set `INNFLOW_API_KEY` in your shell and replace IDs with your own before sending a request. + +## Parameters + +| Name | In | Required | Details | +| --- | --- | --- | --- | +| `X-Innflow-Workspace` | header | No | Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope. | + +## Response + +**HTTP 200** — Returns data as an array. Each entry has id, name, type and role; organization entries also include slug. + +See [OpenAPI download](/openapi.json) for the machine-readable request contract and [errors](/api-reference/errors) for errors and retry behavior. diff --git a/content/docs/api-reference/endpoints/meta.json b/content/docs/api-reference/endpoints/meta.json new file mode 100644 index 0000000..c21f327 --- /dev/null +++ b/content/docs/api-reference/endpoints/meta.json @@ -0,0 +1,37 @@ +{ + "title": "Endpoints", + "pages": [ + "index", + "---Workspaces---", + "list-workspaces", + "---Workflows---", + "list-workflows", + "create-workflow", + "import-workflow", + "get-workflow", + "update-workflow", + "delete-workflow", + "duplicate-workflow", + "deploy-workflow", + "undeploy-workflow", + "---Executions---", + "execute-workflow", + "list-executions", + "get-execution", + "execution-logs", + "execution-payload", + "---Authoring---", + "validate-workflow", + "patch-graph", + "configure-trigger", + "node-options", + "---Catalog---", + "authoring-context", + "list-node-types", + "get-node-type", + "list-connections", + "get-operation", + "---Discovery---", + "get-openapi" + ] +} diff --git a/content/docs/api-reference/endpoints/node-options.mdx b/content/docs/api-reference/endpoints/node-options.mdx new file mode 100644 index 0000000..f02e1f4 --- /dev/null +++ b/content/docs/api-reference/endpoints/node-options.mdx @@ -0,0 +1,39 @@ +--- +title: 'Get node field options' +description: 'GET /workflows/{workflowId}/node-options' +--- + +Resolve options for a field on a saved node. Some dynamic provider selectors require opening the editor. + + +```http +GET /api/v1/workflows/{workflowId}/node-options +``` + +**Permission:** `workflows:read`. Write endpoints also require a workspace role that permits changes. See [authentication](/api-reference/authentication) and [errors](/api-reference/errors). + +## Request + +```bash +curl --request GET 'https://app.innflow.ai/api/v1/workflows/workflow_id/node-options?nodeId=node_id&field=field_name' \ + --header "Authorization: Bearer $INNFLOW_API_KEY" +``` + +Examples use placeholder IDs. Set `INNFLOW_API_KEY` in your shell and replace IDs with your own before sending a request. + +## Parameters + +| Name | In | Required | Details | +| --- | --- | --- | --- | +| `workflowId` | path | Yes | Resource identifier. | +| `X-Innflow-Workspace` | header | No | Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope. | +| `nodeId` | query | Yes | Saved node ID. | +| `field` | query | Yes | Field name from the node schema. | +| `search` | query | No | Case-insensitive label filter. | +| `cursor` | query | No | Nonnegative option offset. | + +## Response + +**HTTP 200** — Returns data with items (id and label), nextCursor and optional handoffUrl. Up to 100 options are returned. Follow handoffUrl when remote options require the editor. + +See [OpenAPI download](/openapi.json) for the machine-readable request contract and [errors](/api-reference/errors) for errors and retry behavior. diff --git a/content/docs/api-reference/endpoints/patch-graph.mdx b/content/docs/api-reference/endpoints/patch-graph.mdx new file mode 100644 index 0000000..13317e0 --- /dev/null +++ b/content/docs/api-reference/endpoints/patch-graph.mdx @@ -0,0 +1,291 @@ +--- +title: 'Patch workflow graph' +description: 'PATCH /workflows/{workflowId}/graph' +--- + +Apply 1–25 graph operations atomically against expectedRevision. Requires authoring to be enabled. Read graphRevision from Get workflow before editing; a stale revision must be refreshed. + + +```http +PATCH /api/v1/workflows/{workflowId}/graph +``` + +**Permission:** `workflows:write`. Write endpoints also require a workspace role that permits changes. See [authentication](/api-reference/authentication) and [errors](/api-reference/errors). + +## Request + +```bash +curl --request PATCH 'https://app.innflow.ai/api/v1/workflows/workflow_id/graph' \ + --header "Authorization: Bearer $INNFLOW_API_KEY" \ + --header "Idempotency-Key: unique-request-001" \ + --header "Content-Type: application/json" \ + --data '{ + "expectedRevision": 0, + "operations": [ + { + "operation": "addNode", + "ref": "new_trigger", + "type": "MANUAL_TRIGGER", + "position": { + "x": 0, + "y": 0 + } + } + ] +}' +``` + +Examples use placeholder IDs. Set `INNFLOW_API_KEY` in your shell and replace IDs with your own before sending a request. + +## Parameters + +| Name | In | Required | Details | +| --- | --- | --- | --- | +| `workflowId` | path | Yes | Resource identifier. | +| `X-Innflow-Workspace` | header | No | Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope. | +| `Idempotency-Key` | header | Yes | Required operation key: 1–200 letters, digits, dots, colons, underscores or hyphens. | + +## JSON body + +Required JSON body. +```json +{ + "type": "object", + "properties": { + "expectedRevision": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "operations": { + "minItems": 1, + "maxItems": 25, + "type": "array", + "items": { + "oneOf": [ + { + "type": "object", + "properties": { + "operation": { + "type": "string", + "const": "addNode" + }, + "ref": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "pattern": "^[A-Za-z0-9_-]+$" + }, + "type": { + "type": "string", + "minLength": 1 + }, + "name": { + "type": "string", + "maxLength": 255 + }, + "position": { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + }, + "required": [ + "x", + "y" + ] + }, + "data": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "operation", + "ref", + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "operation": { + "type": "string", + "const": "configureNode" + }, + "nodeId": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "pattern": "^[A-Za-z0-9_-]+$" + }, + "data": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "operation", + "nodeId", + "data" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "operation": { + "type": "string", + "const": "removeNode" + }, + "nodeId": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "pattern": "^[A-Za-z0-9_-]+$" + } + }, + "required": [ + "operation", + "nodeId" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "operation": { + "type": "string", + "const": "moveNode" + }, + "nodeId": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "pattern": "^[A-Za-z0-9_-]+$" + }, + "position": { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + }, + "required": [ + "x", + "y" + ] + } + }, + "required": [ + "operation", + "nodeId", + "position" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "operation": { + "type": "string", + "const": "connect" + }, + "source": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "pattern": "^[A-Za-z0-9_-]+$" + }, + "target": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "pattern": "^[A-Za-z0-9_-]+$" + }, + "sourceHandle": { + "default": "main", + "type": "string", + "maxLength": 200 + }, + "targetHandle": { + "default": "main", + "type": "string", + "maxLength": 200 + } + }, + "required": [ + "operation", + "source", + "target" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "operation": { + "type": "string", + "const": "disconnect" + }, + "source": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "pattern": "^[A-Za-z0-9_-]+$" + }, + "target": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "pattern": "^[A-Za-z0-9_-]+$" + }, + "sourceHandle": { + "default": "main", + "type": "string", + "maxLength": 200 + }, + "targetHandle": { + "default": "main", + "type": "string", + "maxLength": 200 + } + }, + "required": [ + "operation", + "source", + "target" + ], + "additionalProperties": false + } + ] + } + } + }, + "required": [ + "expectedRevision", + "operations" + ], + "additionalProperties": false +} +``` + +## Response + +**HTTP 200** — Returns data with workflowId, revision, nodeIds (temporary refs mapped to persisted IDs) and editorUrl; the envelope also includes operationId and idempotencyKey. + +See [OpenAPI download](/openapi.json) for the machine-readable request contract and [errors](/api-reference/errors) for errors and retry behavior. diff --git a/content/docs/api-reference/endpoints/undeploy-workflow.mdx b/content/docs/api-reference/endpoints/undeploy-workflow.mdx new file mode 100644 index 0000000..4839ac9 --- /dev/null +++ b/content/docs/api-reference/endpoints/undeploy-workflow.mdx @@ -0,0 +1,37 @@ +--- +title: 'Undeploy workflow' +description: 'POST /workflows/{workflowId}/undeploy' +--- + +Return a deployed workflow to draft and pause active schedules. A workflow that is not currently deployed returns 422. + + +```http +POST /api/v1/workflows/{workflowId}/undeploy +``` + +**Permission:** `workflows:write`. Write endpoints also require a workspace role that permits changes. See [authentication](/api-reference/authentication) and [errors](/api-reference/errors). + +With API-key authentication, this endpoint does not replay Idempotency-Key receipts. + +## Request + +```bash +curl --request POST 'https://app.innflow.ai/api/v1/workflows/workflow_id/undeploy' \ + --header "Authorization: Bearer $INNFLOW_API_KEY" +``` + +Examples use placeholder IDs. Set `INNFLOW_API_KEY` in your shell and replace IDs with your own before sending a request. + +## Parameters + +| Name | In | Required | Details | +| --- | --- | --- | --- | +| `workflowId` | path | Yes | Resource identifier. | +| `X-Innflow-Workspace` | header | No | Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope. | + +## Response + +**HTTP 200** — Returns data with id, name, icon, iconColor, deploymentStatus, deployedAt, createdAt and updatedAt. + +See [OpenAPI download](/openapi.json) for the machine-readable request contract and [errors](/api-reference/errors) for errors and retry behavior. diff --git a/content/docs/api-reference/endpoints/update-workflow.mdx b/content/docs/api-reference/endpoints/update-workflow.mdx new file mode 100644 index 0000000..9e857f1 --- /dev/null +++ b/content/docs/api-reference/endpoints/update-workflow.mdx @@ -0,0 +1,66 @@ +--- +title: 'Update workflow' +description: 'PATCH /workflows/{workflowId}' +--- + +Change workflow metadata. Supply at least one of name, icon or iconColor. name must be non-empty after trimming. Use the graph endpoint for node and connection edits. + + +```http +PATCH /api/v1/workflows/{workflowId} +``` + +**Permission:** `workflows:write`. Write endpoints also require a workspace role that permits changes. See [authentication](/api-reference/authentication) and [errors](/api-reference/errors). + +## Request + +```bash +curl --request PATCH 'https://app.innflow.ai/api/v1/workflows/workflow_id' \ + --header "Authorization: Bearer $INNFLOW_API_KEY" \ + --header "Content-Type: application/json" \ + --data '{ + "name": "Updated workflow" +}' +``` + +Examples use placeholder IDs. Set `INNFLOW_API_KEY` in your shell and replace IDs with your own before sending a request. + +## Parameters + +| Name | In | Required | Details | +| --- | --- | --- | --- | +| `workflowId` | path | Yes | Resource identifier. | +| `X-Innflow-Workspace` | header | No | Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope. | + +## JSON body + +Required JSON body. +```json +{ + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1 + }, + "icon": { + "type": [ + "string", + "null" + ] + }, + "iconColor": { + "type": [ + "string", + "null" + ] + } + } +} +``` + +## Response + +**HTTP 200** — Returns data with id, name, icon, iconColor, deploymentStatus, deployedAt, createdAt and updatedAt. + +See [OpenAPI download](/openapi.json) for the machine-readable request contract and [errors](/api-reference/errors) for errors and retry behavior. diff --git a/content/docs/api-reference/endpoints/validate-workflow.mdx b/content/docs/api-reference/endpoints/validate-workflow.mdx new file mode 100644 index 0000000..a36a07d --- /dev/null +++ b/content/docs/api-reference/endpoints/validate-workflow.mdx @@ -0,0 +1,35 @@ +--- +title: 'Validate workflow' +description: 'GET /workflows/{workflowId}/validate' +--- + +Check a saved graph and its configuration without deploying or executing it. + + +```http +GET /api/v1/workflows/{workflowId}/validate +``` + +**Permission:** `workflows:read`. Write endpoints also require a workspace role that permits changes. See [authentication](/api-reference/authentication) and [errors](/api-reference/errors). + +## Request + +```bash +curl --request GET 'https://app.innflow.ai/api/v1/workflows/workflow_id/validate' \ + --header "Authorization: Bearer $INNFLOW_API_KEY" +``` + +Examples use placeholder IDs. Set `INNFLOW_API_KEY` in your shell and replace IDs with your own before sending a request. + +## Parameters + +| Name | In | Required | Details | +| --- | --- | --- | --- | +| `workflowId` | path | Yes | Resource identifier. | +| `X-Innflow-Workspace` | header | No | Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope. | + +## Response + +**HTTP 200** — Returns data with workflowId, revision, valid, issues and editorUrl. Each issue has code and message, and may include nodeId and field. + +See [OpenAPI download](/openapi.json) for the machine-readable request contract and [errors](/api-reference/errors) for errors and retry behavior. diff --git a/content/docs/api-reference/errors.mdx b/content/docs/api-reference/errors.mdx new file mode 100644 index 0000000..12dcf26 --- /dev/null +++ b/content/docs/api-reference/errors.mdx @@ -0,0 +1,65 @@ +--- +title: "Errors and retries" +description: "Handle REST failures, pagination, rate limits, and idempotent request retries" +--- + +## Error format + +Application-level JSON failures generally contain: + +```json +{ + "error": "Workflow not found", + "code": "NOT_FOUND", + "requestId": "example-request" +} +``` + +Validation errors may include `details`. Trigger-selection errors may include eligible choices. Save the `X-Request-Id` response header when troubleshooting. Responses from the proxy or hosting layer can have a different format, so check the status and content type before parsing JSON. + +| Status | Meaning | Next step | +| --- | --- | --- | +| `400` | Invalid request or import validation failure | Correct the body, query, or referenced node indices | +| `401` | Missing/invalid credential or inaccessible workspace selection | Check the key, expiration, and workspace membership | +| `403` | Insufficient key permission or workspace role | Check endpoint permissions and membership role | +| `404` | Resource missing or outside the selected scope | Check resource ID and explicit workspace | +| `409` | Request conflicts with existing state or idempotency key | Read the error; do not reuse a key for a changed request | +| `422` | Workflow state or trigger selection prevents the action | Deploy/configure the workflow or select an eligible trigger | +| `429` | Rate limit exceeded | Wait for `Retry-After` before retrying | +| `500`, `502` | Server or upstream failure | Use bounded backoff; inspect write outcomes before repeating | + +## Rate limits + +The public API proxy currently applies a 60-request, 60-second window per route path and client IP within a serving instance. This is not a guaranteed account-wide quota; additional credential or infrastructure limits may apply. Use response headers rather than relying on a fixed polling rate. + +- `X-RateLimit-Limit`: window limit. +- `X-RateLimit-Remaining`: remaining requests in that window. +- `X-RateLimit-Reset`: reset time as a Unix timestamp in milliseconds. +- `Retry-After`: seconds to wait when the proxy returns `429`. + +The proxy's `429` body includes `error`, `message`, and `retryAfter` and may not contain an application request ID. + +## Idempotent writes + +The API-key routes for create, import, duplicate, and execute support `Idempotency-Key`. Use a unique key of at most 200 characters for each intended operation. + +After a response is saved, a later identical request can replay it for 24 hours. Replays include `X-Idempotent-Replayed: true`. The key is scoped to the credential, workspace, and route, and the request hash includes the HTTP method and raw body bytes. Keep the body identical, including its serialization, when retrying. + +Reusing a key on the same route with different request bytes returns `409`. Saved responses can include client errors; after correcting input, use a new key. Server errors are not saved by this mechanism. + +This is response replay, not an exactly-once guarantee: concurrent first requests or a failure before the response is persisted can still repeat work. Serialize retries and check the outcome before resubmitting an uncertain write. + +`PATCH`, `DELETE`, deploy, and undeploy do not use this replay mechanism. Read the resource state after a timeout before repeating those requests. + +## Pagination + +Workflow and execution lists accept positive integer `page` and `pageSize` values. The default page size is 20 and the maximum is 100. + +```json +{ + "data": [], + "pagination": { "page": 1, "pageSize": 20, "totalCount": 0, "totalPages": 0 } +} +``` + +Continue through `totalPages` when you need the full result set. These are page-based lists, not snapshot cursors: records can change while you paginate. diff --git a/content/docs/api-reference/executions.mdx b/content/docs/api-reference/executions.mdx new file mode 100644 index 0000000..531846a --- /dev/null +++ b/content/docs/api-reference/executions.mdx @@ -0,0 +1,107 @@ +--- +title: "Executions" +description: "Start deployed workflows and retrieve run status, output, and node logs" +--- + +Use the base URL `https://app.innflow.ai/api/v1` with [authentication and workspace headers](/api-reference/authentication). + +## Execute a workflow + +`POST /workflows/{workflowId}/execute` starts a deployed workflow. Scoped keys need `workflows:execute`, and organization read-only members cannot execute workflows. + +| Body field | Required | Description | +| --- | --- | --- | +| `input` | No | JSON object passed into the workflow; defaults to `{}` | +| `triggerNodeId` | When ambiguous | Node ID selecting one eligible trigger when the workflow has more than one | + +Retrieve node IDs with [read a workflow](/api-reference/workflows#read-a-workflow). A workflow that is not deployed returns `422`; a missing or inaccessible workflow returns `404`. + +```bash +curl --fail-with-body -X POST "https://app.innflow.ai/api/v1/workflows/$WORKFLOW_ID/execute" \ + -H "Authorization: Bearer $INNFLOW_API_KEY" \ + -H "X-Innflow-Workspace: $INNFLOW_WORKSPACE" \ + -H 'Content-Type: application/json' \ + -H 'Idempotency-Key: leasing-digest-2026-09-28' \ + -d '{"input":{"propertyId":"property_example"}}' +``` + +Example `200` response for an API-key request: + +```json +{ + "data": { + "workflowId": "workflow_example", + "executionId": "execution_example", + "eventIds": ["event_example"], + "status": "triggered" + } +} +``` + +`triggered` means the run was dispatched, not that it finished. Use `executionId` to read the execution; event IDs are not execution IDs. The execution record may take time to appear after dispatch. A new intended run needs a new idempotency key. Retry the same request sequentially with the same key when recovering a transport failure; see [retry limitations](/api-reference/errors#idempotent-writes). + +## Read an execution + +`GET /executions/{executionId}` requires `executions:read`. Returns the run's identifiers, workflow name, status, timestamps, error, output, and node logs under `data`. + +```bash +curl --fail-with-body "https://app.innflow.ai/api/v1/executions/$EXECUTION_ID" \ + -H "Authorization: Bearer $INNFLOW_API_KEY" \ + -H "X-Innflow-Workspace: $INNFLOW_WORKSPACE" +``` + +```json +{ + "data": { + "id": "execution_example", + "workflowId": "workflow_example", + "workflowName": "Leasing digest", + "status": "SUCCESS", + "startedAt": "2026-09-28T12:00:00.000Z", + "completedAt": "2026-09-28T12:00:04.000Z", + "error": null, + "output": { "changedUnits": 2 }, + "nodeLogs": [] + } +} +``` + +`output` depends on the workflow. Node logs include node identity, type, status, start/completion times, duration, and any error. Optional `view=summary` provides a smaller status response instead of full output and logs. + +Poll with a bounded interval and honor rate-limit headers. Stop on a terminal status such as `SUCCESS`, `FAILED`, or `CANCELLED`. A `RUNNING` status is not a failure. Allow a short, bounded retry for a newly dispatched run that has not appeared yet; persistent `404` responses require checking the ID and workspace. + +## List executions + +`GET /executions` returns runs ordered by most recently started first. Scoped keys need `executions:read`. + +| Query | Default | Description | +| --- | --- | --- | +| `page` | `1` | Positive page number | +| `pageSize` | `20` | Results per page, maximum `100` | +| `workflowId` | Unset | Restrict to one workflow | +| `status` | Unset | Filter by an execution status, for example `RUNNING`, `SUCCESS`, `FAILED`, or `CANCELLED` | + +```bash +curl --fail-with-body --get 'https://app.innflow.ai/api/v1/executions' \ + -H "Authorization: Bearer $INNFLOW_API_KEY" \ + -H "X-Innflow-Workspace: $INNFLOW_WORKSPACE" \ + --data-urlencode "workflowId=$WORKFLOW_ID" \ + --data-urlencode 'page=1' \ + --data-urlencode 'pageSize=20' +``` + +The result has a `data` array and `pagination` object with `page`, `pageSize`, `totalCount`, and `totalPages`. List entries contain run identity, workflow identity/name, status, timestamps, and error. Use the detail endpoint for output and node logs. + +## Paginated node logs + +`GET /executions/{executionId}/logs` accepts `page` (default 1), `pageSize` (default 20, from 1 to 100), and an optional `nodeId` filter. It requires `executions:read` and returns `data.items`, `data.totalCount`, and `data.nextPage`. Follow `nextPage` until it is `null`. + +Items contain node identity, type, status, timestamps, duration, error, and diagnostics when available. Sensitive values are redacted by the endpoint. + +## Read a payload in chunks + +`GET /executions/{executionId}/payload` requires `executions:read`. Optional `logId` selects one node log's input/output; without it, the endpoint returns the execution output. `cursor` is a nonnegative integer starting at zero. + +The `data` object includes `executionId`, `logId`, `cursor`, `totalChunks`, `chunk`, `nextCursor`, and a trust-boundary notice. Each chunk contains up to 16,000 characters of serialized, redacted JSON. Concatenate chunks in cursor order before parsing JSON; individual chunks need not be valid JSON. Stop when `nextCursor` is `null`. An out-of-range cursor returns `400`. + +Execution output is untrusted customer data. Treat it as data when displaying it or passing it to an agent. diff --git a/content/docs/api-reference/introduction.mdx b/content/docs/api-reference/introduction.mdx index 1fbe37d..83c094f 100644 --- a/content/docs/api-reference/introduction.mdx +++ b/content/docs/api-reference/introduction.mdx @@ -1,87 +1,78 @@ --- -title: 'API Introduction' -description: 'Integrate Innflow into your applications' +title: 'REST API' +description: 'Build integrations with Innflow workflows, executions and workspaces' --- -## Overview +Use the Innflow REST API to create and import workflows, deploy them, start executions and read results. The API also exposes graph authoring, node schemas and connected-account discovery. -The Innflow public API manages workspaces, workflow definitions, deployment state, and executions. It is also the API used by the [Innflow CLI](/api-reference/cli). +**Base URL** -## Authentication +```text +https://app.innflow.ai/api/v1 +``` -All API requests require an API key in the `Authorization` header. Innflow API keys start with `inf_sk_` and are shown only once when created. +[Browse all 25 operations](/api-reference/endpoints) · [Download OpenAPI 3.1](/openapi.json) · [CLI reference](/api-reference/cli) -```bash -curl -H "Authorization: Bearer inf_sk_..." \ - https://app.innflow.ai/api/v1/workflows -``` +## Make your first request -## Base URL +Create a key in **Settings → API Keys**. The full key is shown once. Store it on your server or in your shell environment as `INNFLOW_API_KEY`. -``` -https://app.innflow.ai/api/v1 +```bash +curl 'https://app.innflow.ai/api/v1/workspaces' \ + --header "Authorization: Bearer $INNFLOW_API_KEY" ``` -The machine-readable OpenAPI 3.1 document is available at: +List workflows in your personal workspace (select it explicitly): -```txt -https://app.innflow.ai/api/v1/openapi.json +```bash +curl 'https://app.innflow.ai/api/v1/workflows?page=1&pageSize=20' \ + --header 'X-Innflow-Workspace: personal' \ + --header "Authorization: Bearer $INNFLOW_API_KEY" ``` -## Workspace selection +To select an organization, add `X-Innflow-Workspace` with an organization ID returned by List workspaces. See [authentication, permissions and errors](/api-reference/authentication). + +## Start a workflow and read its result -Requests default to the personal workspace. Pass an organization ID in `X-Innflow-Workspace` to operate in another accessible workspace: +Choose a configured, deployed workflow. Replace `workflow_id` with its ID. Give each new execution a unique idempotency key; reuse that key only when retrying the same request. ```bash --H "X-Innflow-Workspace: org_123" +curl --request POST 'https://app.innflow.ai/api/v1/workflows/workflow_id/execute' \ + --header "Authorization: Bearer $INNFLOW_API_KEY" \ + --header 'Content-Type: application/json' \ + --header 'Idempotency-Key: customer-onboarding-001' \ + --data '{"input":{"email":"customer@example.com"}}' ``` -Read-only workspace members cannot use write endpoints. +The response's `data.executionId` identifies the asynchronous run. If several triggers are eligible, include `triggerNodeId` in the request body. -## Idempotent writes - -Create, import, duplicate, deploy, undeploy, and execute requests support an `Idempotency-Key` header. Repeating the same request with the same key replays the saved response for 24 hours; reusing a key with a different request returns a conflict. - -## Endpoints +```bash +curl 'https://app.innflow.ai/api/v1/executions/execution_id?view=summary' \ + --header "Authorization: Bearer $INNFLOW_API_KEY" +``` -| Method | Endpoint | Purpose | -| --- | --- | --- | -| `GET` | `/workspaces` | List accessible workspaces | -| `GET`, `POST` | `/workflows` | List or create workflows | -| `POST` | `/workflows/import` | Import a workflow graph | -| `GET`, `PATCH`, `DELETE` | `/workflows/{workflowId}` | Read, update, or delete one workflow | -| `POST` | `/workflows/{workflowId}/duplicate` | Duplicate a workflow | -| `POST` | `/workflows/{workflowId}/deploy` | Deploy a workflow | -| `POST` | `/workflows/{workflowId}/undeploy` | Return a workflow to draft state | -| `POST` | `/workflows/{workflowId}/execute` | Start a deployed workflow | -| `GET` | `/executions` | List executions | -| `GET` | `/executions/{executionId}` | Read execution details and node logs | +Poll with backoff until the execution finishes. Use [execution logs](/api-reference/endpoints/execution-logs) for node-level diagnostics and [execution payload](/api-reference/endpoints/execution-payload) for chunked output. -## Workflow layout metadata +## API areas -Workflow definitions can carry `canvasLayoutVersion` alongside their nodes and connections. Version `0` identifies a definition eligible for the editor's one-time horizontal arrangement; version `1` identifies one already using that layout version. Imports without the field default to `0`, while newly created workflows start at `1`. Duplicating a workflow preserves its value. +| Area | What you can do | +| --- | --- | +| [Workspaces](/api-reference/endpoints/list-workspaces) | Discover the workspaces you can access | +| [Workflows](/api-reference/endpoints/list-workflows) | Create, import, inspect, update, duplicate, deploy and delete workflows | +| [Executions](/api-reference/endpoints/list-executions) | Start runs, inspect status, read logs and retrieve output | +| [Authoring](/api-reference/authoring) | Edit graphs, validate configuration and configure triggers | +| [Catalog](/api-reference/endpoints/list-node-types) | Discover node types, fields, connected accounts and operation receipts | -Preserve this field when exporting and reimporting a definition. It tracks canvas arrangement separately from execution version or deployment state; importing an older definition does not rearrange it until it is opened in an editable editor. Use the current OpenAPI schema for endpoint-specific input fields. +## OpenAPI and client tooling -## Execute a Workflow +[Download the complete documentation OpenAPI snapshot](/openapi.json) to import into API clients. It uses the absolute production API base URL and describes the request parameters and bodies for all 25 documented operations. -Workflows must be deployed before they can be executed through the API. +The application also serves its own [OpenAPI document](https://app.innflow.ai/api/v1/openapi.json). That document currently covers a smaller core subset. The documentation snapshot includes the additional routes reviewed on September 28, 2026. Response bodies are described per endpoint; the snapshot does not promise exhaustive typed response models. -```bash -curl -X POST https://app.innflow.ai/api/v1/workflows/{workflowId}/execute \ - -H "Authorization: Bearer inf_sk_..." \ - -H "Content-Type: application/json" \ - -H "Idempotency-Key: run-customer-onboarding-123" \ - -d '{ - "input": { - "email": "customer@example.com", - "message": "Need help with onboarding" - } - }' -``` +## Supported surface -The response includes the workflow ID, event IDs, and a `triggered` status. +These pages describe the customer REST routes under `/api/v1`. Authoring availability is deployment-dependent; check [authoring context](/api-reference/endpoints/authoring-context) before editing graphs. Workflow webhooks and [MCP](/mcp) have their own setup guides. Internal service endpoints and browser-session APIs are not customer REST contracts. -## Errors and request IDs +## Workflow layout metadata -JSON errors include a human-readable `error`, an optional machine-readable `code`, and a `requestId`. Responses also include `X-Request-Id`; provide it to support when investigating a failed request. +Workflow definitions can carry `canvasLayoutVersion` alongside nodes and connections. Version `0` identifies a definition eligible for the editor’s one-time horizontal arrangement; version `1` identifies one already using that layout version. Imports default to `0`, new workflows start at `1`, and duplicates preserve the value. Preserve this field across exports and imports. It tracks canvas arrangement separately from execution version or deployment state. diff --git a/content/docs/api-reference/meta.json b/content/docs/api-reference/meta.json index 6e4f0d3..f15fd47 100644 --- a/content/docs/api-reference/meta.json +++ b/content/docs/api-reference/meta.json @@ -1 +1,5 @@ -{"title": "API Reference", "root": true, "pages": ["introduction", "cli"]} \ No newline at end of file +{ + "title": "API Reference", + "root": true, + "pages": ["introduction", "authentication", "workflows", "executions", "authoring", "errors", "endpoints", "cli"] +} diff --git a/content/docs/api-reference/workflows.mdx b/content/docs/api-reference/workflows.mdx new file mode 100644 index 0000000..67b3a4c --- /dev/null +++ b/content/docs/api-reference/workflows.mdx @@ -0,0 +1,150 @@ +--- +title: "Workflows" +description: "List, create, import, update, duplicate, deploy, and delete workflow definitions" +--- + +All paths below are relative to `https://app.innflow.ai/api/v1`. Use [bearer authentication and an explicit workspace](/api-reference/authentication). Reads require `workflows:read`; writes require `workflows:write` for scoped keys. + +## List workflows + +`GET /workflows` returns standard workflows, ordered by most recently updated first. + +| Query | Default | Description | +| --- | --- | --- | +| `page` | `1` | Positive page number | +| `pageSize` | `20` | Results per page, maximum `100` | +| `search` | Empty | Case-insensitive name search | + +```bash +curl --fail-with-body 'https://app.innflow.ai/api/v1/workflows?page=1&pageSize=20&search=Leasing' \ + -H "Authorization: Bearer $INNFLOW_API_KEY" \ + -H "X-Innflow-Workspace: $INNFLOW_WORKSPACE" +``` + +```json +{ + "data": [{ + "id": "workflow_example", + "name": "Leasing digest", + "icon": null, + "iconColor": null, + "deploymentStatus": "DRAFT", + "deployedAt": null, + "createdAt": "2026-09-28T12:00:00.000Z", + "updatedAt": "2026-09-28T12:00:00.000Z" + }], + "pagination": { "page": 1, "pageSize": 20, "totalCount": 1, "totalPages": 1 } +} +``` + +## Create a workflow + +`POST /workflows` creates a draft with an initial placeholder node. It does not create a complete automation. The optional JSON `name` sets the title. Returns `201` with the workflow summary under `data`. + +```bash +curl --fail-with-body -X POST 'https://app.innflow.ai/api/v1/workflows' \ + -H "Authorization: Bearer $INNFLOW_API_KEY" \ + -H "X-Innflow-Workspace: $INNFLOW_WORKSPACE" \ + -H 'Content-Type: application/json' \ + -H 'Idempotency-Key: create-leasing-digest-001' \ + -d '{"name":"Leasing digest"}' +``` + +Configure its trigger, nodes, and connections in the editor, or import a definition. Use a new idempotency key for each intentionally new workflow. + +## Read a workflow + +`GET /workflows/{workflowId}` returns `{ "data": ... }` with metadata, `nodes`, and `connections`. Node entries contain `id`, `type`, `name`, `position`, and `data`. Connections use `fromNodeId`, `toNodeId`, `fromOutput`, and `toInput`. + +```bash +curl --fail-with-body "https://app.innflow.ai/api/v1/workflows/$WORKFLOW_ID" \ + -H "Authorization: Bearer $INNFLOW_API_KEY" \ + -H "X-Innflow-Workspace: $INNFLOW_WORKSPACE" +``` + +Optional `view=summary` returns metadata and node/connection counts instead of the graph. `nodeIds` accepts a comma-separated selection of at most 50 node IDs; it filters nodes, not the connections array. + +## Update metadata + +`PATCH /workflows/{workflowId}` accepts at least one of `name`, `icon`, or `iconColor`. `name` must be a nonempty string. `icon` and `iconColor` can be cleared with `null`. This endpoint updates metadata, not the workflow graph. Returns `200` with the updated summary under `data`. + +```bash +curl --fail-with-body -X PATCH "https://app.innflow.ai/api/v1/workflows/$WORKFLOW_ID" \ + -H "Authorization: Bearer $INNFLOW_API_KEY" \ + -H "X-Innflow-Workspace: $INNFLOW_WORKSPACE" \ + -H 'Content-Type: application/json' \ + -d '{"name":"Daily leasing digest"}' +``` + +## Import a definition + +`POST /workflows/import` creates a new draft. It accepts a JSON object with these fields: + +| Field | Required | Description | +| --- | --- | --- | +| `name` | No | 1–255 characters when supplied | +| `icon`, `iconColor` | No | Optional presentation values | +| `canvasLayoutVersion` | No | `0` or `1`; defaults to `0` | +| `nodes` | Yes | Between 1 and 200 nodes | +| `edges` | No | Array of connections by zero-based node index; defaults to empty | + +Each node requires a supported `type` and `position: { "x": 0, "y": 0 }`. It can include `name` and a `data` object. Each edge requires integer `source` and `target` indices into the `nodes` array. Optional `fromOutput` and `toInput` select handles; `sourceHandle` and `targetHandle` are accepted aliases. + +This is the smallest illustrative draft definition, not a runnable automation: + +```json +{ + "name": "Integration draft", + "canvasLayoutVersion": 1, + "nodes": [{ "type": "INITIAL", "position": { "x": 0, "y": 0 }, "data": {} }], + "edges": [] +} +``` + +Save the definition as `workflow.json`, then import it: + +```bash +curl --fail-with-body -X POST 'https://app.innflow.ai/api/v1/workflows/import' \ + -H "Authorization: Bearer $INNFLOW_API_KEY" \ + -H "X-Innflow-Workspace: $INNFLOW_WORKSPACE" \ + -H 'Content-Type: application/json' \ + -H 'Idempotency-Key: import-integration-draft-001' \ + --data-binary @workflow.json +``` + +Returns `201` with `id`, `name`, `deploymentStatus`, `nodeCount`, `edgeCount`, `createdAt`, and `updatedAt` under `data`. The import creates fresh node IDs. The read endpoint's `connections` array is not the import endpoint's `edges` array: convert node-ID references to array indices before a REST round trip. The [CLI](/api-reference/cli) provides import/export commands. + +The accepted `description` field is not currently persisted by this import handler. [Layout metadata](/api-reference/introduction#workflow-layout-metadata) should be preserved across exports and imports. Review connected-account references and node configuration before deploying an imported workflow. + +## Duplicate a workflow + +`POST /workflows/{workflowId}/duplicate` accepts an optional `name`. Returns `201` with a new draft summary under `data`; omitted names use the original name with ` (Copy)`. Node IDs are regenerated and layout metadata is preserved. This request supports `Idempotency-Key`. + +## Deploy or undeploy + +| Action | Endpoint | Result | +| --- | --- | --- | +| Deploy | `POST /workflows/{workflowId}/deploy` | Marks the workflow deployed and resumes eligible paused schedules | +| Undeploy | `POST /workflows/{workflowId}/undeploy` | Returns the workflow to draft and attempts to pause active schedules | + +No JSON body is required for these API-key requests. Both return `200` with a workflow summary under `data`. Deploying an already deployed workflow or undeploying one that is not deployed returns `422`. + +```bash +curl --fail-with-body -X POST "https://app.innflow.ai/api/v1/workflows/$WORKFLOW_ID/deploy" \ + -H "Authorization: Bearer $INNFLOW_API_KEY" \ + -H "X-Innflow-Workspace: $INNFLOW_WORKSPACE" +``` + +Deployment can activate configured schedules. Inspect the workflow first. These endpoints do not provide the `Idempotency-Key` replay behavior used by create/import/duplicate/execute. After an ambiguous timeout, read the workflow's deployment state before retrying. + +To start a run, see [executions](/api-reference/executions). + +## Delete a workflow + +`DELETE /workflows/{workflowId}` deletes the workflow and its associated execution history. It returns `200` with: + +```json +{ "data": { "id": "workflow_example", "deleted": true } } +``` + +Deletion is destructive. Read and confirm the workflow ID and workspace before issuing the request. A resource outside the selected scope returns `404`. diff --git a/package.json b/package.json index 069ba2a..a14c6a3 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,10 @@ "check": "npm run types:check", "verify": "node scripts/verify-build.mjs", "docs:sync": "node scripts/sync-tool-reference.mjs", - "docs:check": "node scripts/check-tool-docs.mjs" + "docs:check": "node scripts/check-tool-docs.mjs", + "api:sync": "node scripts/sync-api-reference.mjs", + "api:check": "node scripts/sync-api-reference.mjs --check", + "api:source-check": "node scripts/sync-api-reference.mjs --source-check" }, "dependencies": { "cn": "^0.3.0", diff --git a/public/openapi.json b/public/openapi.json new file mode 100644 index 0000000..08ca69c --- /dev/null +++ b/public/openapi.json @@ -0,0 +1,2424 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "Innflow REST API", + "version": "2026-09-28", + "description": "Customer REST API reference. Authoring operations depend on authoring availability. Internal portal event ingestion is not a customer API." + }, + "servers": [ + { + "url": "https://app.innflow.ai/api/v1" + } + ], + "security": [ + { + "bearerAuth": [] + } + ], + "components": { + "securitySchemes": { + "bearerAuth": { + "type": "http", + "scheme": "bearer", + "description": "Innflow API key. Keep credentials on the server." + } + } + }, + "paths": { + "/workspaces": { + "get": { + "operationId": "list-workspaces", + "summary": "List workspaces", + "description": "List the personal workspace and organizations you belong to.", + "tags": [ + "Workspaces" + ], + "parameters": [ + { + "name": "X-Innflow-Workspace", + "in": "header", + "description": "Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Returns data as an array. Each entry has id, name, type and role; organization entries also include slug.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "default": { + "description": "Error response. See authentication and errors guide; proxy rate-limit responses may not have this envelope.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "code": { + "type": "string" + }, + "requestId": { + "type": "string" + }, + "details": {} + }, + "required": [ + "error" + ] + } + } + } + } + } + } + }, + "/workflows": { + "get": { + "operationId": "list-workflows", + "summary": "List workflows", + "description": "List standard workflows accessible in the selected workspace, newest updated first.", + "tags": [ + "Workflows" + ], + "parameters": [ + { + "name": "X-Innflow-Workspace", + "in": "header", + "description": "Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope.", + "schema": { + "type": "string" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number, starting at 1.", + "schema": { + "type": "integer", + "minimum": 1, + "default": 1 + }, + "required": false + }, + { + "name": "pageSize", + "in": "query", + "description": "Results per page (1–100).", + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20 + }, + "required": false + }, + { + "name": "search", + "in": "query", + "description": "Case-insensitive workflow name filter.", + "schema": { + "type": "string" + }, + "required": false + } + ], + "responses": { + "200": { + "description": "Returns data as an array of workflow summaries and pagination with page, pageSize, totalCount and totalPages.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "default": { + "description": "Error response. See authentication and errors guide; proxy rate-limit responses may not have this envelope.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "code": { + "type": "string" + }, + "requestId": { + "type": "string" + }, + "details": {} + }, + "required": [ + "error" + ] + } + } + } + } + } + }, + "post": { + "operationId": "create-workflow", + "summary": "Create workflow", + "description": "Create a draft workflow with an initial node. An omitted or empty name uses the default untitled name.", + "tags": [ + "Workflows" + ], + "parameters": [ + { + "name": "X-Innflow-Workspace", + "in": "header", + "description": "Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope.", + "schema": { + "type": "string" + } + }, + { + "name": "Idempotency-Key", + "in": "header", + "required": false, + "description": "Optional replay key, at most 200 characters. Same request and key replay for 24 hours.", + "schema": { + "type": "string", + "maxLength": 200 + } + } + ], + "responses": { + "201": { + "description": "Returns data with id, name, icon, iconColor, deploymentStatus, deployedAt, createdAt and updatedAt.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "default": { + "description": "Error response. See authentication and errors guide; proxy rate-limit responses may not have this envelope.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "code": { + "type": "string" + }, + "requestId": { + "type": "string" + }, + "details": {} + }, + "required": [ + "error" + ] + } + } + } + } + }, + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + } + }, + "example": { + "name": "Customer onboarding" + } + } + } + } + } + }, + "/workflows/import": { + "post": { + "operationId": "import-workflow", + "summary": "Import workflow", + "description": "Create a draft from 1–200 nodes and optional edges. Edge source and target are zero-based indexes into nodes. Node types must exist in the Innflow registry. description is accepted by the input schema but is not persisted by this endpoint.", + "tags": [ + "Workflows" + ], + "parameters": [ + { + "name": "X-Innflow-Workspace", + "in": "header", + "description": "Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope.", + "schema": { + "type": "string" + } + }, + { + "name": "Idempotency-Key", + "in": "header", + "required": false, + "description": "Optional replay key, at most 200 characters. Same request and key replay for 24 hours.", + "schema": { + "type": "string", + "maxLength": 200 + } + } + ], + "responses": { + "201": { + "description": "Returns data with id, name, deploymentStatus, nodeCount, edgeCount, createdAt and updatedAt. Node IDs are generated on import. canvasLayoutVersion defaults to 0; preserve 1 when reimporting an already arranged graph.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "default": { + "description": "Error response. See authentication and errors guide; proxy rate-limit responses may not have this envelope.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "code": { + "type": "string" + }, + "requestId": { + "type": "string" + }, + "details": {} + }, + "required": [ + "error" + ] + } + } + } + } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "canvasLayoutVersion": { + "default": 0, + "type": "integer", + "minimum": 0, + "maximum": 1 + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 255 + }, + "description": { + "type": "string" + }, + "icon": { + "type": "string", + "maxLength": 100 + }, + "iconColor": { + "type": "string", + "maxLength": 20 + }, + "nodes": { + "minItems": 1, + "maxItems": 200, + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "minLength": 1 + }, + "name": { + "type": "string", + "maxLength": 255 + }, + "position": { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + }, + "required": [ + "x", + "y" + ] + }, + "data": { + "default": {}, + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type", + "position" + ] + } + }, + "edges": { + "default": [], + "type": "array", + "items": { + "type": "object", + "properties": { + "source": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "target": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "fromOutput": { + "type": "string" + }, + "toInput": { + "type": "string" + }, + "sourceHandle": { + "type": "string" + }, + "targetHandle": { + "type": "string" + } + }, + "required": [ + "source", + "target" + ] + } + } + }, + "required": [ + "nodes" + ] + }, + "example": { + "name": "API workflow", + "nodes": [ + { + "type": "MANUAL_TRIGGER", + "position": { + "x": 0, + "y": 0 + }, + "data": {} + } + ], + "edges": [] + } + } + } + } + } + }, + "/workflows/{workflowId}": { + "get": { + "operationId": "get-workflow", + "summary": "Get workflow", + "description": "Read workflow metadata and its graph.", + "tags": [ + "Workflows" + ], + "parameters": [ + { + "name": "workflowId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "X-Innflow-Workspace", + "in": "header", + "description": "Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope.", + "schema": { + "type": "string" + } + }, + { + "name": "view", + "in": "query", + "description": "Use summary to omit nodes and connections.", + "schema": { + "type": "string", + "enum": [ + "summary" + ] + }, + "required": false + }, + { + "name": "nodeIds", + "in": "query", + "description": "Comma-separated list of at most 50 node IDs. Filters nodes only; connections remain unfiltered.", + "schema": { + "type": "string" + }, + "required": false + } + ], + "responses": { + "200": { + "description": "Returns data with workflow metadata, graphRevision, executionVersion, canvasLayoutVersion, nodes and connections. Summary view returns nodeCount and connectionCount instead of graph arrays.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "default": { + "description": "Error response. See authentication and errors guide; proxy rate-limit responses may not have this envelope.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "code": { + "type": "string" + }, + "requestId": { + "type": "string" + }, + "details": {} + }, + "required": [ + "error" + ] + } + } + } + } + } + }, + "patch": { + "operationId": "update-workflow", + "summary": "Update workflow", + "description": "Change workflow metadata. Supply at least one of name, icon or iconColor. name must be non-empty after trimming. Use the graph endpoint for node and connection edits.", + "tags": [ + "Workflows" + ], + "parameters": [ + { + "name": "workflowId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "X-Innflow-Workspace", + "in": "header", + "description": "Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Returns data with id, name, icon, iconColor, deploymentStatus, deployedAt, createdAt and updatedAt.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "default": { + "description": "Error response. See authentication and errors guide; proxy rate-limit responses may not have this envelope.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "code": { + "type": "string" + }, + "requestId": { + "type": "string" + }, + "details": {} + }, + "required": [ + "error" + ] + } + } + } + } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1 + }, + "icon": { + "type": [ + "string", + "null" + ] + }, + "iconColor": { + "type": [ + "string", + "null" + ] + } + } + }, + "example": { + "name": "Updated workflow" + } + } + } + } + }, + "delete": { + "operationId": "delete-workflow", + "summary": "Delete workflow", + "description": "Delete a workflow and its execution history. This is destructive.", + "tags": [ + "Workflows" + ], + "parameters": [ + { + "name": "workflowId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "X-Innflow-Workspace", + "in": "header", + "description": "Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Returns data with id and deleted: true.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "default": { + "description": "Error response. See authentication and errors guide; proxy rate-limit responses may not have this envelope.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "code": { + "type": "string" + }, + "requestId": { + "type": "string" + }, + "details": {} + }, + "required": [ + "error" + ] + } + } + } + } + } + } + }, + "/workflows/{workflowId}/duplicate": { + "post": { + "operationId": "duplicate-workflow", + "summary": "Duplicate workflow", + "description": "Copy the graph into a new draft, preserving canvas layout metadata and generating new node IDs. Trigger connection state is refreshed.", + "tags": [ + "Workflows" + ], + "parameters": [ + { + "name": "workflowId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "X-Innflow-Workspace", + "in": "header", + "description": "Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope.", + "schema": { + "type": "string" + } + }, + { + "name": "Idempotency-Key", + "in": "header", + "required": false, + "description": "Optional replay key, at most 200 characters. Same request and key replay for 24 hours.", + "schema": { + "type": "string", + "maxLength": 200 + } + } + ], + "responses": { + "201": { + "description": "Returns data with id, name, icon, iconColor, deploymentStatus, deployedAt, createdAt and updatedAt.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "default": { + "description": "Error response. See authentication and errors guide; proxy rate-limit responses may not have this envelope.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "code": { + "type": "string" + }, + "requestId": { + "type": "string" + }, + "details": {} + }, + "required": [ + "error" + ] + } + } + } + } + }, + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + } + }, + "example": { + "name": "Workflow copy" + } + } + } + } + } + }, + "/workflows/{workflowId}/deploy": { + "post": { + "operationId": "deploy-workflow", + "summary": "Deploy workflow", + "description": "Set a draft workflow to deployed and resume eligible paused schedules. Already-deployed workflows return 422. Validate configuration before deploying.\n\nWith API-key authentication, this endpoint does not replay Idempotency-Key receipts. MCP OAuth contract calls have separate transaction semantics; see the authoring guide.", + "tags": [ + "Workflows" + ], + "parameters": [ + { + "name": "workflowId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "X-Innflow-Workspace", + "in": "header", + "description": "Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Returns data with id, name, icon, iconColor, deploymentStatus, deployedAt, createdAt and updatedAt.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "default": { + "description": "Error response. See authentication and errors guide; proxy rate-limit responses may not have this envelope.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "code": { + "type": "string" + }, + "requestId": { + "type": "string" + }, + "details": {} + }, + "required": [ + "error" + ] + } + } + } + } + } + } + }, + "/workflows/{workflowId}/undeploy": { + "post": { + "operationId": "undeploy-workflow", + "summary": "Undeploy workflow", + "description": "Return a deployed workflow to draft and pause active schedules. A workflow that is not currently deployed returns 422.\n\nWith API-key authentication, this endpoint does not replay Idempotency-Key receipts.", + "tags": [ + "Workflows" + ], + "parameters": [ + { + "name": "workflowId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "X-Innflow-Workspace", + "in": "header", + "description": "Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Returns data with id, name, icon, iconColor, deploymentStatus, deployedAt, createdAt and updatedAt.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "default": { + "description": "Error response. See authentication and errors guide; proxy rate-limit responses may not have this envelope.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "code": { + "type": "string" + }, + "requestId": { + "type": "string" + }, + "details": {} + }, + "required": [ + "error" + ] + } + } + } + } + } + } + }, + "/workflows/{workflowId}/execute": { + "post": { + "operationId": "execute-workflow", + "summary": "Execute workflow", + "description": "Start an asynchronous execution of a deployed workflow. Supply triggerNodeId when more than one eligible trigger exists. A successful request means the run was triggered, not that it completed.", + "tags": [ + "Executions" + ], + "parameters": [ + { + "name": "workflowId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "X-Innflow-Workspace", + "in": "header", + "description": "Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope.", + "schema": { + "type": "string" + } + }, + { + "name": "Idempotency-Key", + "in": "header", + "required": false, + "description": "Optional replay key, at most 200 characters. Same request and key replay for 24 hours.", + "schema": { + "type": "string", + "maxLength": 200 + } + } + ], + "responses": { + "200": { + "description": "Returns data with workflowId, eventIds, executionId and status: triggered. Poll Get execution with executionId. MCP OAuth contract requests return 202 and include an operationId receipt.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "default": { + "description": "Error response. See authentication and errors guide; proxy rate-limit responses may not have this envelope.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "code": { + "type": "string" + }, + "requestId": { + "type": "string" + }, + "details": {} + }, + "required": [ + "error" + ] + } + } + } + } + }, + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "input": { + "type": "object", + "additionalProperties": true + }, + "triggerNodeId": { + "type": "string" + } + } + }, + "example": { + "input": { + "email": "customer@example.com" + } + } + } + } + } + } + }, + "/executions": { + "get": { + "operationId": "list-executions", + "summary": "List executions", + "description": "List accessible executions, newest started first.", + "tags": [ + "Executions" + ], + "parameters": [ + { + "name": "X-Innflow-Workspace", + "in": "header", + "description": "Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope.", + "schema": { + "type": "string" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number, starting at 1.", + "schema": { + "type": "integer", + "minimum": 1, + "default": 1 + }, + "required": false + }, + { + "name": "pageSize", + "in": "query", + "description": "Results per page (1–100).", + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20 + }, + "required": false + }, + { + "name": "workflowId", + "in": "query", + "description": "Filter to one workflow.", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "status", + "in": "query", + "description": "Filter by execution status.", + "schema": { + "type": "string", + "enum": [ + "RUNNING", + "SUCCESS", + "FAILED", + "CANCELLED" + ] + }, + "required": false + } + ], + "responses": { + "200": { + "description": "Returns data as an array with id, workflowId, workflowName, status, startedAt, completedAt and error; pagination has page, pageSize, totalCount and totalPages.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "default": { + "description": "Error response. See authentication and errors guide; proxy rate-limit responses may not have this envelope.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "code": { + "type": "string" + }, + "requestId": { + "type": "string" + }, + "details": {} + }, + "required": [ + "error" + ] + } + } + } + } + } + } + }, + "/executions/{executionId}": { + "get": { + "operationId": "get-execution", + "summary": "Get execution", + "description": "Read execution status, output and node logs. Use summary for a smaller polling response.", + "tags": [ + "Executions" + ], + "parameters": [ + { + "name": "executionId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "X-Innflow-Workspace", + "in": "header", + "description": "Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope.", + "schema": { + "type": "string" + } + }, + { + "name": "view", + "in": "query", + "description": "Use summary to omit large output and logs.", + "schema": { + "type": "string", + "enum": [ + "summary" + ] + }, + "required": false + } + ], + "responses": { + "200": { + "description": "Returns a data object with execution metadata. Full API-key responses include output and nodeLogs; summary responses omit large payloads. A recently accepted asynchronous run may not be readable immediately; retry with backoff. MCP OAuth responses may report QUEUED or DISPATCH_FAILED before a run record exists.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "default": { + "description": "Error response. See authentication and errors guide; proxy rate-limit responses may not have this envelope.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "code": { + "type": "string" + }, + "requestId": { + "type": "string" + }, + "details": {} + }, + "required": [ + "error" + ] + } + } + } + } + } + } + }, + "/executions/{executionId}/logs": { + "get": { + "operationId": "execution-logs", + "summary": "List execution logs", + "description": "Read paginated node log metadata, ordered by start time then ID. Payload values are redacted.", + "tags": [ + "Executions" + ], + "parameters": [ + { + "name": "executionId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "X-Innflow-Workspace", + "in": "header", + "description": "Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope.", + "schema": { + "type": "string" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number, starting at 1.", + "schema": { + "type": "integer", + "minimum": 1, + "default": 1 + }, + "required": false + }, + { + "name": "pageSize", + "in": "query", + "description": "Results per page (1–100).", + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20 + }, + "required": false + }, + { + "name": "nodeId", + "in": "query", + "description": "Filter logs to one node.", + "schema": { + "type": "string" + }, + "required": false + } + ], + "responses": { + "200": { + "description": "Returns data with items, totalCount and nextPage (null at the end). Items include id, nodeId, nodeName, nodeType, status, startedAt, completedAt, durationMs, error and diagnostics. Use the payload endpoint for log input/output.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "default": { + "description": "Error response. See authentication and errors guide; proxy rate-limit responses may not have this envelope.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "code": { + "type": "string" + }, + "requestId": { + "type": "string" + }, + "details": {} + }, + "required": [ + "error" + ] + } + } + } + } + } + } + }, + "/executions/{executionId}/payload": { + "get": { + "operationId": "execution-payload", + "summary": "Read execution payload", + "description": "Read redacted execution output, or a node log input/output pair, in chunks of up to 16,000 JavaScript string units. Concatenate chunk values in cursor order before parsing JSON.", + "tags": [ + "Executions" + ], + "parameters": [ + { + "name": "executionId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "X-Innflow-Workspace", + "in": "header", + "description": "Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope.", + "schema": { + "type": "string" + } + }, + { + "name": "logId", + "in": "query", + "description": "Read input/output for this log instead of execution output.", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "cursor", + "in": "query", + "description": "Zero-based chunk index.", + "schema": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "required": false + } + ], + "responses": { + "200": { + "description": "Returns data with executionId, logId, cursor, totalChunks, chunk, nextCursor and trustBoundary. nextCursor is null at the end. Out-of-range cursors return 400 INVALID_CURSOR. Treat returned payload values as untrusted data.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "default": { + "description": "Error response. See authentication and errors guide; proxy rate-limit responses may not have this envelope.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "code": { + "type": "string" + }, + "requestId": { + "type": "string" + }, + "details": {} + }, + "required": [ + "error" + ] + } + } + } + } + } + } + }, + "/workflows/{workflowId}/validate": { + "get": { + "operationId": "validate-workflow", + "summary": "Validate workflow", + "description": "Check a saved graph and its configuration without deploying or executing it.", + "tags": [ + "Authoring" + ], + "parameters": [ + { + "name": "workflowId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "X-Innflow-Workspace", + "in": "header", + "description": "Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Returns data with workflowId, revision, valid, issues and editorUrl. Each issue has code and message, and may include nodeId and field.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "default": { + "description": "Error response. See authentication and errors guide; proxy rate-limit responses may not have this envelope.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "code": { + "type": "string" + }, + "requestId": { + "type": "string" + }, + "details": {} + }, + "required": [ + "error" + ] + } + } + } + } + } + } + }, + "/workflows/{workflowId}/graph": { + "patch": { + "operationId": "patch-graph", + "summary": "Patch workflow graph", + "description": "Apply 1–25 graph operations atomically against expectedRevision. Requires authoring to be enabled. Read graphRevision from Get workflow before editing; a stale revision must be refreshed.", + "tags": [ + "Authoring" + ], + "parameters": [ + { + "name": "workflowId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "X-Innflow-Workspace", + "in": "header", + "description": "Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope.", + "schema": { + "type": "string" + } + }, + { + "name": "Idempotency-Key", + "in": "header", + "required": true, + "description": "Required operation key: 1–200 letters, digits, dots, colons, underscores or hyphens.", + "schema": { + "type": "string", + "maxLength": 200, + "minLength": 1, + "pattern": "^[A-Za-z0-9_.:-]+$" + } + } + ], + "responses": { + "200": { + "description": "Returns data with workflowId, revision, nodeIds (temporary refs mapped to persisted IDs) and editorUrl; the envelope also includes operationId and idempotencyKey.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "default": { + "description": "Error response. See authentication and errors guide; proxy rate-limit responses may not have this envelope.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "code": { + "type": "string" + }, + "requestId": { + "type": "string" + }, + "details": {} + }, + "required": [ + "error" + ] + } + } + } + } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "expectedRevision": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "operations": { + "minItems": 1, + "maxItems": 25, + "type": "array", + "items": { + "oneOf": [ + { + "type": "object", + "properties": { + "operation": { + "type": "string", + "const": "addNode" + }, + "ref": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "pattern": "^[A-Za-z0-9_-]+$" + }, + "type": { + "type": "string", + "minLength": 1 + }, + "name": { + "type": "string", + "maxLength": 255 + }, + "position": { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + }, + "required": [ + "x", + "y" + ] + }, + "data": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "operation", + "ref", + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "operation": { + "type": "string", + "const": "configureNode" + }, + "nodeId": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "pattern": "^[A-Za-z0-9_-]+$" + }, + "data": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "operation", + "nodeId", + "data" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "operation": { + "type": "string", + "const": "removeNode" + }, + "nodeId": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "pattern": "^[A-Za-z0-9_-]+$" + } + }, + "required": [ + "operation", + "nodeId" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "operation": { + "type": "string", + "const": "moveNode" + }, + "nodeId": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "pattern": "^[A-Za-z0-9_-]+$" + }, + "position": { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + }, + "required": [ + "x", + "y" + ] + } + }, + "required": [ + "operation", + "nodeId", + "position" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "operation": { + "type": "string", + "const": "connect" + }, + "source": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "pattern": "^[A-Za-z0-9_-]+$" + }, + "target": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "pattern": "^[A-Za-z0-9_-]+$" + }, + "sourceHandle": { + "default": "main", + "type": "string", + "maxLength": 200 + }, + "targetHandle": { + "default": "main", + "type": "string", + "maxLength": 200 + } + }, + "required": [ + "operation", + "source", + "target" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "operation": { + "type": "string", + "const": "disconnect" + }, + "source": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "pattern": "^[A-Za-z0-9_-]+$" + }, + "target": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "pattern": "^[A-Za-z0-9_-]+$" + }, + "sourceHandle": { + "default": "main", + "type": "string", + "maxLength": 200 + }, + "targetHandle": { + "default": "main", + "type": "string", + "maxLength": 200 + } + }, + "required": [ + "operation", + "source", + "target" + ], + "additionalProperties": false + } + ] + } + } + }, + "required": [ + "expectedRevision", + "operations" + ], + "additionalProperties": false + }, + "example": { + "expectedRevision": 0, + "operations": [ + { + "operation": "addNode", + "ref": "new_trigger", + "type": "MANUAL_TRIGGER", + "position": { + "x": 0, + "y": 0 + } + } + ] + } + } + } + } + } + }, + "/workflows/{workflowId}/trigger": { + "post": { + "operationId": "configure-trigger", + "summary": "Configure trigger", + "description": "Configure a trigger on a saved graph using its nodeId and expectedRevision. Requires authoring to be enabled. Configuration fields depend on the trigger type; obtain its node schema first.", + "tags": [ + "Authoring" + ], + "parameters": [ + { + "name": "workflowId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "X-Innflow-Workspace", + "in": "header", + "description": "Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope.", + "schema": { + "type": "string" + } + }, + { + "name": "Idempotency-Key", + "in": "header", + "required": true, + "description": "Required operation key: 1–200 letters, digits, dots, colons, underscores or hyphens.", + "schema": { + "type": "string", + "maxLength": 200, + "minLength": 1, + "pattern": "^[A-Za-z0-9_.:-]+$" + } + } + ], + "responses": { + "200": { + "description": "Returns data with status (configured, needs_input, provider_handoff or pending), persisted, revision, nodePatch and optional missing/instructions. The envelope includes operationId and idempotencyKey. Follow handoff instructions if provider setup is needed.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "default": { + "description": "Error response. See authentication and errors guide; proxy rate-limit responses may not have this envelope.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "code": { + "type": "string" + }, + "requestId": { + "type": "string" + }, + "details": {} + }, + "required": [ + "error" + ] + } + } + } + } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "nodeId": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "pattern": "^[A-Za-z0-9_-]+$" + }, + "expectedRevision": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "config": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "nodeId", + "expectedRevision", + "config" + ], + "additionalProperties": false + }, + "example": { + "nodeId": "node_id", + "expectedRevision": 0, + "config": {} + } + } + } + } + } + }, + "/workflows/{workflowId}/node-options": { + "get": { + "operationId": "node-options", + "summary": "Get node field options", + "description": "Resolve options for a field on a saved node. Some dynamic provider selectors require opening the editor.", + "tags": [ + "Authoring" + ], + "parameters": [ + { + "name": "workflowId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "X-Innflow-Workspace", + "in": "header", + "description": "Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope.", + "schema": { + "type": "string" + } + }, + { + "name": "nodeId", + "in": "query", + "description": "Saved node ID.", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "field", + "in": "query", + "description": "Field name from the node schema.", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "search", + "in": "query", + "description": "Case-insensitive label filter.", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "cursor", + "in": "query", + "description": "Nonnegative option offset.", + "schema": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "required": false + } + ], + "responses": { + "200": { + "description": "Returns data with items (id and label), nextCursor and optional handoffUrl. Up to 100 options are returned. Follow handoffUrl when remote options require the editor.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "default": { + "description": "Error response. See authentication and errors guide; proxy rate-limit responses may not have this envelope.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "code": { + "type": "string" + }, + "requestId": { + "type": "string" + }, + "details": {} + }, + "required": [ + "error" + ] + } + } + } + } + } + } + }, + "/mcp/context": { + "get": { + "operationId": "authoring-context", + "summary": "Get authoring context", + "description": "Inspect the authenticated principal and authoring availability.", + "tags": [ + "Catalog" + ], + "parameters": [ + { + "name": "X-Innflow-Workspace", + "in": "header", + "description": "Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Returns data with workspace, userId, role, permissions, authoringEnabled and contractVersion. Check authoringEnabled before graph or trigger mutations.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "default": { + "description": "Error response. See authentication and errors guide; proxy rate-limit responses may not have this envelope.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "code": { + "type": "string" + }, + "requestId": { + "type": "string" + }, + "details": {} + }, + "required": [ + "error" + ] + } + } + } + } + } + } + }, + "/mcp/node-types": { + "get": { + "operationId": "list-node-types", + "summary": "Search node types", + "description": "Discover available node types and operations before creating graph nodes.", + "tags": [ + "Catalog" + ], + "parameters": [ + { + "name": "X-Innflow-Workspace", + "in": "header", + "description": "Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope.", + "schema": { + "type": "string" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number, starting at 1.", + "schema": { + "type": "integer", + "minimum": 1, + "default": 1 + }, + "required": false + }, + { + "name": "pageSize", + "in": "query", + "description": "Results per page (1–100).", + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20 + }, + "required": false + }, + { + "name": "search", + "in": "query", + "description": "Search the node catalog.", + "schema": { + "type": "string" + }, + "required": false + } + ], + "responses": { + "200": { + "description": "Returns data with items, totalCount, nextPage and contractVersion. Each item describes type, name, description, category, authMode and operations.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "default": { + "description": "Error response. See authentication and errors guide; proxy rate-limit responses may not have this envelope.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "code": { + "type": "string" + }, + "requestId": { + "type": "string" + }, + "details": {} + }, + "required": [ + "error" + ] + } + } + } + } + } + } + }, + "/mcp/node-types/{nodeType}": { + "get": { + "operationId": "get-node-type", + "summary": "Get node schema", + "description": "Get configuration fields, outputs and handles for a node type.", + "tags": [ + "Catalog" + ], + "parameters": [ + { + "name": "nodeType", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "X-Innflow-Workspace", + "in": "header", + "description": "Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope.", + "schema": { + "type": "string" + } + }, + { + "name": "operation", + "in": "query", + "description": "Operation identifier returned by the node catalog.", + "schema": { + "type": "string" + }, + "required": false + } + ], + "responses": { + "200": { + "description": "Returns data with type, optional operation, fields, outputs, handles and contractVersion. Use these fields to build configuration rather than guessing provider parameters.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "default": { + "description": "Error response. See authentication and errors guide; proxy rate-limit responses may not have this envelope.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "code": { + "type": "string" + }, + "requestId": { + "type": "string" + }, + "details": {} + }, + "required": [ + "error" + ] + } + } + } + } + } + } + }, + "/mcp/connections": { + "get": { + "operationId": "list-connections", + "summary": "List connections", + "description": "List active connected accounts for a provider returned by a node schema. This endpoint returns identifiers and display names, not credentials.", + "tags": [ + "Catalog" + ], + "parameters": [ + { + "name": "X-Innflow-Workspace", + "in": "header", + "description": "Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope.", + "schema": { + "type": "string" + } + }, + { + "name": "provider", + "in": "query", + "description": "Provider identifier from the node schema.", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "page", + "in": "query", + "description": "Page number, starting at 1.", + "schema": { + "type": "integer", + "minimum": 1, + "default": 1 + }, + "required": false + }, + { + "name": "pageSize", + "in": "query", + "description": "Results per page (1–100).", + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20 + }, + "required": false + } + ], + "responses": { + "200": { + "description": "Returns data with items (id, provider, name) and nextPage. An unknown provider returns 422 UNKNOWN_PROVIDER.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "default": { + "description": "Error response. See authentication and errors guide; proxy rate-limit responses may not have this envelope.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "code": { + "type": "string" + }, + "requestId": { + "type": "string" + }, + "details": {} + }, + "required": [ + "error" + ] + } + } + } + } + } + } + }, + "/mcp/operations/{operationId}": { + "get": { + "operationId": "get-operation", + "summary": "Get operation receipt", + "description": "Read an authoring operation receipt owned by the current principal and workspace.", + "tags": [ + "Catalog" + ], + "parameters": [ + { + "name": "operationId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "X-Innflow-Workspace", + "in": "header", + "description": "Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Returns data with id, state, executionId, workflowId, lastError and response. Use this to inspect accepted operations and dispatch failures.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "default": { + "description": "Error response. See authentication and errors guide; proxy rate-limit responses may not have this envelope.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "code": { + "type": "string" + }, + "requestId": { + "type": "string" + }, + "details": {} + }, + "required": [ + "error" + ] + } + } + } + } + } + } + }, + "/openapi.json": { + "get": { + "operationId": "get-openapi", + "summary": "Get OpenAPI document", + "description": "Retrieve the application’s machine-readable OpenAPI 3.1 document without authentication.\n\nThe application-served document currently covers the core API subset. The complete reference snapshot used by these docs is available at /openapi.json on docs.innflow.ai.", + "tags": [ + "Discovery" + ], + "security": [], + "parameters": [], + "responses": { + "200": { + "description": "Returns the application OpenAPI document directly, without a data envelope.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + } + } + } + } + } +} diff --git a/scripts/api/catalog.mjs b/scripts/api/catalog.mjs new file mode 100644 index 0000000..0c1ba1e --- /dev/null +++ b/scripts/api/catalog.mjs @@ -0,0 +1,35 @@ +import { readFileSync } from 'node:fs'; +const schemas = JSON.parse(readFileSync(new URL('./request-schemas.json', import.meta.url))); +const string = { type: 'string' }; +const object = (properties, required = []) => ({ type: 'object', properties, ...(required.length ? { required } : {}) }); +const query = (name, description, schema = string, required = false) => ({ name, in: 'query', description, schema, required }); +const pages = [query('page', 'Page number, starting at 1.', { type: 'integer', minimum: 1, default: 1 }), query('pageSize', 'Results per page (1–100).', { type: 'integer', minimum: 1, maximum: 100, default: 20 })]; +const workflowResponse = 'Returns data with id, name, icon, iconColor, deploymentStatus, deployedAt, createdAt and updatedAt.'; +const op = (id, method, path, title, group, description, extra = {}) => ({ id, method, path, title, group, description, ...extra }); +export const catalog = [ + op('list-workspaces', 'GET', '/workspaces', 'List workspaces', 'Workspaces', 'List the personal workspace and organizations you belong to.', { response: 'Returns data as an array. Each entry has id, name, type and role; organization entries also include slug.', permission: 'workspaces:read' }), + op('list-workflows', 'GET', '/workflows', 'List workflows', 'Workflows', 'List standard workflows accessible in the selected workspace, newest updated first.', { query: [...pages, query('search', 'Case-insensitive workflow name filter.')], response: 'Returns data as an array of workflow summaries and pagination with page, pageSize, totalCount and totalPages.' }), + op('create-workflow', 'POST', '/workflows', 'Create workflow', 'Workflows', 'Create a draft workflow with an initial node. An omitted or empty name uses the default untitled name.', { body: object({ name: string }), example: {name:'Customer onboarding'}, status:201, idempotency:'optional', response:workflowResponse }), + op('import-workflow', 'POST', '/workflows/import', 'Import workflow', 'Workflows', 'Create a draft from 1–200 nodes and optional edges. Edge source and target are zero-based indexes into nodes. Node types must exist in the Innflow registry. description is accepted by the input schema but is not persisted by this endpoint.', { body:schemas.workflowImportSchema, bodyRequired:true, status:201, idempotency:'optional', example:{name:'API workflow',nodes:[{type:'MANUAL_TRIGGER',position:{x:0,y:0},data:{}}],edges:[]}, response:'Returns data with id, name, deploymentStatus, nodeCount, edgeCount, createdAt and updatedAt. Node IDs are generated on import. canvasLayoutVersion defaults to 0; preserve 1 when reimporting an already arranged graph.' }), + op('get-workflow','GET','/workflows/{workflowId}','Get workflow','Workflows','Read workflow metadata and its graph.',{query:[query('view','Use summary to omit nodes and connections.',{type:'string',enum:['summary']}),query('nodeIds','Comma-separated list of at most 50 node IDs. Filters nodes only; connections remain unfiltered.')],response:'Returns data with workflow metadata, graphRevision, executionVersion, canvasLayoutVersion, nodes and connections. Summary view returns nodeCount and connectionCount instead of graph arrays.'}), + op('update-workflow','PATCH','/workflows/{workflowId}','Update workflow','Workflows','Change workflow metadata. Supply at least one of name, icon or iconColor. name must be non-empty after trimming. Use the graph endpoint for node and connection edits.',{body:object({name:{type:'string',minLength:1},icon:{type:['string','null']},iconColor:{type:['string','null']}}),bodyRequired:true,example:{name:'Updated workflow'},response:workflowResponse}), + op('delete-workflow','DELETE','/workflows/{workflowId}','Delete workflow','Workflows','Delete a workflow and its execution history. This is destructive.',{response:'Returns data with id and deleted: true.'}), + op('duplicate-workflow','POST','/workflows/{workflowId}/duplicate','Duplicate workflow','Workflows','Copy the graph into a new draft, preserving canvas layout metadata and generating new node IDs. Trigger connection state is refreshed.',{body:object({name:string}),example:{name:'Workflow copy'},idempotency:'optional',status:201,response:workflowResponse}), + op('deploy-workflow','POST','/workflows/{workflowId}/deploy','Deploy workflow','Workflows','Set a draft workflow to deployed and resume eligible paused schedules. Already-deployed workflows return 422. Validate configuration before deploying.',{response:workflowResponse,notes:'With API-key authentication, this endpoint does not replay Idempotency-Key receipts. MCP OAuth contract calls have separate transaction semantics; see the authoring guide.'}), + op('undeploy-workflow','POST','/workflows/{workflowId}/undeploy','Undeploy workflow','Workflows','Return a deployed workflow to draft and pause active schedules. A workflow that is not currently deployed returns 422.',{response:workflowResponse,notes:'With API-key authentication, this endpoint does not replay Idempotency-Key receipts.'}), + op('execute-workflow','POST','/workflows/{workflowId}/execute','Execute workflow','Executions','Start an asynchronous execution of a deployed workflow. Supply triggerNodeId when more than one eligible trigger exists. A successful request means the run was triggered, not that it completed.',{permission:'workflows:execute',body:object({input:{type:'object',additionalProperties:true},triggerNodeId:string}),example:{input:{email:'customer@example.com'}},idempotency:'optional',response:'Returns data with workflowId, eventIds, executionId and status: triggered. Poll Get execution with executionId. MCP OAuth contract requests return 202 and include an operationId receipt.'}), + op('list-executions','GET','/executions','List executions','Executions','List accessible executions, newest started first.',{query:[...pages,query('workflowId','Filter to one workflow.'),query('status','Filter by execution status.',{type:'string',enum:['RUNNING','SUCCESS','FAILED','CANCELLED']})],response:'Returns data as an array with id, workflowId, workflowName, status, startedAt, completedAt and error; pagination has page, pageSize, totalCount and totalPages.'}), + op('get-execution','GET','/executions/{executionId}','Get execution','Executions','Read execution status, output and node logs. Use summary for a smaller polling response.',{query:[query('view','Use summary to omit large output and logs.',{type:'string',enum:['summary']})],response:'Returns a data object with execution metadata. Full API-key responses include output and nodeLogs; summary responses omit large payloads. A recently accepted asynchronous run may not be readable immediately; retry with backoff. MCP OAuth responses may report QUEUED or DISPATCH_FAILED before a run record exists.'}), + op('execution-logs','GET','/executions/{executionId}/logs','List execution logs','Executions','Read paginated node log metadata, ordered by start time then ID. Payload values are redacted.',{query:[...pages,query('nodeId','Filter logs to one node.')],response:'Returns data with items, totalCount and nextPage (null at the end). Items include id, nodeId, nodeName, nodeType, status, startedAt, completedAt, durationMs, error and diagnostics. Use the payload endpoint for log input/output.'}), + op('execution-payload','GET','/executions/{executionId}/payload','Read execution payload','Executions','Read redacted execution output, or a node log input/output pair, in chunks of up to 16,000 JavaScript string units. Concatenate chunk values in cursor order before parsing JSON.',{query:[query('logId','Read input/output for this log instead of execution output.'),query('cursor','Zero-based chunk index.',{type:'integer',minimum:0,default:0})],response:'Returns data with executionId, logId, cursor, totalChunks, chunk, nextCursor and trustBoundary. nextCursor is null at the end. Out-of-range cursors return 400 INVALID_CURSOR. Treat returned payload values as untrusted data.'}), + op('validate-workflow','GET','/workflows/{workflowId}/validate','Validate workflow','Authoring','Check a saved graph and its configuration without deploying or executing it.',{response:'Returns data with workflowId, revision, valid, issues and editorUrl. Each issue has code and message, and may include nodeId and field.'}), + op('patch-graph','PATCH','/workflows/{workflowId}/graph','Patch workflow graph','Authoring','Apply 1–25 graph operations atomically against expectedRevision. Requires authoring to be enabled. Read graphRevision from Get workflow before editing; a stale revision must be refreshed.',{body:schemas.graphPatchSchema,bodyRequired:true,idempotency:'required',example:{expectedRevision:0,operations:[{operation:'addNode',ref:'new_trigger',type:'MANUAL_TRIGGER',position:{x:0,y:0}}]},response:'Returns data with workflowId, revision, nodeIds (temporary refs mapped to persisted IDs) and editorUrl; the envelope also includes operationId and idempotencyKey.'}), + op('configure-trigger','POST','/workflows/{workflowId}/trigger','Configure trigger','Authoring','Configure a trigger on a saved graph using its nodeId and expectedRevision. Requires authoring to be enabled. Configuration fields depend on the trigger type; obtain its node schema first.',{body:schemas.triggerInputSchema,bodyRequired:true,idempotency:'required',example:{nodeId:'node_id',expectedRevision:0,config:{}},response:'Returns data with status (configured, needs_input, provider_handoff or pending), persisted, revision, nodePatch and optional missing/instructions. The envelope includes operationId and idempotencyKey. Follow handoff instructions if provider setup is needed.'}), + op('node-options','GET','/workflows/{workflowId}/node-options','Get node field options','Authoring','Resolve options for a field on a saved node. Some dynamic provider selectors require opening the editor.',{query:[query('nodeId','Saved node ID.',string,true),query('field','Field name from the node schema.',string,true),query('search','Case-insensitive label filter.'),query('cursor','Nonnegative option offset.',{type:'integer',minimum:0,default:0})],response:'Returns data with items (id and label), nextCursor and optional handoffUrl. Up to 100 options are returned. Follow handoffUrl when remote options require the editor.'}), + op('authoring-context','GET','/mcp/context','Get authoring context','Catalog','Inspect the authenticated principal and authoring availability.',{response:'Returns data with workspace, userId, role, permissions, authoringEnabled and contractVersion. Check authoringEnabled before graph or trigger mutations.'}), + op('list-node-types','GET','/mcp/node-types','Search node types','Catalog','Discover available node types and operations before creating graph nodes.',{query:[...pages,query('search','Search the node catalog.')],response:'Returns data with items, totalCount, nextPage and contractVersion. Each item describes type, name, description, category, authMode and operations.'}), + op('get-node-type','GET','/mcp/node-types/{nodeType}','Get node schema','Catalog','Get configuration fields, outputs and handles for a node type.',{query:[query('operation','Operation identifier returned by the node catalog.')],response:'Returns data with type, optional operation, fields, outputs, handles and contractVersion. Use these fields to build configuration rather than guessing provider parameters.'}), + op('list-connections','GET','/mcp/connections','List connections','Catalog','List active connected accounts for a provider returned by a node schema. This endpoint returns identifiers and display names, not credentials.',{query:[query('provider','Provider identifier from the node schema.',string,true),...pages],response:'Returns data with items (id, provider, name) and nextPage. An unknown provider returns 422 UNKNOWN_PROVIDER.'}), + op('get-operation','GET','/mcp/operations/{operationId}','Get operation receipt','Catalog','Read an authoring operation receipt owned by the current principal and workspace.',{response:'Returns data with id, state, executionId, workflowId, lastError and response. Use this to inspect accepted operations and dispatch failures.'}), + op('get-openapi','GET','/openapi.json','Get OpenAPI document','Discovery','Retrieve the application’s machine-readable OpenAPI 3.1 document without authentication.',{public:true,response:'Returns the application OpenAPI document directly, without a data envelope.',notes:'The application-served document currently covers the core API subset. The complete reference snapshot used by these docs is available at /openapi.json on docs.innflow.ai.'}), +]; diff --git a/scripts/api/request-schemas.json b/scripts/api/request-schemas.json new file mode 100644 index 0000000..e4d7cc9 --- /dev/null +++ b/scripts/api/request-schemas.json @@ -0,0 +1,374 @@ +{ + "workflowImportSchema": { + "type": "object", + "properties": { + "canvasLayoutVersion": { + "default": 0, + "type": "integer", + "minimum": 0, + "maximum": 1 + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 255 + }, + "description": { + "type": "string" + }, + "icon": { + "type": "string", + "maxLength": 100 + }, + "iconColor": { + "type": "string", + "maxLength": 20 + }, + "nodes": { + "minItems": 1, + "maxItems": 200, + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "minLength": 1 + }, + "name": { + "type": "string", + "maxLength": 255 + }, + "position": { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + }, + "required": [ + "x", + "y" + ] + }, + "data": { + "default": {}, + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "type", + "position" + ] + } + }, + "edges": { + "default": [], + "type": "array", + "items": { + "type": "object", + "properties": { + "source": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "target": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "fromOutput": { + "type": "string" + }, + "toInput": { + "type": "string" + }, + "sourceHandle": { + "type": "string" + }, + "targetHandle": { + "type": "string" + } + }, + "required": [ + "source", + "target" + ] + } + } + }, + "required": [ + "nodes" + ] + }, + "graphPatchSchema": { + "type": "object", + "properties": { + "expectedRevision": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "operations": { + "minItems": 1, + "maxItems": 25, + "type": "array", + "items": { + "oneOf": [ + { + "type": "object", + "properties": { + "operation": { + "type": "string", + "const": "addNode" + }, + "ref": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "pattern": "^[A-Za-z0-9_-]+$" + }, + "type": { + "type": "string", + "minLength": 1 + }, + "name": { + "type": "string", + "maxLength": 255 + }, + "position": { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + }, + "required": [ + "x", + "y" + ] + }, + "data": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "operation", + "ref", + "type" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "operation": { + "type": "string", + "const": "configureNode" + }, + "nodeId": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "pattern": "^[A-Za-z0-9_-]+$" + }, + "data": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "operation", + "nodeId", + "data" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "operation": { + "type": "string", + "const": "removeNode" + }, + "nodeId": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "pattern": "^[A-Za-z0-9_-]+$" + } + }, + "required": [ + "operation", + "nodeId" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "operation": { + "type": "string", + "const": "moveNode" + }, + "nodeId": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "pattern": "^[A-Za-z0-9_-]+$" + }, + "position": { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + }, + "required": [ + "x", + "y" + ] + } + }, + "required": [ + "operation", + "nodeId", + "position" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "operation": { + "type": "string", + "const": "connect" + }, + "source": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "pattern": "^[A-Za-z0-9_-]+$" + }, + "target": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "pattern": "^[A-Za-z0-9_-]+$" + }, + "sourceHandle": { + "default": "main", + "type": "string", + "maxLength": 200 + }, + "targetHandle": { + "default": "main", + "type": "string", + "maxLength": 200 + } + }, + "required": [ + "operation", + "source", + "target" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "operation": { + "type": "string", + "const": "disconnect" + }, + "source": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "pattern": "^[A-Za-z0-9_-]+$" + }, + "target": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "pattern": "^[A-Za-z0-9_-]+$" + }, + "sourceHandle": { + "default": "main", + "type": "string", + "maxLength": 200 + }, + "targetHandle": { + "default": "main", + "type": "string", + "maxLength": 200 + } + }, + "required": [ + "operation", + "source", + "target" + ], + "additionalProperties": false + } + ] + } + } + }, + "required": [ + "expectedRevision", + "operations" + ], + "additionalProperties": false + }, + "triggerInputSchema": { + "type": "object", + "properties": { + "nodeId": { + "type": "string", + "minLength": 1, + "maxLength": 200, + "pattern": "^[A-Za-z0-9_-]+$" + }, + "expectedRevision": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "config": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "nodeId", + "expectedRevision", + "config" + ], + "additionalProperties": false + } +} diff --git a/scripts/api/source-manifest.json b/scripts/api/source-manifest.json new file mode 100644 index 0000000..6b72813 --- /dev/null +++ b/scripts/api/source-manifest.json @@ -0,0 +1,34 @@ +{ + "reviewedAt": "2026-09-28", + "revision": "2b758ae966e7d2acef938de7ae8f5c0fa0aae663", + "files": { + "packages/api-contracts/src/index.ts": "a4c24de67f114c6b594dbbf4ef22e275778834b7f5169c83bc07ea08cb07ad30", + "packages/api-contracts/src/mcp.ts": "f83ec497860a2c54546948327dbc99a0c4e7309c7271d2e0aceee602d218985a", + "src/app/api/v1/_lib/api-handler.ts": "9caef49763624bbc7ce5b7d95b5b119857f5540ea914fe70f5f071ec058889c2", + "src/app/api/v1/executions/[executionId]/logs/route.ts": "79e48ce0f8de8647b22d59c99cf5dbc81e83debe8f0553dc047027a694ded1a6", + "src/app/api/v1/executions/[executionId]/payload/route.ts": "51f6f2235b1f5e140aa200f2c91602b820b2145596799af23362333ffcb8d883", + "src/app/api/v1/executions/[executionId]/route.ts": "a246da1d8ac1e9c86b64bba4ed7a8719323fa11d8d8eb8450cd23227ff268f2b", + "src/app/api/v1/executions/route.ts": "4cab24766386ce47a22a3d15b253e98012f9887e1478432fd56db9694fd5ba08", + "src/app/api/v1/mcp/connections/route.ts": "3c2268556e6bbc2e9e1e9147cb0001fd58bca35fa73d08f00240bbfbd0b1a207", + "src/app/api/v1/mcp/context/route.ts": "55e7972168875fe11b2f58b27d4f0c7e3e4ee43cb98b027d4248b077cdb74d20", + "src/app/api/v1/mcp/node-types/[nodeType]/route.ts": "164149db23ddf6f6a01054ee36c3f865d65c10bada33edab291601fff2c10a40", + "src/app/api/v1/mcp/node-types/route.ts": "05aa9bb09a03556777d200b0a74268599650894a68a8e7522fd57ae0f7fa7755", + "src/app/api/v1/mcp/operations/[operationId]/route.ts": "635e7e87a489ce41ccceb7d6edf43549bf39daaa90b6a9ecafde40df7968d878", + "src/app/api/v1/openapi.json/route.ts": "52df5c7baae0a11154657d2c84dccbedbc780e64b264f87216c5eb632ecb877f", + "src/app/api/v1/workflows/[workflowId]/deploy/route.ts": "a07afc621679842feb468dfb3c0e81b204c2aede2dc5c8b0a2430a6ddf552fa7", + "src/app/api/v1/workflows/[workflowId]/duplicate/route.ts": "ffa8ecbc0ed7ecabb7fc18dab0fc64b5490420c9571f36b604aa5799c2e5c1c6", + "src/app/api/v1/workflows/[workflowId]/execute/route.ts": "4fbb1ff29ced3b4ac190b525cb6415654e9c8d7248b37ee904035e72869ccaa7", + "src/app/api/v1/workflows/[workflowId]/graph/route.ts": "59a1ba1d695deb563cd20618f01eac4861a58f80000a5b036c45154549314597", + "src/app/api/v1/workflows/[workflowId]/node-options/route.ts": "12f11de8e5e27791aaf5f3b99e1442210267d28d1e30411754b67411a0b6e8cd", + "src/app/api/v1/workflows/[workflowId]/route.ts": "469913e3fc6b972e8649aa0949f7c13f0483c0ef8b1e7018de3f9c1de8099453", + "src/app/api/v1/workflows/[workflowId]/trigger/route.ts": "16c825bec5de4af411ea4f01773fc6a3568adaa88cc0be0fe61b476fac518e39", + "src/app/api/v1/workflows/[workflowId]/undeploy/route.ts": "8f7a6d57c94874cbea88e16134a6dfc6bfa38362e4153bc4cf0b6078f1c76d7b", + "src/app/api/v1/workflows/[workflowId]/validate/route.ts": "b8f95fa67f67b19b5e7e79cd3bcaf8bc46877d81e6478704defa630ad3ff17b8", + "src/app/api/v1/workflows/import/route.ts": "fda7e617d3a75deba409eba98991d8fe5828e800d7b7c0313cf533f3c0dee171", + "src/app/api/v1/workflows/route.ts": "843ac52d9c21ff8f28683c55a11a80712565bb189db412dda3cc71b598d30903", + "src/app/api/v1/workspaces/route.ts": "f9f1549b84a6378956986584e05aa8706c64f8bb104148e97bc261d733213e6d", + "src/features/mcp/server/errors.ts": "6492e7dd1f491e92f83ed73ad6357923400e90d9f0c36d8e1b3b9734303da0ae", + "src/features/mcp/server/operations.ts": "c0005e2afce7a8b5c5f7c478b3f0f7e2ea53bb7cf0fdbd090aa42a747f6c9638", + "src/lib/api-key-auth.ts": "0ff8bd89b4631e188347136d38ba563ba86bf32eb3d73e425c429c218ec65610" + } +} diff --git a/scripts/sync-api-reference.mjs b/scripts/sync-api-reference.mjs new file mode 100644 index 0000000..88fd0c6 --- /dev/null +++ b/scripts/sync-api-reference.mjs @@ -0,0 +1,61 @@ +import { readFileSync, writeFileSync, mkdirSync, readdirSync } from 'node:fs'; +import { resolve, relative } from 'node:path'; +import { createHash } from 'node:crypto'; +import { catalog } from './api/catalog.mjs'; +const check = process.argv.includes('--check'); +const sourceCheck = process.argv.includes('--source-check'); +const sourceRoot = resolve(process.env.INNFLOW_SOURCE ?? '../innflow'); +const output = (file, value) => { + if (check || sourceCheck) { if (readFileSync(file, 'utf8') !== value) throw new Error(`Stale generated API reference: ${file}`); } + else writeFileSync(file, value); +}; +const json = value => JSON.stringify(value, null, 2) + '\n'; +const code = (language, value) => '\n```' + language + '\n' + value + '\n```\n'; +const permission = entry => entry.permission ?? `${entry.group === 'Executions' ? 'executions' : 'workflows'}:${entry.method === 'GET' ? 'read' : 'write'}`; +const workspace = { name:'X-Innflow-Workspace', in:'header', description:'Organization ID, or personal. Set explicitly; omission uses legacy user-owned resource scope.', schema:{type:'string'} }; +const idempotency = required => ({name:'Idempotency-Key',in:'header',required,description:required ? 'Required operation key: 1–200 letters, digits, dots, colons, underscores or hyphens.' : 'Optional replay key, at most 200 characters. Same request and key replay for 24 hours.',schema:{type:'string',maxLength:200,...(required?{minLength:1,pattern:'^[A-Za-z0-9_.:-]+$'}:{})}}); +const document = {openapi:'3.1.0',info:{title:'Innflow REST API',version:'2026-09-28',description:'Customer REST API reference. Authoring operations depend on authoring availability. Internal portal event ingestion is not a customer API.'},servers:[{url:'https://app.innflow.ai/api/v1'}],security:[{bearerAuth:[]}],components:{securitySchemes:{bearerAuth:{type:'http',scheme:'bearer',description:'Innflow API key. Keep credentials on the server.'}}},paths:{}}; +mkdirSync('content/docs/api-reference/endpoints',{recursive:true}); +const index = []; +for (const entry of catalog) { + const parameters = [...entry.path.matchAll(/\{(\w+)\}/g)].map(match=>({name:match[1],in:'path',required:true,schema:{type:'string'}})); + if (!entry.public) parameters.push(workspace); + if(entry.idempotency) parameters.push(idempotency(entry.idempotency === 'required')); + parameters.push(...(entry.query??[])); + const status = String(entry.status??200); + const operation = {operationId:entry.id,summary:entry.title,description:[entry.description,entry.notes].filter(Boolean).join('\n\n'),tags:[entry.group],...(entry.public?{security:[]}:{}),parameters,responses:{[status]:{description:entry.response,content:{'application/json':{schema:{type:'object',additionalProperties:true}}}}}}; + if(entry.body) operation.requestBody = {required:!!entry.bodyRequired,content:{'application/json':{schema:entry.body,...(entry.example?{example:entry.example}:{})}}}; + if(!entry.public) operation.responses.default={description:'Error response. See authentication and errors guide; proxy rate-limit responses may not have this envelope.',content:{'application/json':{schema:{type:'object',properties:{error:{type:'string'},code:{type:'string'},requestId:{type:'string'},details:{}},required:['error']}}}}; + (document.paths[entry.path]??={})[entry.method.toLowerCase()]=operation; + const url = 'https://app.innflow.ai/api/v1'+entry.path.replace(/\{(\w+)\}/g,(_,key)=>key === 'nodeType' ? 'MANUAL_TRIGGER' : key.replace(/[A-Z]/g,s=>'_'+s.toLowerCase())); + const requiredQuery = (entry.query??[]).filter(p=>p.required).map(p=>`${p.name}=${p.name === 'provider'?'provider_id':p.name === 'field'?'field_name':'node_id'}`).join('&'); + const curl = [`curl --request ${entry.method} '${url}${requiredQuery?'?'+requiredQuery:''}'`,...(!entry.public?[' --header "Authorization: Bearer $INNFLOW_API_KEY"']:[]),...(entry.idempotency?[' --header "Idempotency-Key: unique-request-001"']:[]),...(entry.body?[' --header "Content-Type: application/json"',` --data '${JSON.stringify(entry.example??{},null,2)}'`]:[])].join(' \\\n'); + let page = `---\ntitle: '${entry.title}'\ndescription: '${entry.method} ${entry.path}'\n---\n\n${entry.description}\n\n`+code('http',`${entry.method} /api/v1${entry.path}`); + page += entry.public ? '\nNo authentication required.\n' : `\n**Permission:** \`${permission(entry)}\`. Write endpoints also require a workspace role that permits changes. See [authentication](/api-reference/authentication) and [errors](/api-reference/errors).\n`; + if(entry.notes) page += '\n'+entry.notes+'\n'; + page += '\n## Request\n'+code('bash',curl)+'\nExamples use placeholder IDs. Set `INNFLOW_API_KEY` in your shell and replace IDs with your own before sending a request.\n'; + if(parameters.length) page += '\n## Parameters\n\n| Name | In | Required | Details |\n| --- | --- | --- | --- |\n'+parameters.map(p=>`| \`${p.name}\` | ${p.in} | ${p.required?'Yes':'No'} | ${p.description??'Resource identifier.'} |`).join('\n')+'\n'; + if(entry.body) page+='\n## JSON body\n\n'+(entry.bodyRequired?'Required JSON body.':'Optional JSON body.')+code('json',JSON.stringify(entry.body,null,2)); + page+='\n## Response\n\n**HTTP '+status+'** — '+entry.response+'\n\nSee [OpenAPI download](/openapi.json) for the machine-readable request contract and [errors](/api-reference/errors) for errors and retry behavior.\n'; + output(`content/docs/api-reference/endpoints/${entry.id}.mdx`,page); + index.push(`| \`${entry.method}\` | \`${entry.path}\` | [${entry.title}](/api-reference/endpoints/${entry.id}) |`); +} +output('public/openapi.json',json(document)); +const groups = [...new Set(catalog.map(entry=>entry.group))]; +output('content/docs/api-reference/endpoints/meta.json',json({title:'Endpoints',pages:['index', ...groups.flatMap(group=>[`---${group}---`,...catalog.filter(entry=>entry.group===group).map(entry=>entry.id)])]})); +output('content/docs/api-reference/endpoints/index.mdx',`---\ntitle: 'REST endpoints'\ndescription: '${catalog.length} REST operations for workflows, executions, workspaces and authoring'\n---\n\nBase URL: \`https://app.innflow.ai/api/v1\`.\n\n[Authentication](/api-reference/authentication) · [Authoring guide](/api-reference/authoring) · [Download OpenAPI 3.1](/openapi.json)\n\n${groups.map(group=>'## '+group+'\n\n| Method | Path | Reference |\n| --- | --- | --- |\n'+catalog.map((entry,i)=>entry.group===group?index[i]:null).filter(Boolean).join('\n')).join('\n\n')}\n\n## Scope\n\nThis reference covers every customer-facing route under \`/api/v1\`, including authoring and discovery. \`/api/v1/portal-events\` is service-to-service ingestion and does not accept customer API keys. Provider callbacks, internal service APIs, browser-session routes and tRPC are separate interfaces, not general customer REST endpoints. See [triggers](/triggers) for workflow-specific webhook setup and [MCP](/mcp) for the MCP interface.\n`); +if(sourceCheck){ + const walk = dir => readdirSync(dir,{withFileTypes:true}).flatMap(entry=>entry.isDirectory()?walk(resolve(dir,entry.name)):[resolve(dir,entry.name)]); + const root = resolve(sourceRoot,'src/app/api/v1'); + const actual=[]; + for(const file of walk(root).filter(file=>file.endsWith('/route.ts'))){ + const path='/'+relative(root,file).replace(/\/route.ts$/,'').replace(/\[([^\]]+)\]/g,'{$1}'); + if(path==='/portal-events')continue; + for(const match of readFileSync(file,'utf8').matchAll(/export (?:const|async function|function) (GET|POST|PATCH|DELETE|PUT|OPTIONS|HEAD)\b/g)) actual.push(match[1]+' '+path); + } + const documented=catalog.map(entry=>entry.method+' '+entry.path); + if(JSON.stringify(actual.sort())!==JSON.stringify(documented.sort()))throw new Error('Route coverage mismatch: '+JSON.stringify({actual,documented})); + const baseline=JSON.parse(readFileSync('scripts/api/source-manifest.json','utf8')); + for(const [file,hash] of Object.entries(baseline.files))if(createHash('sha256').update(readFileSync(resolve(sourceRoot,file))).digest('hex')!==hash)throw new Error('Review changed API source: '+file); +} +console.log(`${check||sourceCheck?'Checked':'Generated'} ${catalog.length} REST operations, endpoint pages and OpenAPI 3.1.`); diff --git a/scripts/verify-build.mjs b/scripts/verify-build.mjs index dbe739c..5e576e7 100644 --- a/scripts/verify-build.mjs +++ b/scripts/verify-build.mjs @@ -1,6 +1,8 @@ import { cpSync, existsSync, readFileSync, readdirSync } from 'node:fs'; import { join, relative, dirname, basename } from 'node:path'; -import { spawn } from 'node:child_process'; +import { spawn, execFileSync } from 'node:child_process'; + +execFileSync(process.execPath, ['scripts/sync-api-reference.mjs', '--check'], { stdio: 'inherit' }); import { createServer } from 'node:net'; import { setTimeout as delay } from 'node:timers/promises';