Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@logan-mcduffie
Copy link

@logan-mcduffie logan-mcduffie commented Dec 19, 2025

Summary

Adds a new Public API endpoint to trigger workflow execution programmatically:

POST /api/v1/workflows/{id}/execute

  • Returns { executionId: string } immediately (async execution)
  • Accepts optional inputData (simple JSON) or pinData (advanced n8n format) in request body
  • Requires workflow:execute scope (available to Owner, Admin, Member roles)

Use cases:

  • Triggering workflows from external systems without setting up webhooks
  • Programmatic workflow orchestration
  • CI/CD pipeline integration
  • Custom automation scripts

Example:

curl -X POST "https://your-n8n/api/v1/workflows/{id}/execute" \
  -H "X-N8N-API-KEY: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{"inputData": {"key": "value"}}'
# Returns: {"executionId": "123"}

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

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
@CLAassistant
Copy link

CLAassistant commented Dec 19, 2025

CLA assistant check
All committers have signed the CLA.

@logan-mcduffie logan-mcduffie marked this pull request as ready for review December 19, 2025 01:18
@n8n-assistant n8n-assistant bot added community Authored by a community member core Enhancement outside /nodes-base and /editor-ui in linear Issue or PR has been created in Linear for internal review labels Dec 19, 2025
@n8n-assistant
Copy link

n8n-assistant bot commented Dec 19, 2025

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:
β€’ Tests are included for any new functionality, logic changes or bug fixes.
β€’ The PR aligns with our contribution guidelines.

Regarding new nodes:
We no longer accept new nodes directly into the core codebase. Instead, we encourage contributors to follow our Community Node Submission Guide to publish nodes independently.

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:
This PR has been added to our internal tracker as "GHC-5978". While we plan to review it, we are currently unable to provide an exact timeframe. Our goal is to begin reviews within a month, but this may change depending on team priorities. We will reach out when the review begins.

Thank you again for contributing to n8n.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a 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,
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 19, 2025

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(
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 19, 2025

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>
Fix with Cubic

- 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
@logan-mcduffie
Copy link
Author

@cubic-dev-ai review this PR

@cubic-dev-ai
Copy link
Contributor

cubic-dev-ai bot commented Dec 19, 2025

@cubic-dev-ai review this PR

@logan-mcduffie I have started the AI code review. It will take a few minutes to complete.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a 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&lt;string, unknown&gt; | 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&lt;string, unknown&gt;`, 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:
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 19, 2025

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,
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 19, 2025

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&lt;string, unknown&gt; | 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&lt;string, unknown&gt;`, 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,
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 19, 2025

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
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a 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 }],
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 19, 2025

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>
Fix with Cubic

Copy link
Author

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;
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 19, 2025

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>
Fix with Cubic

Copy link
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community Authored by a community member core Enhancement outside /nodes-base and /editor-ui in linear Issue or PR has been created in Linear for internal review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants