diff --git a/simulator-samples/sample-swagger/src/main/resources/swagger/petstore-api.json b/simulator-samples/sample-swagger/src/main/resources/swagger/petstore-api.json
index 5d2e8e3d0..5fc5236b7 100644
--- a/simulator-samples/sample-swagger/src/main/resources/swagger/petstore-api.json
+++ b/simulator-samples/sample-swagger/src/main/resources/swagger/petstore-api.json
@@ -1,5 +1,5 @@
 {
-  "swagger": "3.0.3",
+  "swagger": "2.0",
   "info": {
     "description": "This is a sample server Petstore server.  You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/).  For this sample, you can use the api key `special-key` to test the authorization filters.",
     "version": "1.0.0",
@@ -1032,4 +1032,4 @@
     "description": "Find out more about Swagger",
     "url": "http://swagger.io"
   }
-}
\ No newline at end of file
+}
diff --git a/simulator-spring-boot/pom.xml b/simulator-spring-boot/pom.xml
index aa94c2c5b..82889791f 100644
--- a/simulator-spring-boot/pom.xml
+++ b/simulator-spring-boot/pom.xml
@@ -130,6 +130,10 @@
       <groupId>org.citrusframework</groupId>
       <artifactId>citrus-http</artifactId>
     </dependency>
+      <dependency>
+          <groupId>org.citrusframework</groupId>
+          <artifactId>citrus-openapi</artifactId>
+      </dependency>
     <dependency>
       <groupId>org.citrusframework</groupId>
       <artifactId>citrus-ws</artifactId>
diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/config/OpenApiScenarioIdGenerationMode.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/config/OpenApiScenarioIdGenerationMode.java
new file mode 100644
index 000000000..669816336
--- /dev/null
+++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/config/OpenApiScenarioIdGenerationMode.java
@@ -0,0 +1,25 @@
+package org.citrusframework.simulator.config;
+
+/**
+ * Enumeration representing the modes for generating scenario IDs in an OpenAPI context.
+ * This enumeration defines two modes:
+ * <ul>
+ *     <li>{@link #OPERATION_ID}: Uses the operation ID defined in the OpenAPI specification.</li>
+ *     <li>{@link #FULL_PATH}: Uses the full path of the API endpoint.</li>
+ * </ul>
+ * The choice of mode affects how scenario IDs are generated, with important implications:
+ *  <ul>
+ *      <li><b>OPERATION_ID:</b> This mode relies on the {@code operationId} field in the OpenAPI specification, which
+ *      provides a unique identifier for each operation. However, the {@code operationId} is not mandatory in the OpenAPI
+ *      specification. If an {@code operationId} is not specified, this mode cannot be used effectively.</li>
+ *      <li><b>FULL_PATH:</b> This mode constructs scenario IDs based on the entire URL path of the API endpoint, including
+ *      path parameters. This is particularly useful when simulating multiple versions of the same API, as it allows for
+ *      differentiation based on the endpoint path. This mode ensures unique scenario IDs even when {@code operationId}
+ *      is not available or when versioning of APIs needs to be distinguished.</li>
+ *  </ul>
+ *  </p>
+ */
+public enum OpenApiScenarioIdGenerationMode {
+    FULL_PATH,
+    OPERATION_ID
+}
diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/config/SimulatorConfigurationProperties.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/config/SimulatorConfigurationProperties.java
index 5214fa6c9..27cc1e01e 100644
--- a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/config/SimulatorConfigurationProperties.java
+++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/config/SimulatorConfigurationProperties.java
@@ -16,13 +16,17 @@
 
 package org.citrusframework.simulator.config;
 
+import jakarta.annotation.Nonnull;
 import lombok.Getter;
 import lombok.Setter;
 import lombok.ToString;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeansException;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
 import org.springframework.context.EnvironmentAware;
 import org.springframework.core.env.Environment;
 
@@ -33,7 +37,7 @@
 @Setter
 @ToString
 @ConfigurationProperties(prefix = "citrus.simulator")
