diff --git a/src/modules/http/Elsa.Http.OpenApi/Contracts/IElsaVersionProvider.cs b/src/modules/http/Elsa.Http.OpenApi/Contracts/IElsaVersionProvider.cs
new file mode 100644
index 00000000..b8897b53
--- /dev/null
+++ b/src/modules/http/Elsa.Http.OpenApi/Contracts/IElsaVersionProvider.cs
@@ -0,0 +1,15 @@
+using System.Reflection;
+
+namespace Elsa.Http.OpenApi.Contracts;
+
+///
+/// Service for retrieving Elsa package version information.
+///
+public interface IElsaVersionProvider
+{
+ ///
+ /// Gets the Elsa package version.
+ ///
+ /// The package version string.
+ string GetVersion();
+}
diff --git a/src/modules/http/Elsa.Http.OpenApi/Contracts/IOpenApiGenerator.cs b/src/modules/http/Elsa.Http.OpenApi/Contracts/IOpenApiGenerator.cs
new file mode 100644
index 00000000..83abab8b
--- /dev/null
+++ b/src/modules/http/Elsa.Http.OpenApi/Contracts/IOpenApiGenerator.cs
@@ -0,0 +1,16 @@
+using Elsa.Http.OpenApi.Models;
+
+namespace Elsa.Http.OpenApi.Contracts;
+
+///
+/// Contract for generating OpenAPI JSON documentation.
+///
+public interface IOpenApiGenerator
+{
+ ///
+ /// Generates OpenAPI JSON documentation from a list of endpoint definitions.
+ ///
+ /// The list of endpoint definitions.
+ /// OpenAPI JSON string.
+ string GenerateOpenApiJson(List endpoints);
+}
diff --git a/src/modules/http/Elsa.Http.OpenApi/Contracts/IWorkflowEndpointExtractor.cs b/src/modules/http/Elsa.Http.OpenApi/Contracts/IWorkflowEndpointExtractor.cs
new file mode 100644
index 00000000..6fd37f15
--- /dev/null
+++ b/src/modules/http/Elsa.Http.OpenApi/Contracts/IWorkflowEndpointExtractor.cs
@@ -0,0 +1,16 @@
+using Elsa.Http.OpenApi.Models;
+
+namespace Elsa.Http.OpenApi.Contracts;
+
+///
+/// Contract for extracting workflow HTTP endpoints for OpenAPI documentation.
+///
+public interface IWorkflowEndpointExtractor
+{
+ ///
+ /// Extracts all HTTP endpoints from workflows.
+ ///
+ /// The cancellation token.
+ /// A list of endpoint definitions.
+ Task> ExtractEndpointsAsync(CancellationToken cancellationToken = default);
+}
diff --git a/src/modules/http/Elsa.Http.OpenApi/Elsa.Http.OpenApi.csproj b/src/modules/http/Elsa.Http.OpenApi/Elsa.Http.OpenApi.csproj
new file mode 100644
index 00000000..ee4356fd
--- /dev/null
+++ b/src/modules/http/Elsa.Http.OpenApi/Elsa.Http.OpenApi.csproj
@@ -0,0 +1,37 @@
+
+
+
+
+ Provides OpenAPI functionality for HTTP triggers in Elsa workflows.
+
+ elsa extension module, http, openapi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/http/Elsa.Http.OpenApi/Extensions/EndpointRouteBuilderExtensions.cs b/src/modules/http/Elsa.Http.OpenApi/Extensions/EndpointRouteBuilderExtensions.cs
new file mode 100644
index 00000000..d30e361f
--- /dev/null
+++ b/src/modules/http/Elsa.Http.OpenApi/Extensions/EndpointRouteBuilderExtensions.cs
@@ -0,0 +1,50 @@
+using Elsa.Http.OpenApi.Contracts;
+using Elsa.Http.OpenApi.Services;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Routing;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Elsa.Http.OpenApi.Extensions;
+
+///
+/// Extension methods for mapping OpenAPI endpoints.
+///
+public static class EndpointRouteBuilderExtensions
+{
+ ///
+ /// Maps OpenAPI endpoints for workflow documentation.
+ ///
+ /// The endpoint route builder.
+ /// The endpoint route builder for chaining.
+ public static IEndpointRouteBuilder MapWorkflowOpenApi(this IEndpointRouteBuilder app)
+ {
+ // OpenAPI JSON endpoint
+ app.MapGet("/openapi.json", async ([FromServices] IWorkflowEndpointExtractor extractor, [FromServices] IOpenApiGenerator generator) =>
+ {
+ var endpoints = await extractor.ExtractEndpointsAsync();
+ var openApiJson = generator.GenerateOpenApiJson(endpoints);
+ return Results.Content(openApiJson, "application/json");
+ });
+
+ // ReDoc UI endpoint
+ app.MapGet("/documentation", () =>
+ {
+ var html = @"
+
+
+
+ API Documentation
+
+
+
+
+
+ ";
+ return Results.Content(html, "text/html");
+ });
+
+ return app;
+ }
+}
diff --git a/src/modules/http/Elsa.Http.OpenApi/Extensions/ModuleExtensions.cs b/src/modules/http/Elsa.Http.OpenApi/Extensions/ModuleExtensions.cs
new file mode 100644
index 00000000..03b69616
--- /dev/null
+++ b/src/modules/http/Elsa.Http.OpenApi/Extensions/ModuleExtensions.cs
@@ -0,0 +1,22 @@
+using Elsa.Extensions;
+using Elsa.Features.Services;
+using Elsa.Http.Features;
+using Elsa.Http.OpenApi.Features;
+
+// ReSharper disable once CheckNamespace
+namespace Elsa.Extensions;
+
+///
+/// Provides extensions to install the HTTP OpenAPI feature.
+///
+public static class ModuleExtensions
+{
+ ///
+ /// Install the feature as part of the HTTP feature configuration.
+ ///
+ public static HttpFeature UseOpenApi(this HttpFeature feature, Action? configure = default)
+ {
+ feature.Module.Configure(configure);
+ return feature;
+ }
+}
diff --git a/src/modules/http/Elsa.Http.OpenApi/Extensions/ServiceCollectionExtensions.cs b/src/modules/http/Elsa.Http.OpenApi/Extensions/ServiceCollectionExtensions.cs
new file mode 100644
index 00000000..fe13a45a
--- /dev/null
+++ b/src/modules/http/Elsa.Http.OpenApi/Extensions/ServiceCollectionExtensions.cs
@@ -0,0 +1,25 @@
+using Elsa.Http.OpenApi.Contracts;
+using Elsa.Http.OpenApi.Services;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Elsa.Http.OpenApi.Extensions;
+
+///
+/// Extension methods for configuring HTTP OpenAPI services.
+///
+public static class ServiceCollectionExtensions
+{
+ ///
+ /// Adds HTTP OpenAPI services to the service collection.
+ ///
+ /// The service collection.
+ /// The service collection for chaining.
+ public static IServiceCollection AddElsaHttpOpenApi(this IServiceCollection services)
+ {
+ services.AddScoped();
+ services.AddSingleton();
+ services.AddSingleton();
+
+ return services;
+ }
+}
diff --git a/src/modules/http/Elsa.Http.OpenApi/Features/HttpOpenApiFeature.cs b/src/modules/http/Elsa.Http.OpenApi/Features/HttpOpenApiFeature.cs
new file mode 100644
index 00000000..d298b579
--- /dev/null
+++ b/src/modules/http/Elsa.Http.OpenApi/Features/HttpOpenApiFeature.cs
@@ -0,0 +1,25 @@
+using Elsa.Features.Abstractions;
+using Elsa.Features.Attributes;
+using Elsa.Features.Services;
+using Elsa.Http.Features;
+using Elsa.Http.OpenApi.Extensions;
+
+namespace Elsa.Http.OpenApi.Features;
+
+///
+/// Feature for HTTP OpenAPI functionality.
+///
+[DependsOn(typeof(HttpFeature))]
+public class HttpOpenApiFeature : FeatureBase
+{
+ ///
+ public HttpOpenApiFeature(IModule module) : base(module)
+ {
+ }
+
+ ///
+ public override void Apply()
+ {
+ Services.AddElsaHttpOpenApi();
+ }
+}
diff --git a/src/modules/http/Elsa.Http.OpenApi/FodyWeavers.xml b/src/modules/http/Elsa.Http.OpenApi/FodyWeavers.xml
new file mode 100644
index 00000000..00e1d9a1
--- /dev/null
+++ b/src/modules/http/Elsa.Http.OpenApi/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/src/modules/http/Elsa.Http.OpenApi/Models/EndpointDefinition.cs b/src/modules/http/Elsa.Http.OpenApi/Models/EndpointDefinition.cs
new file mode 100644
index 00000000..b7df861c
--- /dev/null
+++ b/src/modules/http/Elsa.Http.OpenApi/Models/EndpointDefinition.cs
@@ -0,0 +1,18 @@
+namespace Elsa.Http.OpenApi.Models;
+
+///
+/// Represents an HTTP endpoint definition extracted from a workflow.
+///
+/// The HTTP path of the endpoint.
+/// The HTTP method (GET, POST, etc.).
+/// Optional summary description of the endpoint.
+/// The workflow definition ID that contains this endpoint.
+/// The name of the workflow definition.
+/// The version of the workflow definition.
+public record EndpointDefinition(
+ string Path,
+ string Method,
+ string? Summary = null,
+ string? WorkflowDefinitionId = null,
+ string? WorkflowDefinitionName = null,
+ int? WorkflowVersion = null);
diff --git a/src/modules/http/Elsa.Http.OpenApi/README.md b/src/modules/http/Elsa.Http.OpenApi/README.md
new file mode 100644
index 00000000..e69de29b
diff --git a/src/modules/http/Elsa.Http.OpenApi/Services/ElsaVersionProvider.cs b/src/modules/http/Elsa.Http.OpenApi/Services/ElsaVersionProvider.cs
new file mode 100644
index 00000000..4775ec1d
--- /dev/null
+++ b/src/modules/http/Elsa.Http.OpenApi/Services/ElsaVersionProvider.cs
@@ -0,0 +1,44 @@
+using System.Linq;
+using System.Reflection;
+using Elsa.Http.OpenApi.Contracts;
+
+namespace Elsa.Http.OpenApi.Services;
+
+///
+/// Service for retrieving Elsa package version information by examining loaded assemblies.
+///
+public class ElsaVersionProvider : IElsaVersionProvider
+{
+ ///
+ /// Gets the Elsa package version by examining loaded assemblies.
+ ///
+ /// The package version string.
+ public string GetVersion()
+ {
+ // Try to get version from Elsa.Workflows.Core assembly first
+ var elsaCoreAssembly = AppDomain.CurrentDomain.GetAssemblies()
+ .FirstOrDefault(a => a.GetName().Name == "Elsa.Workflows.Core");
+
+ if (elsaCoreAssembly != null)
+ {
+ var versionAttribute = elsaCoreAssembly.GetCustomAttribute();
+ return RemoveAutoGeneratedPostfix(versionAttribute);
+ }
+
+ // Fallback to any Elsa assembly
+ var elsaAssembly = AppDomain.CurrentDomain.GetAssemblies()
+ .FirstOrDefault(a => a.GetName().Name?.StartsWith("Elsa.") == true);
+
+ if (elsaAssembly != null)
+ {
+ var versionAttribute = elsaAssembly.GetCustomAttribute();
+ return RemoveAutoGeneratedPostfix(versionAttribute);
+ }
+
+ // Final fallback
+ return "1.0.0";
+ }
+
+ private static string RemoveAutoGeneratedPostfix(AssemblyInformationalVersionAttribute? versionAttribute) =>
+ versionAttribute?.InformationalVersion.Split("+")[0] ?? "1.0.0";
+}
diff --git a/src/modules/http/Elsa.Http.OpenApi/Services/OpenApiGenerator.cs b/src/modules/http/Elsa.Http.OpenApi/Services/OpenApiGenerator.cs
new file mode 100644
index 00000000..0b88e617
--- /dev/null
+++ b/src/modules/http/Elsa.Http.OpenApi/Services/OpenApiGenerator.cs
@@ -0,0 +1,85 @@
+using Elsa.Http.OpenApi.Contracts;
+using Elsa.Http.OpenApi.Models;
+using System.Text.Json;
+
+namespace Elsa.Http.OpenApi.Services;
+
+///
+/// Service for generating OpenAPI JSON documentation from workflow endpoints.
+///
+public class OpenApiGenerator : IOpenApiGenerator
+{
+ private readonly IElsaVersionProvider _versionProvider;
+
+ public OpenApiGenerator(IElsaVersionProvider versionProvider)
+ {
+ _versionProvider = versionProvider;
+ }
+
+ ///
+ /// Generates OpenAPI JSON documentation from a list of endpoint definitions.
+ ///
+ /// The list of endpoint definitions.
+ /// OpenAPI JSON string.
+ public string GenerateOpenApiJson(List endpoints)
+ {
+ var openApiDoc = new
+ {
+ openapi = "3.0.0",
+ info = new
+ {
+ title = "Elsa Workflow HTTP Endpoints",
+ version = _versionProvider.GetVersion(),
+ description = "HTTP endpoints exposed by Elsa workflows"
+ },
+ paths = GeneratePaths(endpoints)
+ };
+
+ return JsonSerializer.Serialize(openApiDoc, new JsonSerializerOptions
+ {
+ WriteIndented = true,
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase
+ });
+ }
+
+ private object GeneratePaths(List endpoints)
+ {
+ var paths = new Dictionary();
+
+ foreach (var endpoint in endpoints)
+ {
+ if (!paths.ContainsKey(endpoint.Path))
+ {
+ paths[endpoint.Path] = new Dictionary();
+ }
+
+ var pathItem = (Dictionary)paths[endpoint.Path];
+
+ // Create description with workflow definition ID if available
+ var description = endpoint.WorkflowDefinitionId != null
+ ? $"Workflow endpoint from '{endpoint.WorkflowDefinitionName}' (ID: {endpoint.WorkflowDefinitionId})"
+ : $"Workflow endpoint for {endpoint.Method.ToUpperInvariant()} {endpoint.Path}";
+
+ // Use workflow name as tag, fallback to "Workflows"
+ var tags = endpoint.WorkflowDefinitionName != null
+ ? new[] { endpoint.WorkflowDefinitionName }
+ : new[] { "Workflows" };
+
+ pathItem[endpoint.Method.ToLowerInvariant()] = new
+ {
+ summary = $"{endpoint.Method.ToUpperInvariant()} {endpoint.Path}",
+ description = description,
+ responses = new
+ {
+ @default = new
+ {
+ description = "Response from workflow execution"
+ }
+ },
+ tags = tags
+ };
+ }
+
+ return paths;
+ }
+}
diff --git a/src/modules/http/Elsa.Http.OpenApi/Services/WorkflowEndpointExtractor.cs b/src/modules/http/Elsa.Http.OpenApi/Services/WorkflowEndpointExtractor.cs
new file mode 100644
index 00000000..f0a5dc9c
--- /dev/null
+++ b/src/modules/http/Elsa.Http.OpenApi/Services/WorkflowEndpointExtractor.cs
@@ -0,0 +1,76 @@
+using Elsa.Extensions;
+using Elsa.Http;
+using Elsa.Http.Bookmarks;
+using Elsa.Http.OpenApi.Contracts;
+using Elsa.Http.OpenApi.Models;
+using Elsa.Workflows.Helpers;
+using Elsa.Workflows.Runtime;
+using Elsa.Workflows.Runtime.Filters;
+using Elsa.Common.Models;
+using Elsa.Workflows;
+using System.Net;
+using Elsa.Scheduling.Activities;
+using Elsa.Workflows.Management;
+using Elsa.Workflows.Management.Services;
+using Elsa.Workflows.Management.Stores;
+using Elsa.Workflows.Management.Filters;
+using Elsa.Workflows.Models;
+
+namespace Elsa.Http.OpenApi.Services;
+
+///
+/// Service for extracting HTTP endpoint definitions from Elsa workflows.
+///
+public class WorkflowEndpointExtractor : IWorkflowEndpointExtractor
+{
+ private readonly ITriggerStore _triggerStore;
+ private readonly IWorkflowDefinitionStore _workflowDefinitionStore;
+
+ public WorkflowEndpointExtractor(ITriggerStore triggerStore, IWorkflowDefinitionStore workflowDefinitionStore)
+ {
+ _triggerStore = triggerStore;
+ _workflowDefinitionStore = workflowDefinitionStore;
+ }
+
+ public async Task> ExtractEndpointsAsync(CancellationToken cancellationToken = default)
+ {
+ var endpoints = new List();
+
+ var httpEndpointTypeName = ActivityTypeNameHelper.GenerateTypeName();
+ var triggerFilter = new TriggerFilter
+ {
+ Name = httpEndpointTypeName
+ };
+ var triggers = (await _triggerStore.FindManyAsync(triggerFilter, cancellationToken)).ToList();
+
+ var filteredTriggers = triggers.Where(x => x.Name == httpEndpointTypeName && x.Payload != null);
+
+ // Group triggers by workflow definition ID to minimize database queries
+ var triggersByWorkflow = filteredTriggers.GroupBy(t => t.WorkflowDefinitionId);
+
+ foreach (var workflowGroup in triggersByWorkflow)
+ {
+ var workflowDefinitionId = workflowGroup.Key;
+
+ // Get workflow definition information
+ var filter = new WorkflowDefinitionFilter { DefinitionId = workflowDefinitionId };
+ var workflowDefinition = await _workflowDefinitionStore.FindAsync(filter, cancellationToken);
+
+ foreach (var trigger in workflowGroup)
+ {
+ var payload = trigger.GetPayload();
+
+ endpoints.Add(new EndpointDefinition(
+ Path: payload.Path,
+ Method: payload.Method,
+ Summary: null, // Could be enhanced to extract from activity properties
+ WorkflowDefinitionId: workflowDefinitionId,
+ WorkflowDefinitionName: workflowDefinition?.Name ?? "Unknown Workflow",
+ WorkflowVersion: workflowDefinition?.Version
+ ));
+ }
+ }
+
+ return endpoints;
+ }
+}