-
Notifications
You must be signed in to change notification settings - Fork 52.3k
feat(API): Add POST /workflows/{id}/execute endpoint #23435
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
feat(API): Add POST /workflows/{id}/execute endpoint #23435
Conversation
Adds ability to trigger workflow execution via the Public API with API key authentication. - Returns executionId immediately (async execution) - Accepts optional inputData or pinData in request body - Requires workflow:execute scope (Owner, Admin, Member roles)
Tests cover: - API key authentication (missing/invalid) - Non-existing workflow (404) - Successful execution returning executionId - Execution with inputData - Execution with pinData - Error when both inputData and pinData provided - Owner can execute any workflow - Member cannot execute workflows without access
|
Hey @logan-mcduffie, Thank you for your contribution. We appreciate the time and effort youβve taken to submit this pull request. Before we can proceed, please ensure the following: Regarding new nodes: If your node integrates with an AI service that you own or represent, please email [email protected] and we will be happy to discuss the best approach. About review timelines: Thank you again for contributing to n8n. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2 issues found across 8 files
Prompt for AI agents (all 2 issues)
Check if these issues are valid β if so, understand the root cause of each and fix them.
<file name="packages/cli/src/public-api/v1/handlers/workflows/workflows.handler.ts">
<violation number="1" location="packages/cli/src/public-api/v1/handlers/workflows/workflows.handler.ts:413">
P2: Rule violated: **Prefer Typeguards over Type casting**
Use proper validation instead of `as` type casting for request body data. The codebase already uses zod schemas for request validation (see `transferWorkflow` handler). Consider defining a zod schema to validate `inputData` and `pinData` types from the request body, rather than using type assertions on untrusted input.</violation>
</file>
<file name="packages/cli/src/workflows/workflow-execution.service.ts">
<violation number="1" location="packages/cli/src/workflows/workflow-execution.service.ts:280">
P1: Rule violated: **Tests**
The new `executeViaPublicApi` method and its helper `findStartNode` lack unit tests despite containing meaningful business logic (start node preference logic, inputDataβpinData conversion, error handling). The existing test file tests similar methods extensively. Consider adding tests for:
- Finding manual trigger when present
- Falling back to other triggers
- Error when no trigger exists
- inputData to pinData conversion
- Direct pinData passthrough</violation>
</file>
Since this is your first cubic review, here's how it works:
- cubic automatically reviews your code and comments on bugs and improvements
- Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
- Ask questions if you need clarification on any suggestion
Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR
| // Execute workflow | ||
| const executionService = Container.get(WorkflowExecutionService); | ||
| const result = await executionService.executeViaPublicApi(workflow, req.user, { | ||
| inputData: inputData as IDataObject | undefined, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Rule violated: Prefer Typeguards over Type casting
Use proper validation instead of as type casting for request body data. The codebase already uses zod schemas for request validation (see transferWorkflow handler). Consider defining a zod schema to validate inputData and pinData types from the request body, rather than using type assertions on untrusted input.
Prompt for AI agents
Check if this issue is valid β if so, understand the root cause and fix it. At packages/cli/src/public-api/v1/handlers/workflows/workflows.handler.ts, line 413:
<comment>Use proper validation instead of `as` type casting for request body data. The codebase already uses zod schemas for request validation (see `transferWorkflow` handler). Consider defining a zod schema to validate `inputData` and `pinData` types from the request body, rather than using type assertions on untrusted input.</comment>
<file context>
@@ -379,6 +381,51 @@ export = {
+ // Execute workflow
+ const executionService = Container.get(WorkflowExecutionService);
+ const result = await executionService.executeViaPublicApi(workflow, req.user, {
+ inputData: inputData as IDataObject | undefined,
+ pinData: pinData as IPinData | undefined,
+ });
</file context>
β
Addressed in 9fa0dfb
| * Execute a workflow via the public API. | ||
| * Returns the execution ID immediately (asynchronous execution). | ||
| */ | ||
| async executeViaPublicApi( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: Rule violated: Tests
The new executeViaPublicApi method and its helper findStartNode lack unit tests despite containing meaningful business logic (start node preference logic, inputDataβpinData conversion, error handling). The existing test file tests similar methods extensively. Consider adding tests for:
- Finding manual trigger when present
- Falling back to other triggers
- Error when no trigger exists
- inputData to pinData conversion
- Direct pinData passthrough
Prompt for AI agents
Check if this issue is valid β if so, understand the root cause and fix it. At packages/cli/src/workflows/workflow-execution.service.ts, line 280:
<comment>The new `executeViaPublicApi` method and its helper `findStartNode` lack unit tests despite containing meaningful business logic (start node preference logic, inputDataβpinData conversion, error handling). The existing test file tests similar methods extensively. Consider adding tests for:
- Finding manual trigger when present
- Falling back to other triggers
- Error when no trigger exists
- inputData to pinData conversion
- Direct pinData passthrough</comment>
<file context>
@@ -272,6 +273,67 @@ export class WorkflowExecutionService {
+ * Execute a workflow via the public API.
+ * Returns the execution ID immediately (asynchronous execution).
+ */
+ async executeViaPublicApi(
+ workflow: WorkflowEntity,
+ user: User,
</file context>
- Add Zod schema validation for request body instead of type casting - Add unit tests for executeViaPublicApi() method covering: - Manual trigger preference - Fallback to other triggers - Disabled trigger handling - Error when no trigger exists - inputData to pinData conversion - Direct pinData passthrough - Execution data properties
|
@cubic-dev-ai review this PR |
@logan-mcduffie I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
3 issues found across 9 files
Prompt for AI agents (all 3 issues)
Check if these issues are valid β if so, understand the root cause of each and fix them.
<file name="packages/cli/src/public-api/v1/handlers/workflows/spec/paths/workflows.id.execute.yml">
<violation number="1" location="packages/cli/src/public-api/v1/handlers/workflows/spec/paths/workflows.id.execute.yml:15">
P2: Response schema should mark `executionId` as required for proper OpenAPI documentation and client code generation. This matches the codebase pattern (e.g., `error.yml`, `user.yml`).</violation>
</file>
<file name="packages/cli/src/public-api/v1/handlers/workflows/workflows.handler.ts">
<violation number="1" location="packages/cli/src/public-api/v1/handlers/workflows/workflows.handler.ts:424">
P2: Rule violated: **Prefer Typeguards over Type casting**
Type narrowing with `as` keyword. The Zod schema produces `Record<string, unknown> | undefined`, which is then cast to `IDataObject | undefined`. Consider defining a type-safe Zod schema that produces the correct type, or use a type guard. Alternatively, if `IDataObject` is compatible with `Record<string, unknown>`, update `executeViaPublicApi` to accept the Zod-inferred type directly.</violation>
<violation number="2" location="packages/cli/src/public-api/v1/handlers/workflows/workflows.handler.ts:425">
P2: Rule violated: **Prefer Typeguards over Type casting**
Type narrowing with `as` keyword. The Zod schema produces a complex record type, which is then cast to `IPinData | undefined`. Consider defining a type-safe Zod schema that produces the correct type, or use a type guard. Alternatively, if `IPinData` is compatible with the Zod-inferred type, update `executeViaPublicApi` to accept it directly.</violation>
</file>
Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR
| required: false | ||
| content: | ||
| application/json: | ||
| schema: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Response schema should mark executionId as required for proper OpenAPI documentation and client code generation. This matches the codebase pattern (e.g., error.yml, user.yml).
Prompt for AI agents
Check if this issue is valid β if so, understand the root cause and fix it. At packages/cli/src/public-api/v1/handlers/workflows/spec/paths/workflows.id.execute.yml, line 15:
<comment>Response schema should mark `executionId` as required for proper OpenAPI documentation and client code generation. This matches the codebase pattern (e.g., `error.yml`, `user.yml`).</comment>
<file context>
@@ -0,0 +1,40 @@
+ required: false
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
</file context>
β
Addressed in 7fc98cc
| // Execute workflow | ||
| const executionService = Container.get(WorkflowExecutionService); | ||
| const result = await executionService.executeViaPublicApi(workflow, req.user, { | ||
| inputData: inputData as IDataObject | undefined, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Rule violated: Prefer Typeguards over Type casting
Type narrowing with as keyword. The Zod schema produces Record<string, unknown> | undefined, which is then cast to IDataObject | undefined. Consider defining a type-safe Zod schema that produces the correct type, or use a type guard. Alternatively, if IDataObject is compatible with Record<string, unknown>, update executeViaPublicApi to accept the Zod-inferred type directly.
Prompt for AI agents
Check if this issue is valid β if so, understand the root cause and fix it. At packages/cli/src/public-api/v1/handlers/workflows/workflows.handler.ts, line 424:
<comment>Type narrowing with `as` keyword. The Zod schema produces `Record<string, unknown> | undefined`, which is then cast to `IDataObject | undefined`. Consider defining a type-safe Zod schema that produces the correct type, or use a type guard. Alternatively, if `IDataObject` is compatible with `Record<string, unknown>`, update `executeViaPublicApi` to accept the Zod-inferred type directly.</comment>
<file context>
@@ -379,6 +381,62 @@ export = {
+ // Execute workflow
+ const executionService = Container.get(WorkflowExecutionService);
+ const result = await executionService.executeViaPublicApi(workflow, req.user, {
+ inputData: inputData as IDataObject | undefined,
+ pinData: pinData as IPinData | undefined,
+ });
</file context>
β
Addressed in 7fc98cc
| const executionService = Container.get(WorkflowExecutionService); | ||
| const result = await executionService.executeViaPublicApi(workflow, req.user, { | ||
| inputData: inputData as IDataObject | undefined, | ||
| pinData: pinData as IPinData | undefined, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Rule violated: Prefer Typeguards over Type casting
Type narrowing with as keyword. The Zod schema produces a complex record type, which is then cast to IPinData | undefined. Consider defining a type-safe Zod schema that produces the correct type, or use a type guard. Alternatively, if IPinData is compatible with the Zod-inferred type, update executeViaPublicApi to accept it directly.
Prompt for AI agents
Check if this issue is valid β if so, understand the root cause and fix it. At packages/cli/src/public-api/v1/handlers/workflows/workflows.handler.ts, line 425:
<comment>Type narrowing with `as` keyword. The Zod schema produces a complex record type, which is then cast to `IPinData | undefined`. Consider defining a type-safe Zod schema that produces the correct type, or use a type guard. Alternatively, if `IPinData` is compatible with the Zod-inferred type, update `executeViaPublicApi` to accept it directly.</comment>
<file context>
@@ -379,6 +381,62 @@ export = {
+ const executionService = Container.get(WorkflowExecutionService);
+ const result = await executionService.executeViaPublicApi(workflow, req.user, {
+ inputData: inputData as IDataObject | undefined,
+ pinData: pinData as IPinData | undefined,
+ });
+
</file context>
β
Addressed in 7fc98cc
- Add 'required' field to OpenAPI response schema for executionId - Update executeViaPublicApi() to accept Zod-inferred types directly - Remove type casts from handler by accepting Record<string, unknown> types
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2 issues found across 3 files (changes from recent commits).
Prompt for AI agents (all 2 issues)
Check if these issues are valid β if so, understand the root cause of each and fix them.
<file name="packages/cli/src/workflows/workflow-execution.service.ts">
<violation number="1" location="packages/cli/src/workflows/workflow-execution.service.ts:303">
P2: Rule violated: **Prefer Typeguards over Type casting**
Using `as IPinData` for type narrowing violates the type casting rule. Consider using a type guard function to validate the `pinData` structure, or keep the `IPinData` type in the function signature if the API layer already validates this structure.</violation>
<violation number="2" location="packages/cli/src/workflows/workflow-execution.service.ts:307">
P2: Rule violated: **Prefer Typeguards over Type casting**
Using `as IDataObject` for type narrowing violates the type casting rule. Consider using a type guard function to validate `inputData`, or keep the `IDataObject` type in the function signature if the API layer already ensures the correct type.</violation>
</file>
Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR
| } else if (inputData) { | ||
| // Convert simple inputData to pinData format for the start node | ||
| effectivePinData = { | ||
| [startNode.name]: [{ json: inputData as IDataObject }], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Rule violated: Prefer Typeguards over Type casting
Using as IDataObject for type narrowing violates the type casting rule. Consider using a type guard function to validate inputData, or keep the IDataObject type in the function signature if the API layer already ensures the correct type.
Prompt for AI agents
Check if this issue is valid β if so, understand the root cause and fix it. At packages/cli/src/workflows/workflow-execution.service.ts, line 307:
<comment>Using `as IDataObject` for type narrowing violates the type casting rule. Consider using a type guard function to validate `inputData`, or keep the `IDataObject` type in the function signature if the API layer already ensures the correct type.</comment>
<file context>
@@ -296,11 +299,12 @@ export class WorkflowExecutionService {
// Convert simple inputData to pinData format for the start node
effectivePinData = {
- [startNode.name]: [{ json: inputData }],
+ [startNode.name]: [{ json: inputData as IDataObject }],
};
}
</file context>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The pinData parameter is validated by a Zod schema at the API layer (z.record(z.array(z.object({ json: z.record(z.unknown()) })))), which structurally matches IPinData ({ [nodeName: string]: INodeExecutionData[] }). The cast is safe because the validation has already occurred before this code executes. Creating a runtime type guard here would be redundant validation.
| if (pinData) { | ||
| // Use provided pinData directly (advanced mode) | ||
| // The pinData structure from the API is compatible with IPinData | ||
| effectivePinData = pinData as IPinData; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Rule violated: Prefer Typeguards over Type casting
Using as IPinData for type narrowing violates the type casting rule. Consider using a type guard function to validate the pinData structure, or keep the IPinData type in the function signature if the API layer already validates this structure.
Prompt for AI agents
Check if this issue is valid β if so, understand the root cause and fix it. At packages/cli/src/workflows/workflow-execution.service.ts, line 303:
<comment>Using `as IPinData` for type narrowing violates the type casting rule. Consider using a type guard function to validate the `pinData` structure, or keep the `IPinData` type in the function signature if the API layer already validates this structure.</comment>
<file context>
@@ -296,11 +299,12 @@ export class WorkflowExecutionService {
// Use provided pinData directly (advanced mode)
- effectivePinData = pinData;
+ // The pinData structure from the API is compatible with IPinData
+ effectivePinData = pinData as IPinData;
} else if (inputData) {
// Convert simple inputData to pinData format for the start node
</file context>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The inputData parameter is validated by a Zod schema at the API layer (z.record(z.unknown())), which is structurally compatible with IDataObject ({ [key: string]: GenericValue | IDataObject | ... }). The cast is safe because the API layer ensures only valid JSON objects reach this code. The cast occurs inside the pinData construction where we wrap it as { json: inputData }, matching n8n's expected format.
Summary
Adds a new Public API endpoint to trigger workflow execution programmatically:
POST /api/v1/workflows/{id}/execute{ executionId: string }immediately (async execution)inputData(simple JSON) orpinData(advanced n8n format) in request bodyworkflow:executescope (available to Owner, Admin, Member roles)Use cases:
Example:
Related Linear tickets, Github issues, and Community forum posts
This addresses a common community request for programmatic workflow execution via the Public API.
Review / Merge checklist