-public class SimulatorConfigurationProperties implements EnvironmentAware, InitializingBean {
+public class SimulatorConfigurationProperties implements ApplicationContextAware, EnvironmentAware, InitializingBean {
 
     private static final Logger logger = LoggerFactory.getLogger(SimulatorConfigurationProperties.class);
 
@@ -46,6 +50,8 @@ public class SimulatorConfigurationProperties implements EnvironmentAware, Initi
     private static final String SIMULATOR_OUTBOUND_JSON_DICTIONARY_PROPERTY = "citrus.simulator.outbound.json.dictionary.location";
     private static final String SIMULATOR_OUTBOUND_JSON_DICTIONARY_ENV = "CITRUS_SIMULATOR_OUTBOUND_JSON_DICTIONARY_LOCATION";
 
+    private static ApplicationContext applicationContext;
+
     /**
      * Global option to enable/disable simulator support, default is true.
      */
@@ -104,6 +110,15 @@ public class SimulatorConfigurationProperties implements EnvironmentAware, Initi
 
     private SimulationResults simulationResults = new SimulationResults();
 
+    public static ApplicationContext getApplicationContext() {
+        if (applicationContext == null) {
+            throw new IllegalStateException("Application context has not been initialized. This bean needs to be instantiated by Spring in order to function properly!");
+        }
+        return applicationContext;
+    }
+
+
+
     @Override
     public void setEnvironment(Environment environment) {
         inboundXmlDictionary = environment.getProperty(SIMULATOR_INBOUND_XML_DICTIONARY_PROPERTY, environment.getProperty(SIMULATOR_INBOUND_XML_DICTIONARY_ENV, inboundXmlDictionary));
@@ -117,6 +132,15 @@ public void afterPropertiesSet() {
         logger.info("Using the simulator configuration: {}", this);
     }
 
+    @Override
+    public void setApplicationContext(@Nonnull ApplicationContext context) throws BeansException {
+        initStaticApplicationContext(context);
+    }
+
+    private static void initStaticApplicationContext(ApplicationContext context) {
+        applicationContext = context;
+    }
+
     @Getter
     @Setter
     @ToString
@@ -127,4 +151,5 @@ public static class SimulationResults {
          */
         private boolean resetEnabled = true;
     }
+
 }
diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/http/HttpOperationScenario.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/http/HttpOperationScenario.java
index 8f4ee0b40..8334077da 100644
--- a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/http/HttpOperationScenario.java
+++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/http/HttpOperationScenario.java
@@ -16,395 +16,132 @@
 
 package org.citrusframework.simulator.http;
 
-import io.swagger.models.ArrayModel;
-import io.swagger.models.Model;
-import io.swagger.models.Operation;
-import io.swagger.models.RefModel;
-import io.swagger.models.Response;
-import io.swagger.models.parameters.AbstractSerializableParameter;
-import io.swagger.models.parameters.BodyParameter;
-import io.swagger.models.parameters.HeaderParameter;
-import io.swagger.models.parameters.Parameter;
-import io.swagger.models.parameters.QueryParameter;
-import io.swagger.models.properties.ArrayProperty;
-import io.swagger.models.properties.BooleanProperty;
-import io.swagger.models.properties.DateProperty;
-import io.swagger.models.properties.DateTimeProperty;
-import io.swagger.models.properties.DoubleProperty;
-import io.swagger.models.properties.FloatProperty;
-import io.swagger.models.properties.IntegerProperty;
-import io.swagger.models.properties.LongProperty;
-import io.swagger.models.properties.Property;
-import io.swagger.models.properties.RefProperty;
-import io.swagger.models.properties.StringProperty;
-import org.citrusframework.http.actions.HttpServerRequestActionBuilder;
+import static java.lang.String.format;
+import static org.citrusframework.actions.EchoAction.Builder.echo;
+
+import io.apicurio.datamodels.openapi.models.OasDocument;
+import io.apicurio.datamodels.openapi.models.OasOperation;
+import io.apicurio.datamodels.openapi.models.OasResponse;
+import java.util.concurrent.atomic.AtomicReference;
+import lombok.Getter;
 import org.citrusframework.http.actions.HttpServerResponseActionBuilder;
-import org.citrusframework.http.message.HttpMessageHeaders;
+import org.citrusframework.message.Message;
 import org.citrusframework.message.MessageHeaders;
-import org.citrusframework.message.MessageType;
-import org.citrusframework.simulator.exception.SimulatorException;
+import org.citrusframework.openapi.OpenApiSpecification;
+import org.citrusframework.openapi.actions.OpenApiActionBuilder;
+import org.citrusframework.openapi.actions.OpenApiServerActionBuilder;
+import org.citrusframework.openapi.actions.OpenApiServerRequestActionBuilder;
+import org.citrusframework.openapi.model.OasModelHelper;
+import org.citrusframework.simulator.config.OpenApiScenarioIdGenerationMode;
 import org.citrusframework.simulator.scenario.AbstractSimulatorScenario;
 import org.citrusframework.simulator.scenario.ScenarioRunner;
 import org.citrusframework.variable.dictionary.json.JsonPathMappingDataDictionary;
-import org.hamcrest.CustomMatcher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-import org.springframework.util.AntPathMatcher;
-import org.springframework.util.CollectionUtils;
-import org.springframework.util.StringUtils;
-import org.springframework.web.bind.annotation.RequestMethod;
-
-import java.util.Map;
-import java.util.stream.Collectors;
-
-import static org.citrusframework.actions.EchoAction.Builder.echo;
 
+@Getter
 public class HttpOperationScenario extends AbstractSimulatorScenario {
 
-    /** Operation in wsdl */
-    private final Operation operation;
-
-    /** Schema model definitions */
-    private final Map<String, Model> definitions;
+    private static final Logger logger = LoggerFactory.getLogger(HttpOperationScenario.class);
 
-    /** Request path */
     private final String path;
 
-    /** Request method */
-    private final RequestMethod method;
+    private final String scenarioId;
 
-    /** Response */
-    private Response response;
+    private final OpenApiSpecification openApiSpecification;
+
+    private final OasOperation operation;
+
+    private OasResponse response;
 
-    /** Response status code */
     private HttpStatus statusCode = HttpStatus.OK;
 
     private JsonPathMappingDataDictionary inboundDataDictionary;
+
     private JsonPathMappingDataDictionary outboundDataDictionary;
 
-    /**
-     * Default constructor.
-     * @param path
-     * @param method
-     * @param operation
-     * @param definitions
-     */
-    public HttpOperationScenario(String path, RequestMethod method, Operation operation, Map<String, Model> definitions) {
-        this.operation = operation;
-        this.definitions = definitions;
+    private final HttpResponseActionBuilderProvider httpResponseActionBuilderProvider;
+
+    public HttpOperationScenario(String path, String scenarioId, OpenApiSpecification openApiSpecification, OasOperation operation, HttpResponseActionBuilderProvider httpResponseActionBuilderProvider) {
         this.path = path;
-        this.method = method;
+        this.scenarioId = scenarioId;
+        this.openApiSpecification = openApiSpecification;
+        this.operation = operation;
+        this.httpResponseActionBuilderProvider = httpResponseActionBuilderProvider;
 
-        if (operation.getResponses() != null) {
-            this.response = operation.getResponses().get("200");
-        }
+        // Note, that in case of an absent response, an OK response will be sent. This is to maintain backwards compatibility with previous swagger implementation.
+        // Also, the petstore api lacks the definition of good responses for several operations
+        this.response = OasModelHelper.getResponseForRandomGeneration(getOasDocument(), operation).orElse(null);
     }
 
     @Override
     public void run(ScenarioRunner scenario) {
-        scenario.name(operation.getOperationId());
-        scenario.$(echo("Generated scenario from swagger operation: " + operation.getOperationId()));
-
-        HttpServerRequestActionBuilder requestBuilder = switch (method) {
-            case GET -> scenario.http()
-                    .receive()
-                    .get();
-            case POST -> scenario.http()
-                    .receive()
-                    .post();
-            case PUT -> scenario.http()
-                    .receive()
-                    .put();
-            case HEAD -> scenario.http()
-                    .receive()
-                    .head();
-            case DELETE -> scenario.http()
-                    .receive()
-                    .delete();
-            default -> throw new SimulatorException("Unsupported request method: " + method.name());
-        };
-
-        requestBuilder
-            .message()
-            .type(MessageType.JSON)
-            .header(MessageHeaders.MESSAGE_PREFIX + "generated", true)
-            .header(HttpMessageHeaders.HTTP_REQUEST_URI, new CustomMatcher<String>(String.format("request path matching %s", path)) {
-                @Override
-                public boolean matches(Object item) {
-                    return ((item instanceof String) && new AntPathMatcher().match(path, (String) item));
-                }
-            });
-
-        if (operation.getParameters() != null) {
-            operation.getParameters().stream()
-                    .filter(p -> p instanceof HeaderParameter)
-                    .filter(Parameter::getRequired)
-                    .forEach(p -> requestBuilder.message().header(p.getName(), createValidationExpression(((HeaderParameter) p))));
-
-            String queryParams = operation.getParameters().stream()
-                    .filter(param -> param instanceof QueryParameter)
-                    .filter(Parameter::getRequired)
-                    .map(param -> "containsString(" + param.getName() + ")")
-                    .collect(Collectors.joining(", "));
-
-            if (StringUtils.hasText(queryParams)) {
-                requestBuilder.message().header(HttpMessageHeaders.HTTP_QUERY_PARAMS, "@assertThat(allOf(" + queryParams + "))@");
-            }
-
-            operation.getParameters().stream()
-                    .filter(p -> p instanceof BodyParameter)
-                    .filter(Parameter::getRequired)
-                    .forEach(p -> requestBuilder.message().body(createValidationPayload((BodyParameter) p)));
-
-            if (inboundDataDictionary != null) {
-                requestBuilder.message().dictionary(inboundDataDictionary);
-            }
-        }
-
-        // Verify incoming request
-        scenario.$(requestBuilder);
+        scenario.name(operation.operationId);
+        scenario.$(echo("Generated scenario from swagger operation: " + operation.operationId));
 
-        HttpServerResponseActionBuilder responseBuilder = scenario.http()
-            .send()
-            .response(statusCode);
+        OpenApiServerActionBuilder openApiServerActionBuilder = new OpenApiActionBuilder(
+            openApiSpecification).server(getScenarioEndpoint());
 
-        responseBuilder.message()
-            .type(MessageType.JSON)
-            .header(MessageHeaders.MESSAGE_PREFIX + "generated", true)
-            .contentType(MediaType.APPLICATION_JSON_VALUE);
-
-        if (response != null) {
-            if (response.getHeaders() != null) {
-                for (Map.Entry<String, Property> header : response.getHeaders().entrySet()) {
-                    responseBuilder.message().header(header.getKey(), createRandomValue(header.getValue(), false));
-                }
-            }
-
-            if (response.getSchema() != null) {
-                if (outboundDataDictionary != null &&
-                        (response.getSchema() instanceof RefProperty || response.getSchema() instanceof ArrayProperty)) {
-                    responseBuilder.message().dictionary(outboundDataDictionary);
-                }
-
-                responseBuilder.message().body(createRandomValue(response.getSchema(), false));
-            }
-        }
-
-        // Return generated response
-        scenario.$(responseBuilder);
+        Message receivedMessage = receive(scenario, openApiServerActionBuilder);
+        respond(scenario, openApiServerActionBuilder, receivedMessage);
     }
 
-    /**
-     * Create payload from schema with random values.
-     * @param property
-     * @param quotes
-     * @return
-     */
-    private String createRandomValue(Property property, boolean quotes) {
-        StringBuilder payload = new StringBuilder();
-        if (property instanceof RefProperty) {
-            Model model = definitions.get(((RefProperty) property).getSimpleRef());
-            payload.append("{");
-
-            if (model.getProperties() != null) {
-                for (Map.Entry<String, Property> entry : model.getProperties().entrySet()) {
-                    payload.append("\"").append(entry.getKey()).append("\": ").append(createRandomValue(entry.getValue(), true)).append(",");
-                }
-            }
-
-            if (payload.toString().endsWith(",")) {
-                payload.replace(payload.length() - 1, payload.length(), "");
-            }
-
-            payload.append("}");
-        } else if (property instanceof ArrayProperty) {
-            payload.append("[");
-            payload.append(createRandomValue(((ArrayProperty) property).getItems(), true));
-            payload.append("]");
-        } else if (property instanceof StringProperty || property instanceof DateProperty || property instanceof DateTimeProperty) {
-            if (quotes) {
-                payload.append("\"");
-            }
-
-            if (property instanceof DateProperty) {
-                payload.append("citrus:currentDate()");
-            } else if (property instanceof DateTimeProperty) {
-                payload.append("citrus:currentDate('yyyy-MM-dd'T'hh:mm:ss')");
-            } else if (!CollectionUtils.isEmpty(((StringProperty) property).getEnum())) {
-                payload.append("citrus:randomEnumValue(").append(((StringProperty) property).getEnum().stream().map(value -> "'" + value + "'").collect(Collectors.joining(","))).append(")");
-            } else {
-                payload.append("citrus:randomString(").append(((StringProperty) property).getMaxLength() != null && ((StringProperty) property).getMaxLength() > 0 ? ((StringProperty) property).getMaxLength() : (((StringProperty) property).getMinLength() != null && ((StringProperty) property).getMinLength() > 0 ? ((StringProperty) property).getMinLength() : 10)).append(")");
-            }
-
-            if (quotes) {
-                payload.append("\"");
-            }
-        } else if (property instanceof IntegerProperty || property instanceof LongProperty) {
-            payload.append("citrus:randomNumber(10)");
-        } else if (property instanceof FloatProperty || property instanceof DoubleProperty) {
-            payload.append("citrus:randomNumber(10)");
-        } else if (property instanceof BooleanProperty) {
-            payload.append("citrus:randomEnumValue('true', 'false')");
-        } else {
-            if (quotes) {
-                payload.append("\"\"");
-            } else {
-                payload.append("");
-            }
-        }
-
-        return payload.toString();
-    }
+    private Message receive(ScenarioRunner scenario,
+        OpenApiServerActionBuilder openApiServerActionBuilder) {
 
-    /**
-     * Creates control payload for validation.
-     * @param parameter
-     * @return
-     */
-    private String createValidationPayload(BodyParameter parameter) {
-        StringBuilder payload = new StringBuilder();
+        OpenApiServerRequestActionBuilder requestActionBuilder = openApiServerActionBuilder.receive(
+            operation.operationId);
 
-        Model model = parameter.getSchema();
+        requestActionBuilder
+            .message()
+            .header(MessageHeaders.MESSAGE_PREFIX + "generated", true);
 
-        if (model instanceof RefModel) {
-            model = definitions.get(((RefModel) model).getSimpleRef());
+        if (operation.getParameters() != null && inboundDataDictionary != null) {
+            requestActionBuilder.message().dictionary(inboundDataDictionary);
         }
 
-        if (model instanceof ArrayModel) {
-            payload.append("[");
-            payload.append(createValidationExpression(((ArrayModel) model).getItems()));
-            payload.append("]");
-        } else {
-
-            payload.append("{");
-
-            if (model.getProperties() != null) {
-                for (Map.Entry<String, Property> entry : model.getProperties().entrySet()) {
-                    payload.append("\"").append(entry.getKey()).append("\": ").append(createValidationExpression(entry.getValue())).append(",");
-                }
-            }
+        AtomicReference<Message> receivedMessage = new AtomicReference<>();
+        requestActionBuilder.getMessageProcessors().add(
+            (message, context) -> receivedMessage.set(message));
 
-            if (payload.toString().endsWith(",")) {
-                payload.replace(payload.length() - 1, payload.length(), "");
-            }
-
-            payload.append("}");
-        }
+        // Verify incoming request
+        scenario.$(requestActionBuilder);
 
-        return payload.toString();
+        return receivedMessage.get();
     }
 
-    /**
-     * Create validation expression using functions according to parameter type and format.
-     * @param property
-     * @return
-     */
-    private String createValidationExpression(Property property) {
-        StringBuilder payload = new StringBuilder();
-        if (property instanceof RefProperty) {
-            Model model = definitions.get(((RefProperty) property).getSimpleRef());
-            payload.append("{");
-
-            if (model.getProperties() != null) {
-                for (Map.Entry<String, Property> entry : model.getProperties().entrySet()) {
-                    payload.append("\"").append(entry.getKey()).append("\": ").append(createValidationExpression(entry.getValue())).append(",");
-                }
-            }
-
-            if (payload.toString().endsWith(",")) {
-                payload.replace(payload.length() - 1, payload.length(), "");
-            }
-
-            payload.append("}");
-        } else if (property instanceof ArrayProperty) {
-            payload.append("\"@ignore@\"");
-        } else if (property instanceof StringProperty) {
-            if (StringUtils.hasText(((StringProperty) property).getPattern())) {
-                payload.append("\"@matches(").append(((StringProperty) property).getPattern()).append(")@\"");
-            } else if (!CollectionUtils.isEmpty(((StringProperty) property).getEnum())) {
-                payload.append("\"@matches(").append(((StringProperty) property).getEnum().stream().collect(Collectors.joining("|"))).append(")@\"");
-            } else {
-                payload.append("\"@notEmpty()@\"");
-            }
-        } else if (property instanceof DateProperty) {
-            payload.append("\"@matchesDatePattern('yyyy-MM-dd')@\"");
-        } else if (property instanceof DateTimeProperty) {
-            payload.append("\"@matchesDatePattern('yyyy-MM-dd'T'hh:mm:ss')@\"");
-        } else if (property instanceof IntegerProperty || property instanceof LongProperty) {
-            payload.append("\"@isNumber()@\"");
-        } else if (property instanceof FloatProperty || property instanceof DoubleProperty) {
-            payload.append("\"@isNumber()@\"");
-        } else if (property instanceof BooleanProperty) {
-            payload.append("\"@matches(true|false)@\"");
-        } else {
-            payload.append("\"@ignore@\"");
-        }
-
-        return payload.toString();
-    }
+    private void respond(ScenarioRunner scenario,
+        OpenApiServerActionBuilder openApiServerActionBuilder, Message receivedMessage) {
 
-    /**
-     * Create validation expression using functions according to parameter type and format.
-     * @param parameter
-     * @return
-     */
-    private String createValidationExpression(AbstractSerializableParameter parameter) {
-        switch (parameter.getType()) {
-            case "integer":
-                return "@isNumber()@";
-            case "string":
-                if (parameter.getFormat() != null && parameter.getFormat().equals("date")) {
-                    return "\"@matchesDatePattern('yyyy-MM-dd')@\"";
-                } else if (parameter.getFormat() != null && parameter.getFormat().equals("date-time")) {
-                    return "\"@matchesDatePattern('yyyy-MM-dd'T'hh:mm:ss')@\"";
-                } else if (StringUtils.hasText(parameter.getPattern())) {
-                    return "\"@matches(" + parameter.getPattern() + ")@\"";
-                } else if (!CollectionUtils.isEmpty(parameter.getEnum())) {
-                    return "\"@matches(" + (parameter.getEnum().stream().collect(Collectors.joining("|"))) + ")@\"";
-                } else {
-                    return "@notEmpty()@";
-                }
-            case "boolean":
-                return "@matches(true|false)@";
-            default:
-                return "@ignore@";
+        HttpServerResponseActionBuilder responseBuilder = null;
+        if (httpResponseActionBuilderProvider != null) {
+            responseBuilder = httpResponseActionBuilderProvider.provideHttpServerResponseActionBuilder(operation, receivedMessage);
         }
-    }
 
-    /**
-     * Gets the operation.
-     *
-     * @return
-     */
-    public Operation getOperation() {
-        return operation;
-    }
+        HttpStatus httpStatus = response != null && response.getStatusCode() != null ? HttpStatus.valueOf(Integer.parseInt(response.getStatusCode())) : HttpStatus.OK;
+        responseBuilder = responseBuilder != null ? responseBuilder : openApiServerActionBuilder.send(
+            operation.operationId, httpStatus);
 
-    /**
-     * Gets the path.
-     *
-     * @return
-     */
-    public String getPath() {
-        return path;
+        responseBuilder.message()
+            .status(httpStatus)
+            .header(MessageHeaders.MESSAGE_PREFIX + "generated", true);
+
+        // Return generated response
+        scenario.$(responseBuilder);
     }
 
     /**
-     * Gets the method.
+     * Gets the document.
      *
      * @return
      */
-    public RequestMethod getMethod() {
-        return method;
+    public OasDocument getOasDocument() {
+        return openApiSpecification.getOpenApiDoc(null);
     }
 
-    /**
-     * Gets the response.
-     *
-     * @return
-     */
-    public Response getResponse() {
-        return response;
+    public String getMethod() {
+        return operation.getMethod() != null ? operation.getMethod().toUpperCase() : null;
     }
 
     /**
@@ -412,19 +149,10 @@ public Response getResponse() {
      *
      * @param response
      */
-    public void setResponse(Response response) {
+    public void setResponse(OasResponse response) {
         this.response = response;
     }
 
-    /**
-     * Gets the statusCode.
-     *
-     * @return
-     */
-    public HttpStatus getStatusCode() {
-        return statusCode;
-    }
-
     /**
      * Sets the statusCode.
      *
@@ -434,15 +162,6 @@ public void setStatusCode(HttpStatus statusCode) {
         this.statusCode = statusCode;
     }
 
-    /**
-     * Gets the inboundDataDictionary.
-     *
-     * @return
-     */
-    public JsonPathMappingDataDictionary getInboundDataDictionary() {
-        return inboundDataDictionary;
-    }
-
     /**
      * Sets the inboundDataDictionary.
      *
@@ -453,20 +172,28 @@ public void setInboundDataDictionary(JsonPathMappingDataDictionary inboundDataDi
     }
 
     /**
-     * Gets the outboundDataDictionary.
+     * Sets the outboundDataDictionary.
      *
-     * @return
+     * @param outboundDataDictionary
      */
-    public JsonPathMappingDataDictionary getOutboundDataDictionary() {
-        return outboundDataDictionary;
+    public void setOutboundDataDictionary(JsonPathMappingDataDictionary outboundDataDictionary) {
+        this.outboundDataDictionary = outboundDataDictionary;
     }
 
     /**
-     * Sets the outboundDataDictionary.
+     * Retrieve a unique scenario id for the oas operation.
      *
-     * @param outboundDataDictionary
+     * @param openApiScenarioIdGenerationMode
+     * @param path
+     * @param oasOperation
+     * @return
      */
-    public void setOutboundDataDictionary(JsonPathMappingDataDictionary outboundDataDictionary) {
-        this.outboundDataDictionary = outboundDataDictionary;
+    public static String getUniqueScenarioId(
+        OpenApiScenarioIdGenerationMode openApiScenarioIdGenerationMode, String path, OasOperation oasOperation) {
+
+        return switch(openApiScenarioIdGenerationMode)  {
+            case OPERATION_ID -> oasOperation.operationId;
+            case FULL_PATH -> format("%s_%s", oasOperation.getMethod().toUpperCase(), path);
+        };
     }
 }
diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/http/HttpOperationScenarioRegistrar.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/http/HttpOperationScenarioRegistrar.java
new file mode 100644
index 000000000..5bdc6eec3
--- /dev/null
+++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/http/HttpOperationScenarioRegistrar.java
@@ -0,0 +1,28 @@
+package org.citrusframework.simulator.http;
+
+import org.citrusframework.openapi.OpenApiSpecification;
+import org.citrusframework.openapi.OpenApiSpecificationProcessor;
+import org.citrusframework.simulator.config.SimulatorConfigurationProperties;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ConfigurableApplicationContext;
+
+/**
+ * Registrar for HTTP operation scenarios based on an OpenAPI specification.
+ * <p>
+ * This class implements the {@link OpenApiSpecificationProcessor} interface and processes an OpenAPI specification
+ * to register HTTP operation scenarios.
+ * </p>
+ */
+public class HttpOperationScenarioRegistrar implements OpenApiSpecificationProcessor {
+
+    @Override
+    public void process(OpenApiSpecification openApiSpecification) {
+
+        HttpScenarioGenerator generator = new HttpScenarioGenerator(openApiSpecification);
+        ApplicationContext applicationContext = SimulatorConfigurationProperties.getApplicationContext();
+
+        if (applicationContext instanceof ConfigurableApplicationContext configurableApplicationContext) {
+            generator.postProcessBeanFactory(configurableApplicationContext.getBeanFactory());
+        }
+    }
+}
diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/http/HttpRequestPathScenarioMapper.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/http/HttpRequestPathScenarioMapper.java
index ed4c4a475..1d7c9e0d9 100644
--- a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/http/HttpRequestPathScenarioMapper.java
+++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/http/HttpRequestPathScenarioMapper.java
@@ -16,6 +16,7 @@
 
 package org.citrusframework.simulator.http;
 
+import java.util.Objects;
 import org.citrusframework.http.message.HttpMessage;
 import org.citrusframework.message.Message;
 import org.citrusframework.simulator.config.SimulatorConfigurationProperties;
@@ -44,23 +45,19 @@ public class HttpRequestPathScenarioMapper extends AbstractScenarioMapper implem
 
     @Override
     protected String getMappingKey(Message request) {
-        if (request instanceof HttpMessage) {
-            String requestPath = ((HttpMessage) request).getPath();
+        if (request instanceof HttpMessage httpMessage) {
+            String requestPath = httpMessage.getPath();
 
             if (requestPath != null) {
                 for (HttpOperationScenario scenario : scenarioList) {
-                    if (scenario.getPath().equals(requestPath)) {
-                        if (scenario.getMethod().name().equals(((HttpMessage) request).getRequestMethod().name())) {
-                            return scenario.getOperation().getOperationId();
-                        }
+                    if (Objects.equals(scenario.getMethod(), ((HttpMessage) request).getRequestMethod().name()) && Objects.equals(requestPath, scenario.getPath())) {
+                        return scenario.getScenarioId();
                     }
                 }
 
                 for (HttpOperationScenario scenario : scenarioList) {
-                    if (pathMatcher.match(scenario.getPath(), requestPath)) {
-                        if (scenario.getMethod().name().equals(((HttpMessage) request).getRequestMethod().name())) {
-                            return scenario.getOperation().getOperationId();
-                        }
+                    if (Objects.equals(scenario.getMethod(), ((HttpMessage) request).getRequestMethod().name()) && pathMatcher.match(scenario.getPath(), requestPath)) {
+                        return scenario.getScenarioId();
                     }
                 }
             }
@@ -90,8 +87,8 @@ public void setHttpScenarios(List<HttpOperationScenario> httpScenarios) {
     @Override
     public void setScenarioList(List<SimulatorScenario> scenarioList) {
         this.scenarioList = scenarioList.stream()
-                                        .filter(scenario -> scenario instanceof HttpOperationScenario)
-                                        .map(scenario -> (HttpOperationScenario) scenario)
+                                        .filter(HttpOperationScenario.class::isInstance)
+                                        .map(HttpOperationScenario.class::cast)
                                         .toList();
     }
 
diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/http/HttpResponseActionBuilderProvider.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/http/HttpResponseActionBuilderProvider.java
new file mode 100644
index 000000000..a68b230b5
--- /dev/null
+++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/http/HttpResponseActionBuilderProvider.java
@@ -0,0 +1,15 @@
+package org.citrusframework.simulator.http;
+
+import io.apicurio.datamodels.openapi.models.OasOperation;
+import org.citrusframework.http.actions.HttpServerResponseActionBuilder;
+import org.citrusframework.message.Message;
+
+/**
+ * Interface for providing an {@link HttpServerResponseActionBuilder} based on an OpenAPI operation and a received message.
+ */
+public interface HttpResponseActionBuilderProvider {
+
+    HttpServerResponseActionBuilder provideHttpServerResponseActionBuilder(OasOperation oasOperation,
+        Message receivedMessage);
+
+}
diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/http/HttpScenarioGenerator.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/http/HttpScenarioGenerator.java
index c39673a1b..d7462bbac 100644
--- a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/http/HttpScenarioGenerator.java
+++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/http/HttpScenarioGenerator.java
@@ -16,17 +16,19 @@
 
 package org.citrusframework.simulator.http;
 
-import static org.citrusframework.util.FileUtils.readToString;
 import static org.springframework.beans.factory.support.BeanDefinitionBuilder.genericBeanDefinition;
 
-import io.swagger.models.Model;
-import io.swagger.models.Operation;
-import io.swagger.models.Path;
-import io.swagger.models.Swagger;
-import io.swagger.parser.SwaggerParser;
-import java.io.IOException;
+import io.apicurio.datamodels.combined.visitors.CombinedVisitorAdapter;
+import io.apicurio.datamodels.openapi.models.OasDocument;
+import io.apicurio.datamodels.openapi.models.OasOperation;
+import io.apicurio.datamodels.openapi.models.OasPathItem;
+import io.apicurio.datamodels.openapi.models.OasPaths;
+import jakarta.annotation.Nonnull;
 import java.util.Map;
-import org.citrusframework.simulator.exception.SimulatorException;
+import org.citrusframework.context.TestContext;
+import org.citrusframework.openapi.OpenApiSpecification;
+import org.citrusframework.openapi.model.OasModelHelper;
+import org.citrusframework.simulator.config.OpenApiScenarioIdGenerationMode;
 import org.citrusframework.spi.CitrusResourceWrapper;
 import org.citrusframework.spi.Resource;
 import org.slf4j.Logger;
@@ -38,7 +40,6 @@
 import org.springframework.beans.factory.support.BeanDefinitionRegistry;
 import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
 import org.springframework.util.Assert;
-import org.springframework.web.bind.annotation.RequestMethod;
 
 /**
  * @author Christoph Deppisch
@@ -48,9 +49,11 @@ public class HttpScenarioGenerator implements BeanFactoryPostProcessor {
     private static final Logger logger = LoggerFactory.getLogger(HttpScenarioGenerator.class);
 
     /**
-     * Target swagger API to generate scenarios from
+     * Target Open API to generate scenarios from
      */
-    private final Resource swaggerResource;
+    private final Resource openApiResource;
+
+    private OpenApiSpecification openApiSpecification;
 
     /**
      * Optional context path
@@ -61,74 +64,120 @@ public class HttpScenarioGenerator implements BeanFactoryPostProcessor {
      * Constructor using Spring environment.
      */
     public HttpScenarioGenerator(SimulatorRestConfigurationProperties simulatorRestConfigurationProperties) {
-        swaggerResource = new CitrusResourceWrapper(
+        openApiResource = new CitrusResourceWrapper(
             new PathMatchingResourcePatternResolver()
-                .getResource(simulatorRestConfigurationProperties.getSwagger().getApi())
+                .getResource(simulatorRestConfigurationProperties.getOpenApi().getApi())
         );
 
-        contextPath = simulatorRestConfigurationProperties.getSwagger().getContextPath();
+        contextPath = simulatorRestConfigurationProperties.getOpenApi().getContextPath();
     }
 
     /**
      * Constructor using swagger API file resource.
      *
-     * @param swaggerResource
+     * @param openApiResource
      */
-    public HttpScenarioGenerator(Resource swaggerResource) {
-        this.swaggerResource = swaggerResource;
+    public HttpScenarioGenerator(Resource openApiResource) {
+        this.openApiResource = openApiResource;
+    }
+
+    public HttpScenarioGenerator(OpenApiSpecification openApiSpecification) {
+        this.openApiResource = null;
+        this.openApiSpecification = openApiSpecification;
     }
 
     @Override
-    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
-        try {
-            Assert.notNull(swaggerResource,
-                "Missing either swagger api system property setting or explicit swagger api resource for scenario auto generation");
+    public void postProcessBeanFactory(@Nonnull ConfigurableListableBeanFactory beanFactory) throws BeansException {
+
+        if (openApiSpecification == null) {
+            Assert.notNull(openApiResource,
+                """
+                    Failed to load OpenAPI specification. No OpenAPI specification was provided.
+                    To load a specification, ensure that either the 'openApiResource' property is set
+                    or the 'swagger.api' system property is configured to specify the location of the OpenAPI resource.""");
+            openApiSpecification = OpenApiSpecification.from(openApiResource);
+            openApiSpecification.setRootContextPath(contextPath);
+        }
 
-            Swagger swagger = new SwaggerParser().parse(readToString(swaggerResource));
+        HttpResponseActionBuilderProvider httpResponseActionBuilderProvider = retrieveOptionalBuilderProvider(
+            beanFactory);
 
-            for (Map.Entry<String, Path> path : swagger.getPaths().entrySet()) {
-                for (Map.Entry<io.swagger.models.HttpMethod, Operation> operation : path.getValue().getOperationMap().entrySet()) {
+        OpenApiScenarioIdGenerationMode openApiScenarioIdGenerationMode = beanFactory.getBean(
+            SimulatorRestConfigurationProperties.class).getOpenApiScenarioIdGenerationMode();
 
-                    if (beanFactory instanceof BeanDefinitionRegistry beanDefinitionRegistry) {
-                        logger.info("Register auto generated scenario as bean definition: {}", operation.getValue().getOperationId());
+        TestContext testContext = new TestContext();
+        OasDocument openApiDocument = openApiSpecification.getOpenApiDoc(testContext);
+        if (openApiDocument != null && openApiDocument.paths != null) {
+            openApiDocument.paths.accept(new CombinedVisitorAdapter() {
 
-                        BeanDefinitionBuilder beanDefinitionBuilder = genericBeanDefinition(HttpOperationScenario.class)
-                            .addConstructorArgValue((contextPath + (swagger.getBasePath() != null ? swagger.getBasePath() : "")) + path.getKey())
-                            .addConstructorArgValue(RequestMethod.valueOf(operation.getKey().name()))
-                            .addConstructorArgValue(operation.getValue())
-                            .addConstructorArgValue(swagger.getDefinitions());
+                @Override
+                public void visitPaths(OasPaths oasPaths) {
+                    oasPaths.getPathItems().forEach(oasPathItem -> oasPathItem.accept(this));
+                }
 
-                        if (beanFactory.containsBeanDefinition("inboundJsonDataDictionary")) {
-                            beanDefinitionBuilder.addPropertyReference("inboundDataDictionary", "inboundJsonDataDictionary");
-                        }
+                @Override
+                public void visitPathItem(OasPathItem oasPathItem) {
+                    String path = oasPathItem.getPath();
+                    for (Map.Entry<String, OasOperation> operationEntry : OasModelHelper.getOperationMap(
+                        oasPathItem).entrySet()) {
 
-                        if (beanFactory.containsBeanDefinition("outboundJsonDataDictionary")) {
-                            beanDefinitionBuilder.addPropertyReference("outboundDataDictionary", "outboundJsonDataDictionary");
-                        }
+                        String fullPath = contextPath + OasModelHelper.getBasePath(openApiDocument) + path;
+                        OasOperation oasOperation = operationEntry.getValue();
+
+                        String scenarioId = HttpOperationScenario.getUniqueScenarioId(openApiScenarioIdGenerationMode, OasModelHelper.getBasePath(openApiDocument) + path, oasOperation);
+
+                        if (beanFactory instanceof BeanDefinitionRegistry beanDefinitionRegistry) {
+                            logger.info("Register auto generated scenario as bean definition: {}", fullPath);
 
-                        beanDefinitionRegistry.registerBeanDefinition(operation.getValue().getOperationId(), beanDefinitionBuilder.getBeanDefinition());
-                    } else {
-                        logger.info("Register auto generated scenario as singleton: {}", operation.getValue().getOperationId());
-                        beanFactory.registerSingleton(operation.getValue().getOperationId(), createScenario((contextPath + (swagger.getBasePath() != null ? swagger.getBasePath() : "")) + path.getKey(), RequestMethod.valueOf(operation.getKey().name()), operation.getValue(), swagger.getDefinitions()));
+                            BeanDefinitionBuilder beanDefinitionBuilder = genericBeanDefinition(HttpOperationScenario.class)
+                                .addConstructorArgValue(fullPath)
+                                .addConstructorArgValue(scenarioId)
+                                .addConstructorArgValue(openApiSpecification)
+                                .addConstructorArgValue(oasOperation)
+                                .addConstructorArgValue(httpResponseActionBuilderProvider);
+
+                            if (beanFactory.containsBeanDefinition("inboundJsonDataDictionary")) {
+                                beanDefinitionBuilder.addPropertyReference("inboundDataDictionary", "inboundJsonDataDictionary");
+                            }
+
+                            if (beanFactory.containsBeanDefinition("outboundJsonDataDictionary")) {
+                                beanDefinitionBuilder.addPropertyReference("outboundDataDictionary", "outboundJsonDataDictionary");
+                            }
+
+                            beanDefinitionRegistry.registerBeanDefinition(scenarioId, beanDefinitionBuilder.getBeanDefinition());
+                        } else {
+                            logger.info("Register auto generated scenario as singleton: {}", scenarioId);
+                            beanFactory.registerSingleton(scenarioId, createScenario(fullPath, scenarioId, openApiSpecification, oasOperation, httpResponseActionBuilderProvider));
+                        }
                     }
                 }
-            }
-        } catch (IOException e) {
-            throw new SimulatorException("Failed to read swagger api resource", e);
+            });
+        }
+    }
+
+    private static HttpResponseActionBuilderProvider retrieveOptionalBuilderProvider(
+        ConfigurableListableBeanFactory beanFactory) {
+        HttpResponseActionBuilderProvider httpResponseActionBuilderProvider = null;
+        try {
+            httpResponseActionBuilderProvider = beanFactory.getBean(
+                HttpResponseActionBuilderProvider.class);
+        } catch (BeansException e) {
+            // Ignore non existing optional provider
         }
+        return httpResponseActionBuilderProvider;
     }
 
     /**
      * Creates an HTTP scenario based on the given swagger path and operation information.
      *
-     * @param path        Request path
-     * @param method      Request method
-     * @param operation   Swagger operation
-     * @param definitions Additional definitions
+     * @param path        Full request path, including the context
+     * @param scenarioId      Request method
+     * @param openApiSpecification   OpenApiSpecification
+     * @param operation OpenApi operation
      * @return a matching HTTP scenario
      */
-    protected HttpOperationScenario createScenario(String path, RequestMethod method, Operation operation, Map<String, Model> definitions) {
-        return new HttpOperationScenario(path, method, operation, definitions);
+    protected HttpOperationScenario createScenario(String path, String scenarioId, OpenApiSpecification openApiSpecification, OasOperation operation, HttpResponseActionBuilderProvider httpResponseActionBuilderProvider) {
+        return new HttpOperationScenario(path, scenarioId, openApiSpecification, operation, httpResponseActionBuilderProvider);
     }
 
     public String getContextPath() {
@@ -137,5 +186,9 @@ public String getContextPath() {
 
     public void setContextPath(String contextPath) {
         this.contextPath = contextPath;
+
+        if (openApiSpecification != null) {
+            openApiSpecification.setRootContextPath(contextPath);
+        }
     }
 }
diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/http/SimulatorRestConfigurationProperties.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/http/SimulatorRestConfigurationProperties.java
index e962dd213..eeaeffd73 100644
--- a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/http/SimulatorRestConfigurationProperties.java
+++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/http/SimulatorRestConfigurationProperties.java
@@ -16,21 +16,25 @@
 
 package org.citrusframework.simulator.http;
 
+import static java.util.Collections.emptyList;
+import static java.util.Collections.unmodifiableList;
+
 import jakarta.validation.constraints.NotNull;
+import java.util.List;
+import lombok.Getter;
+import lombok.Setter;
 import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.citrusframework.simulator.config.OpenApiScenarioIdGenerationMode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 
-import java.util.List;
-
-import static java.util.Collections.emptyList;
-import static java.util.Collections.unmodifiableList;
-
 /**
  * @author Christoph Deppisch
  */
+@Getter
+@Setter
 @ConfigurationProperties(prefix = "citrus.simulator.rest")
 public class SimulatorRestConfigurationProperties implements InitializingBean {
 
@@ -47,25 +51,15 @@ public class SimulatorRestConfigurationProperties implements InitializingBean {
      */
     private List<String> urlMappings =  List.of("/services/rest/**");
 
-    private Swagger swagger = new Swagger();
-
     /**
-     * Gets the enabled.
-     *
-     * @return
+     * The scenario id generation mode for open api scenario generation.
      */
-    public boolean isEnabled() {
-        return enabled;
-    }
+    private OpenApiScenarioIdGenerationMode openApiScenarioIdGenerationMode = OpenApiScenarioIdGenerationMode.FULL_PATH;
 
     /**
-     * Sets the enabled.
-     *
-     * @param enabled
+     * The OpenApi used by the simulator to simulate OpenApi operations.
      */
-    public void setEnabled(boolean enabled) {
-        this.enabled = enabled;
-    }
+    private OpenApi openApi = new OpenApi();
 
     /**
      * Gets the urlMappings.
@@ -86,14 +80,6 @@ public void setUrlMappings(List<String> urlMappings) {
         this.urlMappings = urlMappings != null ? unmodifiableList(urlMappings) : emptyList();
     }
 
-    public Swagger getSwagger() {
-        return swagger;
-    }
-
-    public void setSwagger(Swagger swagger) {
-        this.swagger = swagger;
-    }
-
     @Override
     public void afterPropertiesSet() throws Exception {
         logger.info("Using the simulator configuration: {}", this);
@@ -107,34 +93,12 @@ public String toString() {
             .toString();
     }
 
-    public static class Swagger {
 
+    @Getter
+    @Setter
+    public static class OpenApi {
         private String api;
         private String contextPath;
         private boolean enabled = false;
-
-        public String getApi() {
-            return api;
-        }
-
-        public void setApi(String api) {
-            this.api = api;
-        }
-
-        public String getContextPath() {
-            return contextPath;
-        }
-
-        public void setContextPath(String contextPath) {
-            this.contextPath = contextPath;
-        }
-
-        public boolean isEnabled() {
-            return enabled;
-        }
-
-        public void setEnabled(boolean enabled) {
-            this.enabled = enabled;
-        }
     }
 }
diff --git a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/scenario/mapper/ScenarioMappers.java b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/scenario/mapper/ScenarioMappers.java
index b0edaa50e..1727deb47 100644
--- a/simulator-spring-boot/src/main/java/org/citrusframework/simulator/scenario/mapper/ScenarioMappers.java
+++ b/simulator-spring-boot/src/main/java/org/citrusframework/simulator/scenario/mapper/ScenarioMappers.java
@@ -16,7 +16,10 @@
 
 package org.citrusframework.simulator.scenario.mapper;
 
-import io.swagger.models.Operation;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
 import org.citrusframework.message.Message;
 import org.citrusframework.simulator.config.SimulatorConfigurationPropertiesAware;
 import org.citrusframework.simulator.http.HttpOperationScenario;
@@ -28,11 +31,6 @@
 import org.springframework.core.annotation.AnnotationUtils;
 import org.springframework.util.StringUtils;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Optional;
-
 /**
  * Scenario mapper chain goes through a list of mappers to find best match of extracted mapping keys. When no suitable
  * mapping key is found in the list of mappers a default mapping is used based on provided base class evaluation.
@@ -67,8 +65,8 @@ public static ScenarioMappers of(ScenarioMapper ... scenarioMappers) {
     public String getMappingKey(Message message) {
         return scenarioMapperList.stream()
                 .map(mapper -> {
-                    if (mapper instanceof AbstractScenarioMapper) {
-                        ((AbstractScenarioMapper) mapper).setUseDefaultMapping(false);
+                    if (mapper instanceof AbstractScenarioMapper abstractScenarioMapper) {
+                        abstractScenarioMapper.setUseDefaultMapping(false);
                     }
 
                     try {
@@ -82,11 +80,8 @@ public String getMappingKey(Message message) {
                 .filter(StringUtils::hasLength)
                 .filter(key -> scenarioList.parallelStream()
                         .anyMatch(scenario -> {
-                            if (scenario instanceof HttpOperationScenario) {
-                                return Optional.ofNullable(((HttpOperationScenario) scenario).getOperation())
-                                                .map(Operation::getOperationId)
-                                                .orElse("")
-                                                .equals(key);
+                            if (scenario instanceof HttpOperationScenario httpOperationScenario) {
+                                return key.equals(httpOperationScenario.getScenarioId());
                             }
 
                             return Optional.ofNullable(AnnotationUtils.findAnnotation(scenario.getClass(), Scenario.class))
@@ -101,13 +96,13 @@ public String getMappingKey(Message message) {
     @Override
     public void afterPropertiesSet() {
         scenarioMapperList.stream()
-                .filter(mapper -> mapper instanceof ScenarioListAware)
-                .map(mapper -> (ScenarioListAware) mapper)
+                .filter(ScenarioListAware.class::isInstance)
+                .map(ScenarioListAware.class::cast)
                 .forEach(mapper -> mapper.setScenarioList(scenarioList));
 
         scenarioMapperList.stream()
-                .filter(mapper -> mapper instanceof SimulatorConfigurationPropertiesAware)
-                .map(mapper -> (SimulatorConfigurationPropertiesAware) mapper)
+                .filter(SimulatorConfigurationPropertiesAware.class::isInstance)
+                .map(SimulatorConfigurationPropertiesAware.class::cast)
                 .forEach(mapper -> mapper.setSimulatorConfigurationProperties(getSimulatorConfigurationProperties()));
     }
 
diff --git a/simulator-spring-boot/src/main/resources/META-INF/citrus/openapi/processor/scenarioRegistrar b/simulator-spring-boot/src/main/resources/META-INF/citrus/openapi/processor/scenarioRegistrar
new file mode 100644
index 000000000..4c6b54b46
--- /dev/null
+++ b/simulator-spring-boot/src/main/resources/META-INF/citrus/openapi/processor/scenarioRegistrar
@@ -0,0 +1,2 @@
+name=httpOperationScenarioRegistrar
+type=org.citrusframework.simulator.http.HttpOperationScenarioRegistrar
diff --git a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/http/HttpOperationScenarioIT.java b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/http/HttpOperationScenarioIT.java
new file mode 100644
index 000000000..91f12d81b
--- /dev/null
+++ b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/http/HttpOperationScenarioIT.java
@@ -0,0 +1,244 @@
+package org.citrusframework.simulator.http;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.junit.jupiter.params.provider.Arguments.arguments;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import io.apicurio.datamodels.openapi.models.OasOperation;
+import java.io.IOException;
+import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Stream;
+import org.citrusframework.context.TestContext;
+import org.citrusframework.exceptions.CitrusRuntimeException;
+import org.citrusframework.exceptions.TestCaseFailedException;
+import org.citrusframework.functions.DefaultFunctionRegistry;
+import org.citrusframework.http.actions.HttpServerResponseActionBuilder;
+import org.citrusframework.http.message.HttpMessage;
+import org.citrusframework.log.DefaultLogModifier;
+import org.citrusframework.message.Message;
+import org.citrusframework.openapi.OpenApiRepository;
+import org.citrusframework.openapi.actions.OpenApiClientResponseActionBuilder;
+import org.citrusframework.openapi.model.OasModelHelper;
+import org.citrusframework.simulator.config.SimulatorConfigurationProperties;
+import org.citrusframework.simulator.scenario.ScenarioEndpoint;
+import org.citrusframework.simulator.scenario.ScenarioEndpointConfiguration;
+import org.citrusframework.simulator.scenario.ScenarioRunner;
+import org.citrusframework.spi.Resources.ClasspathResource;
+import org.citrusframework.util.FileUtils;
+import org.citrusframework.validation.DefaultMessageHeaderValidator;
+import org.citrusframework.validation.DefaultMessageValidatorRegistry;
+import org.citrusframework.validation.context.HeaderValidationContext;
+import org.citrusframework.validation.json.JsonMessageValidationContext;
+import org.citrusframework.validation.json.JsonTextMessageValidator;
+import org.citrusframework.validation.matcher.DefaultValidationMatcherRegistry;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.http.HttpHeaders;
+import org.springframework.test.util.ReflectionTestUtils;
+
+@ExtendWith(MockitoExtension.class)
+class HttpOperationScenarioIT {
+
+    private static final Function<String, String> IDENTITY = (text) -> text;
+
+    private final DirectScenarioEndpoint scenarioEndpoint = new DirectScenarioEndpoint();
+
+    private static final OpenApiRepository openApiRepository = new OpenApiRepository();
+
+    private static DefaultListableBeanFactory defaultListableBeanFactory;
+
+    private ScenarioRunner scenarioRunner;
+
+    private TestContext testContext;
+
+    @BeforeAll
+    static void beforeAll() {
+        ConfigurableApplicationContext applicationContext = mock();
+        defaultListableBeanFactory = new DefaultListableBeanFactory();
+        doReturn(defaultListableBeanFactory).when(applicationContext).getBeanFactory();
+        SimulatorConfigurationProperties simulatorConfigurationProperties = new SimulatorConfigurationProperties();
+        simulatorConfigurationProperties.setApplicationContext(applicationContext);
+
+        defaultListableBeanFactory.registerSingleton("SimulatorRestConfigurationProperties", new SimulatorRestConfigurationProperties());
+
+        openApiRepository.addRepository(new ClasspathResource("swagger/petstore-v2.json"));
+        openApiRepository.addRepository(new ClasspathResource("swagger/petstore-v3.json"));
+    }
+
+    @BeforeEach
+    void beforeEach() {
+        testContext = new TestContext();
+        testContext.setReferenceResolver(mock());
+        testContext.setMessageValidatorRegistry(new DefaultMessageValidatorRegistry());
+        testContext.setFunctionRegistry(new DefaultFunctionRegistry());
+        testContext.setValidationMatcherRegistry(new DefaultValidationMatcherRegistry());
+        testContext.setLogModifier(new DefaultLogModifier());
+        scenarioRunner = new ScenarioRunner(scenarioEndpoint, mock(), testContext);
+    }
+
+    static Stream<Arguments> scenarioExecution() {
+        return Stream.of(
+                arguments("v2_addPet_success", "POST_/petstore/v2/pet", "data/addPet.json", IDENTITY, null),
+                arguments("v3_addPet_success", "POST_/petstore/v3/pet", "data/addPet.json", IDENTITY, null),
+                arguments("v2_addPet_payloadValidationFailure", "POST_/petstore/v2/pet", "data/addPet_incorrect.json", IDENTITY, "Missing JSON entry, expected 'id' to be in '[photoUrls, wrong_id_property, name, category, tags, status]'"),
+                arguments("v3_addPet_payloadValidationFailure", "POST_/petstore/v3/pet", "data/addPet_incorrect.json", IDENTITY, "Missing JSON entry, expected 'id' to be in '[photoUrls, wrong_id_property, name, category, tags, status]'"),
+                arguments("v2_getPetById_success", "GET_/petstore/v2/pet/{petId}", null, (Function<String, String>)(text) -> text.replace("{petId}", "1234"), null),
+                arguments("v3_getPetById_success", "GET_/petstore/v3/pet/{petId}", null, (Function<String, String>)(text) -> text.replace("{petId}", "1234"), null),
+                arguments("v2_getPetById_pathParameterValidationFailure", "GET_/petstore/v2/pet/{petId}", null, (Function<String, String>)(text) -> text.replace("{petId}", "xxxx"), "MatchesValidationMatcher failed for field 'citrus_http_request_uri'. Received value is '/petstore/v2/pet/xxxx', control value is '/petstore/v2/pet/[0-9]+'"),
+                arguments("v3_getPetById_pathParameterValidationFailure", "GET_/petstore/v3/pet/{petId}", null, (Function<String, String>)(text) -> text.replace("{petId}", "xxxx"), "MatchesValidationMatcher failed for field 'citrus_http_request_uri'. Received value is '/petstore/v3/pet/xxxx', control value is '/petstore/v3/pet/[0-9]+'")
+            );
+    }
+
+    @ParameterizedTest(name="{0}")
+    @MethodSource()
+    void scenarioExecution(String name, String operationName, String payloadFile, Function<String, String> urlAdjuster, String exceptionMessage)
+        throws IOException {
+        if (defaultListableBeanFactory.containsSingleton("httpResponseActionBuilderProvider")) {
+            defaultListableBeanFactory.destroySingleton("httpResponseActionBuilderProvider");
+        }
+
+        HttpOperationScenario httpOperationScenario = getHttpOperationScenario(operationName);
+        HttpMessage controlMessage = new HttpMessage();
+        OpenApiClientResponseActionBuilder.fillMessageFromResponse(httpOperationScenario.getOpenApiSpecification(), testContext, controlMessage, httpOperationScenario.getOperation(), httpOperationScenario.getResponse());
+
+        this.scenarioExecution(operationName, payloadFile, urlAdjuster, exceptionMessage, controlMessage);
+    }
+
+    @ParameterizedTest(name="{0}_custom_payload")
+    @MethodSource("scenarioExecution")
+    void scenarioExecutionWithProvider(String name, String operationName, String payloadFile, Function<String, String> urlAdjuster, String exceptionMessage) {
+
+        String payload = "{\"id\":1234}";
+        HttpResponseActionBuilderProvider httpResponseActionBuilderProvider = (oasOperation, receivedMessage) -> {
+            HttpServerResponseActionBuilder serverResponseActionBuilder = new HttpServerResponseActionBuilder();
+            serverResponseActionBuilder
+                .endpoint(scenarioEndpoint)
+                .getMessageBuilderSupport()
+                    .body(payload);
+            return serverResponseActionBuilder;
+        };
+
+        if (!defaultListableBeanFactory.containsSingleton("httpResponseActionBuilderProvider")) {
+            defaultListableBeanFactory.registerSingleton("httpResponseActionBuilderProvider",
+                httpResponseActionBuilderProvider);
+        }
+
+        HttpOperationScenario httpOperationScenario = getHttpOperationScenario(operationName);
+        try {
+            ReflectionTestUtils.setField(httpOperationScenario, "httpResponseActionBuilderProvider",
+                httpResponseActionBuilderProvider);
+
+            HttpMessage correctPayloadMessage = new HttpMessage(payload);
+            assertThatCode(() -> this.scenarioExecution(operationName, payloadFile, urlAdjuster, exceptionMessage,
+                correctPayloadMessage)).doesNotThrowAnyException();
+
+            if (exceptionMessage == null) {
+                String otherPayload = "{\"id\":12345}";
+                HttpMessage incorrectPayloadMessage = new HttpMessage(otherPayload);
+                assertThatThrownBy(
+                    () -> this.scenarioExecution(operationName, payloadFile, urlAdjuster,
+                        exceptionMessage,
+                        incorrectPayloadMessage)).isInstanceOf(CitrusRuntimeException.class);
+            }
+        } finally {
+            ReflectionTestUtils.setField(httpOperationScenario, "httpResponseActionBuilderProvider",
+                null);
+        }
+    }
+
+    private void scenarioExecution(String operationName, String payloadFile, Function<String, String> urlAdjuster, String exceptionMessage, Message controlMessage)
+        throws IOException {
+        HttpOperationScenario httpOperationScenario = getHttpOperationScenario(operationName);
+        OasOperation oasOperation = httpOperationScenario.getOperation();
+
+        String payload = payloadFile != null ? FileUtils.readToString(new ClasspathResource(payloadFile)) : null;
+
+        Message receiveMessage = new HttpMessage()
+            .setPayload(payload)
+            .setHeader("citrus_http_request_uri", urlAdjuster.apply(httpOperationScenario.getPath()))
+            .setHeader("citrus_http_method", httpOperationScenario.getMethod().toUpperCase());
+
+        OasModelHelper.getRequestContentType(oasOperation)
+            .ifPresent(contentType -> receiveMessage.setHeader(HttpHeaders.CONTENT_TYPE, contentType));
+
+        scenarioEndpoint.setReceiveMessage(receiveMessage);
+
+        ReflectionTestUtils.setField(httpOperationScenario, "scenarioEndpoint",
+            scenarioEndpoint);
+
+        if (exceptionMessage != null) {
+            assertThatThrownBy(() -> httpOperationScenario.run(scenarioRunner)).isInstanceOf(
+                TestCaseFailedException.class).hasMessage(exceptionMessage);
+        } else {
+            assertThatCode(() -> httpOperationScenario.run(scenarioRunner)).doesNotThrowAnyException();
+
+            Message sendMessage = scenarioEndpoint.getSendMessage();
+
+            JsonTextMessageValidator jsonTextMessageValidator = new JsonTextMessageValidator();
+            jsonTextMessageValidator.validateMessage(sendMessage, controlMessage, testContext,
+                List.of(new JsonMessageValidationContext()));
+            DefaultMessageHeaderValidator defaultMessageHeaderValidator = new DefaultMessageHeaderValidator();
+            defaultMessageHeaderValidator.validateMessage(sendMessage, controlMessage, testContext, List.of(new HeaderValidationContext()));
+        }
+
+    }
+
+    private HttpOperationScenario getHttpOperationScenario(String operationName) {
+        Object bean = defaultListableBeanFactory.getBean(operationName);
+
+        assertThat(bean).isInstanceOf(HttpOperationScenario.class);
+
+        return  (HttpOperationScenario) bean;
+    }
+
+    private static class DirectScenarioEndpoint extends ScenarioEndpoint {
+
+        private Message receiveMessage;
+
+        private Message sendMessage;
+
+        public DirectScenarioEndpoint() {
+            super(new ScenarioEndpointConfiguration());
+        }
+
+        @Override
+        public void send(Message message, TestContext context) {
+            this.sendMessage = new HttpMessage(message);
+
+            if (sendMessage.getPayload() instanceof String stringPayload) {
+                this.sendMessage.setPayload(
+                    context.replaceDynamicContentInString(stringPayload));
+            }
+        }
+
+        @Override
+        public Message receive(TestContext context) {
+            return receiveMessage;
+        }
+
+        @Override
+        public Message receive(TestContext context, long timeout) {
+            return receiveMessage;
+        }
+
+        public void setReceiveMessage(Message receiveMessage) {
+            this.receiveMessage = receiveMessage;
+        }
+
+        public Message getSendMessage() {
+            return sendMessage;
+        }
+
+    }
+}
diff --git a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/http/HttpRequestPathScenarioMapperTest.java b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/http/HttpRequestPathScenarioMapperTest.java
index 6d4c69e54..41682e562 100644
--- a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/http/HttpRequestPathScenarioMapperTest.java
+++ b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/http/HttpRequestPathScenarioMapperTest.java
@@ -16,33 +16,46 @@
 
 package org.citrusframework.simulator.http;
 
-import io.swagger.models.Operation;
+import static org.assertj.core.api.Assertions.fail;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import io.apicurio.datamodels.openapi.models.OasDocument;
+import io.apicurio.datamodels.openapi.models.OasOperation;
+import io.apicurio.datamodels.openapi.v2.models.Oas20Document;
+import io.apicurio.datamodels.openapi.v2.models.Oas20Operation;
+import io.apicurio.datamodels.openapi.v3.models.Oas30Document;
+import io.apicurio.datamodels.openapi.v3.models.Oas30Operation;
+import java.util.Arrays;
 import org.citrusframework.exceptions.CitrusRuntimeException;
 import org.citrusframework.http.message.HttpMessage;
+import org.citrusframework.openapi.OpenApiSpecification;
 import org.citrusframework.simulator.config.SimulatorConfigurationProperties;
 import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
 import org.mockito.Mock;
-import org.mockito.Mockito;
 import org.mockito.junit.jupiter.MockitoExtension;
 import org.springframework.http.HttpMethod;
 import org.springframework.web.bind.annotation.RequestMethod;
 
-import java.util.Arrays;
-import java.util.Collections;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.when;
-
 /**
  * @author Christoph Deppisch
  */
 @ExtendWith(MockitoExtension.class)
 class HttpRequestPathScenarioMapperTest {
 
+    public static final String DEFAULT_SCENARIO = "default";
+    public static final String FOO_LIST_SCENARIO = "fooListScenario";
+    public static final String FOO_LIST_POST_SCENARIO = "fooListPostScenario";
+    public static final String BAR_LIST_SCENARIO = "barListScenario";
+    public static final String FOO_SCENARIO = "fooScenario";
+    public static final String BAR_SCENARIO = "barScenario";
+    public static final String FOO_DETAIL_SCENARIO = "fooDetailScenario";
+    public static final String BAR_DETAIL_SCENARIO = "barDetailScenario";
     @Mock
     private SimulatorConfigurationProperties simulatorConfigurationMock;
 
@@ -53,42 +66,60 @@ void beforeEachSetup() {
         fixture = new HttpRequestPathScenarioMapper();
         fixture.setConfiguration(simulatorConfigurationMock);
 
-        doReturn("default").when(simulatorConfigurationMock).getDefaultScenario();
+        doReturn(DEFAULT_SCENARIO).when(simulatorConfigurationMock).getDefaultScenario();
     }
 
-    @Test
-    void testGetMappingKey() {
-        Operation operation = Mockito.mock(Operation.class);
-
-        fixture.setScenarioList(Arrays.asList(new HttpOperationScenario("/issues/foos", RequestMethod.GET, operation, Collections.emptyMap()),
-            new HttpOperationScenario("/issues/foos", RequestMethod.POST, operation, Collections.emptyMap()),
-            new HttpOperationScenario("/issues/foo/{id}", RequestMethod.GET, operation, Collections.emptyMap()),
-            new HttpOperationScenario("/issues/foo/detail", RequestMethod.GET, operation, Collections.emptyMap()),
-            new HttpOperationScenario("/issues/bars", RequestMethod.GET, operation, Collections.emptyMap()),
-            new HttpOperationScenario("/issues/bar/{id}", RequestMethod.GET, operation, Collections.emptyMap()),
-            new HttpOperationScenario("/issues/bar/detail", RequestMethod.GET, operation, Collections.emptyMap())));
-
-        when(operation.getOperationId())
-            .thenReturn("fooListScenario")
-            .thenReturn("fooListPostScenario")
-            .thenReturn("barListScenario")
-            .thenReturn("fooScenario")
-            .thenReturn("barScenario")
-            .thenReturn("fooDetailScenario")
-            .thenReturn("barDetailScenario");
-
-        assertEquals(fixture.getMappingKey(new HttpMessage().method(HttpMethod.GET)), "default");
-        assertEquals(fixture.getMappingKey(new HttpMessage().method(HttpMethod.POST)), "default");
-        assertEquals(fixture.getMappingKey(new HttpMessage().method(HttpMethod.GET).path("/issues")), "default");
-        assertEquals(fixture.getMappingKey(new HttpMessage().method(HttpMethod.GET).path("/issues/foos")), "fooListScenario");
-        assertEquals(fixture.getMappingKey(new HttpMessage().method(HttpMethod.POST).path("/issues/foos")), "fooListPostScenario");
-        assertEquals(fixture.getMappingKey(new HttpMessage().method(HttpMethod.PUT).path("/issues/foos")), "default");
-        assertEquals(fixture.getMappingKey(new HttpMessage().method(HttpMethod.GET).path("/issues/bars")), "barListScenario");
-        assertEquals(fixture.getMappingKey(new HttpMessage().method(HttpMethod.DELETE).path("/issues/bars")), "default");
-        assertEquals(fixture.getMappingKey(new HttpMessage().method(HttpMethod.GET).path("/issues/foo/1")), "fooScenario");
-        assertEquals(fixture.getMappingKey(new HttpMessage().method(HttpMethod.GET).path("/issues/bar/1")), "barScenario");
-        assertEquals(fixture.getMappingKey(new HttpMessage().method(HttpMethod.GET).path("/issues/foo/detail")), "fooDetailScenario");
-        assertEquals(fixture.getMappingKey(new HttpMessage().method(HttpMethod.GET).path("/issues/bar/detail")), "barDetailScenario");
+    @ParameterizedTest
+    @ValueSource(strings = {"oas2", "oas3"})
+    void testGetMappingKey(String version) {
+        OpenApiSpecification openApiSpecificationMock = mock();
+
+        OasDocument oasDocument = null;
+        if ("oas2".equals(version)) {
+            oasDocument = mock(Oas20Document.class);
+        } else if ("oas3".equals(version)) {
+            oasDocument = mock(Oas30Document.class);
+        } else {
+            fail("Unexpected version: "+ version);
+        }
+
+        doReturn(oasDocument).when(openApiSpecificationMock).getOpenApiDoc(null);
+
+        fixture.setScenarioList(Arrays.asList(new HttpOperationScenario("/issues/foos",
+                FOO_LIST_SCENARIO, openApiSpecificationMock, mockOperation(oasDocument, RequestMethod.GET), null),
+            new HttpOperationScenario("/issues/foos", FOO_LIST_POST_SCENARIO, openApiSpecificationMock, mockOperation(oasDocument, RequestMethod.POST), null),
+            new HttpOperationScenario("/issues/foo/{id}", FOO_SCENARIO, openApiSpecificationMock, mockOperation(oasDocument, RequestMethod.GET), null),
+            new HttpOperationScenario("/issues/foo/detail", FOO_DETAIL_SCENARIO, openApiSpecificationMock, mockOperation(oasDocument, RequestMethod.GET), null),
+            new HttpOperationScenario("/issues/bars", BAR_LIST_SCENARIO, openApiSpecificationMock, mockOperation(oasDocument, RequestMethod.GET), null),
+            new HttpOperationScenario("/issues/bar/{id}", BAR_SCENARIO, openApiSpecificationMock, mockOperation(oasDocument, RequestMethod.GET), null),
+            new HttpOperationScenario("/issues/bar/detail", BAR_DETAIL_SCENARIO, openApiSpecificationMock, mockOperation(oasDocument, RequestMethod.GET), null)));
+
+        assertEquals(DEFAULT_SCENARIO,
+            fixture.getMappingKey(new HttpMessage().method(HttpMethod.GET)));
+        assertEquals(DEFAULT_SCENARIO,
+            fixture.getMappingKey(new HttpMessage().method(HttpMethod.POST)));
+        assertEquals(DEFAULT_SCENARIO,
+            fixture.getMappingKey(new HttpMessage().method(HttpMethod.GET).path("/issues")));
+        assertEquals(FOO_LIST_SCENARIO,
+            fixture.getMappingKey(new HttpMessage().method(HttpMethod.GET).path("/issues/foos")));
+        assertEquals(FOO_LIST_POST_SCENARIO,
+            fixture.getMappingKey(new HttpMessage().method(HttpMethod.POST).path("/issues/foos")));
+        assertEquals(DEFAULT_SCENARIO,
+            fixture.getMappingKey(new HttpMessage().method(HttpMethod.PUT).path("/issues/foos")));
+        assertEquals(BAR_LIST_SCENARIO,
+            fixture.getMappingKey(new HttpMessage().method(HttpMethod.GET).path("/issues/bars")));
+        assertEquals(DEFAULT_SCENARIO,
+            fixture.getMappingKey(new HttpMessage().method(HttpMethod.DELETE).path("/issues/bars")));
+        assertEquals(FOO_SCENARIO,
+            fixture.getMappingKey(new HttpMessage().method(HttpMethod.GET).path("/issues/foo/1")));
+        assertEquals(BAR_SCENARIO,
+            fixture.getMappingKey(new HttpMessage().method(HttpMethod.GET).path("/issues/bar/1")));
+        assertEquals(FOO_DETAIL_SCENARIO,
+            fixture.getMappingKey(
+                new HttpMessage().method(HttpMethod.GET).path("/issues/foo/detail")));
+        assertEquals(BAR_DETAIL_SCENARIO,
+            fixture.getMappingKey(
+                new HttpMessage().method(HttpMethod.GET).path("/issues/bar/detail")));
 
         fixture.setUseDefaultMapping(false);
 
@@ -98,4 +129,18 @@ void testGetMappingKey() {
         HttpMessage httpGetIssuesMessage = new HttpMessage().method(HttpMethod.GET).path("/issues");
         assertThrows(CitrusRuntimeException.class, () -> fixture.getMappingKey(httpGetIssuesMessage));
     }
+
+    private OasOperation mockOperation(OasDocument oasDocument, RequestMethod requestMethod) {
+
+        OasOperation oasOperationMock = null;
+        if (oasDocument instanceof  Oas20Document) {
+            oasOperationMock = mock(Oas20Operation.class);
+        } else if (oasDocument instanceof  Oas30Document) {
+            oasOperationMock = mock(Oas30Operation.class);
+        } else {
+            fail("Unexpected version document type!");
+        }
+        doReturn(requestMethod.toString()).when(oasOperationMock).getMethod();
+        return oasOperationMock;
+    }
 }
diff --git a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/http/HttpScenarioGeneratorTest.java b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/http/HttpScenarioGeneratorTest.java
index a13140bd7..553c4bb57 100644
--- a/simulator-spring-boot/src/test/java/org/citrusframework/simulator/http/HttpScenarioGeneratorTest.java
+++ b/simulator-spring-boot/src/test/java/org/citrusframework/simulator/http/HttpScenarioGeneratorTest.java
@@ -16,26 +16,28 @@
 
 package org.citrusframework.simulator.http;
 
-import io.swagger.models.Operation;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import io.apicurio.datamodels.openapi.models.OasOperation;
+import org.citrusframework.openapi.OpenApiSpecification;
 import org.citrusframework.spi.Resources;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.Mock;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
 import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanFactory;
 import org.springframework.beans.factory.config.BeanDefinition;
 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
 import org.springframework.beans.factory.support.DefaultListableBeanFactory;
-import org.springframework.web.bind.annotation.RequestMethod;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.verify;
 
 /**
  * @author Christoph Deppisch
@@ -43,148 +45,161 @@
 @ExtendWith(MockitoExtension.class)
 class HttpScenarioGeneratorTest {
 
-    @Mock
-    private ConfigurableListableBeanFactory beanFactoryMock;
+    private HttpScenarioGenerator fixture;
 
-    @Mock
-    private DefaultListableBeanFactory beanRegistryMock;
+    @ParameterizedTest
+    @ValueSource(strings={"v2", "v3"})
+    void generateHttpScenarios(String version) {
+        ConfigurableListableBeanFactory beanFactoryMock = mock();
 
-    private HttpScenarioGenerator fixture;
+        mockBeanFactory(beanFactoryMock);
 
-    @BeforeEach
-    void beforeEachSetup() {
-        fixture = new HttpScenarioGenerator(new Resources.ClasspathResource("swagger/swagger-api.json"));
-    }
+        fixture = new HttpScenarioGenerator(new Resources.ClasspathResource(
+            "swagger/petstore-"+version+".json"));
+
+        String addPetScenarioId = "POST_/petstore/"+version+"/pet";
+        String getPetScenarioId = "GET_/petstore/"+version+"/pet/{petId}";
+        String deletePetScenarioId = "DELETE_/petstore/"+version+"/pet/{petId}";
 
-    @Test
-    void generateHttpScenarios() {
+        String context = "/petstore/"+ version ;
         doAnswer(invocation -> {
             HttpOperationScenario scenario = (HttpOperationScenario) invocation.getArguments()[1];
-
-            assertNotNull(scenario.getOperation());
-            assertEquals(scenario.getPath(), "/v2/pet");
-            assertEquals(scenario.getMethod(), RequestMethod.POST);
-
+            assertScenarioProperties(scenario, context+"/pet", addPetScenarioId, "POST");
             return null;
-        }).when(beanFactoryMock).registerSingleton(eq("addPet"), any(HttpOperationScenario.class));
+        }).when(beanFactoryMock).registerSingleton(eq(addPetScenarioId), any(HttpOperationScenario.class));
 
         doAnswer(invocation -> {
             HttpOperationScenario scenario = (HttpOperationScenario) invocation.getArguments()[1];
-
-            assertNotNull(scenario.getOperation());
-            assertEquals(scenario.getPath(), "/v2/pet/{petId}");
-            assertEquals(scenario.getMethod(), RequestMethod.GET);
-
+            assertScenarioProperties(scenario, context+"/pet/{petId}", getPetScenarioId, "GET");
             return null;
-        }).when(beanFactoryMock).registerSingleton(eq("getPetById"), any(HttpOperationScenario.class));
+        }).when(beanFactoryMock).registerSingleton(eq(getPetScenarioId), any(HttpOperationScenario.class));
 
         doAnswer(invocation -> {
             HttpOperationScenario scenario = (HttpOperationScenario) invocation.getArguments()[1];
-
-            assertNotNull(scenario.getOperation());
-            assertEquals(scenario.getPath(), "/v2/pet/{petId}");
-            assertEquals(scenario.getMethod(), RequestMethod.DELETE);
-
+            assertScenarioProperties(scenario, context+"/pet/{petId}", deletePetScenarioId, "DELETE");
             return null;
-        }).when(beanFactoryMock).registerSingleton(eq("deletePet"), any(HttpOperationScenario.class));
+        }).when(beanFactoryMock).registerSingleton(eq(deletePetScenarioId), any(HttpOperationScenario.class));
 
         fixture.postProcessBeanFactory(beanFactoryMock);
 
-        verify(beanFactoryMock).registerSingleton(eq("addPet"), any(HttpOperationScenario.class));
-        verify(beanFactoryMock).registerSingleton(eq("getPetById"), any(HttpOperationScenario.class));
-        verify(beanFactoryMock).registerSingleton(eq("deletePet"), any(HttpOperationScenario.class));
+        verify(beanFactoryMock).registerSingleton(eq(addPetScenarioId), any(HttpOperationScenario.class));
+        verify(beanFactoryMock).registerSingleton(eq(getPetScenarioId), any(HttpOperationScenario.class));
+        verify(beanFactoryMock).registerSingleton(eq(deletePetScenarioId), any(HttpOperationScenario.class));
     }
 
-    @Test
-    void testGenerateScenariosWithBeandDefinitionRegistry() {
-        doAnswer(invocation -> {
-            BeanDefinition scenario = (BeanDefinition) invocation.getArguments()[1];
+    @ParameterizedTest
+    @ValueSource(strings={"v2", "v3"})
+    void testGenerateScenariosWithBeanDefinitionRegistry(String version) {
 
-            assertEquals(scenario.getConstructorArgumentValues().getArgumentValue(0, String.class).getValue(), "/v2/pet");
-            assertEquals(scenario.getConstructorArgumentValues().getArgumentValue(1, RequestMethod.class).getValue(), RequestMethod.POST);
-            assertNotNull(scenario.getConstructorArgumentValues().getArgumentValue(2, Operation.class).getValue());
-            assertNull(scenario.getPropertyValues().get("inboundDataDictionary"));
-            assertNull(scenario.getPropertyValues().get("outboundDataDictionary"));
+        DefaultListableBeanFactory beanRegistryMock = mock();
+        mockBeanFactory(beanRegistryMock);
 
-            return null;
-        }).when(beanRegistryMock).registerBeanDefinition(eq("addPet"), any(BeanDefinition.class));
+        fixture = new HttpScenarioGenerator(new Resources.ClasspathResource(
+            "swagger/petstore-"+version+".json"));
+
+        String context = "/petstore/"+ version ;
 
         doAnswer(invocation -> {
             BeanDefinition scenario = (BeanDefinition) invocation.getArguments()[1];
-
-            assertEquals(scenario.getConstructorArgumentValues().getArgumentValue(0, String.class).getValue(), "/v2/pet/{petId}");
-            assertEquals(scenario.getConstructorArgumentValues().getArgumentValue(1, RequestMethod.class).getValue(), RequestMethod.GET);
-            assertNotNull(scenario.getConstructorArgumentValues().getArgumentValue(2, Operation.class).getValue());
-            assertNull(scenario.getPropertyValues().get("inboundDataDictionary"));
-            assertNull(scenario.getPropertyValues().get("outboundDataDictionary"));
-
+            assertBeanDefinition(scenario, context+"/pet", "POST_/petstore/"+version+"/pet", "post", false);
             return null;
-        }).when(beanRegistryMock).registerBeanDefinition(eq("getPetById"), any(BeanDefinition.class));
+        }).when(beanRegistryMock).registerBeanDefinition(eq("POST_/petstore/"+version+"/pet"), any(BeanDefinition.class));
 
         doAnswer(invocation -> {
             BeanDefinition scenario = (BeanDefinition) invocation.getArguments()[1];
+            assertBeanDefinition(scenario, context+"/pet/{petId}", "GET_/petstore/"+version+"/pet/{petId}", "get", false);
+            return null;
+        }).when(beanRegistryMock).registerBeanDefinition(eq("GET_/petstore/"+version+"/pet/{petId}"), any(BeanDefinition.class));
 
-            assertEquals(scenario.getConstructorArgumentValues().getArgumentValue(0, String.class).getValue(), "/v2/pet/{petId}");
-            assertEquals(scenario.getConstructorArgumentValues().getArgumentValue(1, RequestMethod.class).getValue(), RequestMethod.DELETE);
-            assertNotNull(scenario.getConstructorArgumentValues().getArgumentValue(2, Operation.class).getValue());
-            assertNull(scenario.getPropertyValues().get("inboundDataDictionary"));
-            assertNull(scenario.getPropertyValues().get("outboundDataDictionary"));
-
+        doAnswer(invocation -> {
+            BeanDefinition scenario = (BeanDefinition) invocation.getArguments()[1];
+            assertBeanDefinition(scenario, context+"/pet/{petId}", "DELETE_/petstore/"+version+"/pet/{petId}", "delete", false);
             return null;
-        }).when(beanRegistryMock).registerBeanDefinition(eq("deletePet"), any(BeanDefinition.class));
+        }).when(beanRegistryMock).registerBeanDefinition(eq("DELETE_/petstore/"+version+"/pet/{petId}"), any(BeanDefinition.class));
 
         fixture.postProcessBeanFactory(beanRegistryMock);
 
-        verify(beanRegistryMock).registerBeanDefinition(eq("addPet"), any(BeanDefinition.class));
-        verify(beanRegistryMock).registerBeanDefinition(eq("getPetById"), any(BeanDefinition.class));
-        verify(beanRegistryMock).registerBeanDefinition(eq("deletePet"), any(BeanDefinition.class));
+        verify(beanRegistryMock).registerBeanDefinition(eq("POST_/petstore/"+version+"/pet"), any(BeanDefinition.class));
+        verify(beanRegistryMock).registerBeanDefinition(eq("GET_/petstore/"+version+"/pet/{petId}"), any(BeanDefinition.class));
+        verify(beanRegistryMock).registerBeanDefinition(eq("DELETE_/petstore/"+version+"/pet/{petId}"), any(BeanDefinition.class));
     }
 
-    @Test
-    void testGenerateScenariosWithDataDictionaries() {
+    @ParameterizedTest
+    @ValueSource(strings={"v2", "v3"})
+    void testGenerateScenariosWithDataDictionariesAtRootContext(String version) {
+        DefaultListableBeanFactory beanRegistryMock = mock();
+        mockBeanFactory(beanRegistryMock);
+
+        fixture = new HttpScenarioGenerator(new Resources.ClasspathResource(
+            "swagger/petstore-"+version+".json"));
+        fixture.setContextPath("/services/rest2");
+
+        String addPetScenarioId = "POST_/petstore/"+version+"/pet";
+        String getPetScenarioId = "GET_/petstore/"+version+"/pet/{petId}";
+        String deletePetScenarioId = "DELETE_/petstore/"+version+"/pet/{petId}";
+
+        String context = fixture.getContextPath()+"/petstore/"+ version ;
+
         doReturn(true).when(beanRegistryMock).containsBeanDefinition("inboundJsonDataDictionary");
         doReturn(true).when(beanRegistryMock).containsBeanDefinition("outboundJsonDataDictionary");
 
         doAnswer(invocation -> {
             BeanDefinition scenario = (BeanDefinition) invocation.getArguments()[1];
-
-            assertEquals(scenario.getConstructorArgumentValues().getArgumentValue(0, String.class).getValue(), "/v2/pet");
-            assertEquals(scenario.getConstructorArgumentValues().getArgumentValue(1, RequestMethod.class).getValue(), RequestMethod.POST);
-            assertNotNull(scenario.getConstructorArgumentValues().getArgumentValue(2, Operation.class).getValue());
-            assertNotNull(scenario.getPropertyValues().get("inboundDataDictionary"));
-            assertNotNull(scenario.getPropertyValues().get("outboundDataDictionary"));
-
+            assertBeanDefinition(scenario, context+"/pet",  addPetScenarioId, "post", true);
             return null;
-        }).when(beanRegistryMock).registerBeanDefinition(eq("addPet"), any(BeanDefinition.class));
+        }).when(beanRegistryMock).registerBeanDefinition(eq(addPetScenarioId), any(BeanDefinition.class));
 
         doAnswer(invocation -> {
             BeanDefinition scenario = (BeanDefinition) invocation.getArguments()[1];
-
-            assertEquals(scenario.getConstructorArgumentValues().getArgumentValue(0, String.class).getValue(), "/v2/pet/{petId}");
-            assertEquals(scenario.getConstructorArgumentValues().getArgumentValue(1, RequestMethod.class).getValue(), RequestMethod.GET);
-            assertNotNull(scenario.getConstructorArgumentValues().getArgumentValue(2, Operation.class).getValue());
-            assertNotNull(scenario.getPropertyValues().get("inboundDataDictionary"));
-            assertNotNull(scenario.getPropertyValues().get("outboundDataDictionary"));
-
+            assertBeanDefinition(scenario, context+"/pet/{petId}", getPetScenarioId, "get", true);
             return null;
-        }).when(beanRegistryMock).registerBeanDefinition(eq("getPetById"), any(BeanDefinition.class));
+        }).when(beanRegistryMock).registerBeanDefinition(eq(getPetScenarioId), any(BeanDefinition.class));
 
         doAnswer(invocation -> {
             BeanDefinition scenario = (BeanDefinition) invocation.getArguments()[1];
-
-            assertEquals(scenario.getConstructorArgumentValues().getArgumentValue(0, String.class).getValue(), "/v2/pet/{petId}");
-            assertEquals(scenario.getConstructorArgumentValues().getArgumentValue(1, RequestMethod.class).getValue(), RequestMethod.DELETE);
-            assertNotNull(scenario.getConstructorArgumentValues().getArgumentValue(2, Operation.class).getValue());
-            assertNotNull(scenario.getPropertyValues().get("inboundDataDictionary"));
-            assertNotNull(scenario.getPropertyValues().get("outboundDataDictionary"));
-
+            assertBeanDefinition(scenario, context+"/pet/{petId}",deletePetScenarioId,"delete", true);
             return null;
-        }).when(beanRegistryMock).registerBeanDefinition(eq("deletePet"), any(BeanDefinition.class));
+        }).when(beanRegistryMock).registerBeanDefinition(eq(deletePetScenarioId), any(BeanDefinition.class));
 
         fixture.postProcessBeanFactory(beanRegistryMock);
 
-        verify(beanRegistryMock).registerBeanDefinition(eq("addPet"), any(BeanDefinition.class));
-        verify(beanRegistryMock).registerBeanDefinition(eq("getPetById"), any(BeanDefinition.class));
-        verify(beanRegistryMock).registerBeanDefinition(eq("deletePet"), any(BeanDefinition.class));
+        verify(beanRegistryMock).registerBeanDefinition(eq(addPetScenarioId), any(BeanDefinition.class));
+        verify(beanRegistryMock).registerBeanDefinition(eq(getPetScenarioId), any(BeanDefinition.class));
+        verify(beanRegistryMock).registerBeanDefinition(eq(deletePetScenarioId), any(BeanDefinition.class));
+    }
+
+    private void mockBeanFactory(BeanFactory beanFactory) {
+        doReturn(new SimulatorRestConfigurationProperties()).when(beanFactory).getBean(SimulatorRestConfigurationProperties.class);
+        doThrow(new BeansException("No such bean") {
+        }).when(beanFactory).getBean(HttpResponseActionBuilderProvider.class);
+    }
+
+    private void assertBeanDefinition(BeanDefinition scenario, String path, String scenarioId, String method, boolean withDictionaries) {
+        assertThat(getConstructorArgument(scenario, 0)).isEqualTo( path);
+        assertThat(getConstructorArgument(scenario, 1)).isEqualTo( scenarioId);
+        assertThat(getConstructorArgument(scenario, 2)).isInstanceOf(OpenApiSpecification.class);
+        assertThat(getConstructorArgument(scenario, 3)).isInstanceOf(OasOperation.class);
+        assertThat(((OasOperation)getConstructorArgument(scenario, 3)).getMethod()).isEqualTo(method);
+
+        if (withDictionaries) {
+            assertThat(scenario.getPropertyValues().get("inboundDataDictionary")).isNotNull();
+            assertThat(scenario.getPropertyValues().get("outboundDataDictionary")).isNotNull();
+        } else {
+            assertThat(scenario.getPropertyValues().get("inboundDataDictionary")).isNull();
+            assertThat(scenario.getPropertyValues().get("outboundDataDictionary")).isNull();
+        }
+    }
+
+    private static Object getConstructorArgument(BeanDefinition scenario, int index) {
+        ValueHolder argumentValue = scenario.getConstructorArgumentValues()
+            .getArgumentValue(index, String.class);
+        assertThat(argumentValue).isNotNull();
+        return argumentValue.getValue();
+    }
+
+    private void assertScenarioProperties(HttpOperationScenario scenario, String path, String operationId, String method) {
+        assertThat(scenario).extracting(HttpOperationScenario::getPath, HttpOperationScenario::getScenarioId).containsExactly(path, operationId);
+        assertThat(scenario.getMethod()).isEqualTo(method);
+        assertThat(scenario.getOperation()).isNotNull().extracting(OasOperation::getMethod).isEqualTo(method.toLowerCase());
     }
 }
diff --git a/simulator-spring-boot/src/test/resources/data/addPet.json b/simulator-spring-boot/src/test/resources/data/addPet.json
new file mode 100644
index 000000000..fae210be0
--- /dev/null
+++ b/simulator-spring-boot/src/test/resources/data/addPet.json
@@ -0,0 +1,15 @@
+{
+  "id": 0,
+  "category": {
+    "id": 0,
+    "name": "string"
+  },
+  "name": "doggie",
+  "photoUrls": [
+    "string"
+  ],
+  "tags": [
+    {}
+  ],
+  "status": "available"
+}
diff --git a/simulator-spring-boot/src/test/resources/data/addPet_incorrect.json b/simulator-spring-boot/src/test/resources/data/addPet_incorrect.json
new file mode 100644
index 000000000..0e4b8f388
--- /dev/null
+++ b/simulator-spring-boot/src/test/resources/data/addPet_incorrect.json
@@ -0,0 +1,15 @@
+{
+  "wrong_id_property": 0,
+  "category": {
+    "id": 0,
+    "name": "string"
+  },
+  "name": "doggie",
+  "photoUrls": [
+    "string"
+  ],
+  "tags": [
+    {}
+  ],
+  "status": "available"
+}
diff --git a/simulator-spring-boot/src/test/resources/swagger/swagger-api.json b/simulator-spring-boot/src/test/resources/swagger/petstore-v2.json
similarity index 99%
rename from simulator-spring-boot/src/test/resources/swagger/swagger-api.json
rename to simulator-spring-boot/src/test/resources/swagger/petstore-v2.json
index bfd4ee2fb..f1012b5c4 100644
--- a/simulator-spring-boot/src/test/resources/swagger/swagger-api.json
+++ b/simulator-spring-boot/src/test/resources/swagger/petstore-v2.json
@@ -1,5 +1,5 @@
 {
-  "swagger": "3.0.3",
+  "swagger": "2.0",
   "info": {
     "version": "1.0.0",
     "title": "Swagger Petstore",
@@ -9,7 +9,7 @@
     }
   },
   "host": "localhost",
-  "basePath": "/v2",
+  "basePath": "/petstore/v2",
   "schemes": [
     "http"
   ],
@@ -281,4 +281,4 @@
       }
     }
   }
-}
\ No newline at end of file
+}
diff --git a/simulator-spring-boot/src/test/resources/swagger/petstore-v3.json b/simulator-spring-boot/src/test/resources/swagger/petstore-v3.json
new file mode 100644
index 000000000..6c2b5bdfb
--- /dev/null
+++ b/simulator-spring-boot/src/test/resources/swagger/petstore-v3.json
@@ -0,0 +1,254 @@
+{
+    "openapi": "3.0.2",
+    "info": {
+        "title": "Swagger Petstore",
+        "version": "1.0.1",
+        "description": "This is a sample server Petstore server.",
+        "license": {
+            "name": "Apache 2.0",
+            "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
+        }
+    },
+    "servers": [
+        {
+            "url": "http://localhost/petstore/v3"
+        }
+    ],
+    "paths": {
+        "/pet": {
+            "post": {
+                "requestBody": {
+                    "description": "Pet object that needs to be added to the store",
+                    "content": {
+                        "application/json": {
+                            "schema": {
+                                "$ref": "#/components/schemas/Pet"
+                            }
+                        },
+                        "application/xml": {
+                            "schema": {
+                                "$ref": "#/components/schemas/Pet"
+                            }
+                        }
+                    },
+                    "required": true
+                },
+                "tags": [
+                    "pet"
+                ],
+                "responses": {
+                    "201": {
+                        "description": "Created"
+                    },
+                    "405": {
+                        "description": "Invalid input"
+                    }
+                },
+                "operationId": "addPet",
+                "summary": "Add a new pet to the store",
+                "description": ""
+            }
+        },
+        "/pet/{petId}": {
+            "get": {
+                "tags": [
+                    "pet"
+                ],
+                "parameters": [
+                    {
+                        "name": "petId",
+                        "description": "ID of pet to return",
+                        "schema": {
+                            "format": "int64",
+                            "type": "integer"
+                        },
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "name": "verbose",
+                        "description": "Output details",
+                        "schema": {
+                            "type": "boolean"
+                        },
+                        "in": "query",
+                        "required": false
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/Pet"
+                                }
+                            },
+                            "application/xml": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/Pet"
+                                }
+                            }
+                        },
+                        "description": "successful operation"
+                    },
+                    "400": {
+                        "description": "Invalid ID supplied"
+                    },
+                    "404": {
+                        "description": "Pet not found"
+                    }
+                },
+                "operationId": "getPetById",
+                "summary": "Find pet by ID",
+                "description": "Returns a single pet"
+            },
+            "delete": {
+                "tags": [
+                    "pet"
+                ],
+                "parameters": [
+                    {
+                        "name": "api_key",
+                        "schema": {
+                            "type": "string"
+                        },
+                        "in": "header",
+                        "required": false
+                    },
+                    {
+                        "name": "petId",
+                        "description": "Pet id to delete",
+                        "schema": {
+                            "format": "int64",
+                            "type": "integer"
+                        },
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "204": {
+                        "description": "No content"
+                    },
+                    "400": {
+                        "description": "Invalid ID supplied"
+                    },
+                    "404": {
+                        "description": "Pet not found"
+                    }
+                },
+                "operationId": "deletePet",
+                "summary": "Deletes a pet",
+                "description": ""
+            }
+        }
+    },
+    "components": {
+        "schemas": {
+            "Category": {
+                "type": "object",
+                "properties": {
+                    "id": {
+                        "format": "int64",
+                        "type": "integer"
+                    },
+                    "name": {
+                        "type": "string"
+                    }
+                },
+                "xml": {
+                    "name": "Category"
+                }
+            },
+            "Tag": {
+                "type": "object",
+                "properties": {
+                    "id": {
+                        "format": "int64",
+                        "type": "integer"
+                    },
+                    "name": {
+                        "type": "string"
+                    }
+                },
+                "xml": {
+                    "name": "Tag"
+                }
+            },
+            "Pet": {
+                "required": [
+                    "category",
+                    "name",
+                    "status"
+                ],
+                "type": "object",
+                "properties": {
+                    "id": {
+                        "format": "int64",
+                        "type": "integer"
+                    },
+                    "category": {
+                        "$ref": "#/components/schemas/Category"
+                    },
+                    "name": {
+                        "type": "string",
+                        "example": "doggie"
+                    },
+                    "photoUrls": {
+                        "type": "array",
+                        "items": {
+                            "type": "string"
+                        },
+                        "xml": {
+                            "name": "photoUrl",
+                            "wrapped": true
+                        }
+                    },
+                    "tags": {
+                        "type": "array",
+                        "items": {
+                            "$ref": "#/components/schemas/Tag"
+                        },
+                        "xml": {
+                            "name": "tag",
+                            "wrapped": true
+                        }
+                    },
+                    "status": {
+                        "description": "pet status in the store",
+                        "enum": [
+                            "available",
+                            "pending",
+                            "sold"
+                        ],
+                        "type": "string"
+                    }
+                },
+                "xml": {
+                    "name": "Pet"
+                }
+            },
+            "ApiResponse": {
+                "type": "object",
+                "properties": {
+                    "code": {
+                        "format": "int32",
+                        "type": "integer"
+                    },
+                    "type": {
+                        "type": "string"
+                    },
+                    "message": {
+                        "type": "string"
+                    }
+                }
+            }
+        }
+    },
+    "tags": [
+        {
+            "name": "pet",
+            "description": "Everything about your Pets"
+        }
+    ]
+}